Le problème
Si on ne change pas la séquence de démarrage, le gcc réclame la version 37 du dos avec le message laconique "Need version 37 of dos.library".
Se limiter à la version 37 est un non sens, le 1.2 (version 33) était livré avec le A500 et A2000, le 1.3 (version 34) était livré avec le A2000B.
Un petit fichier assembleur mystart.s
Ce n'est pas de l'assembleur 68000, mais de l'assembleur compris par gcc.
Le main référencé est préfixé par trois traits bas ___.
.text .even .globl start start: jmp ___startup
Le code source nostartup.c
Le point d'entrée en C a deux traits bas __startup.
.
#define __NOLIBBASE__ #include <stdarg.h> #include <string.h> #include <dos/dosextens.h> #include <workbench/startup.h> #include <proto/exec.h> #include <proto/dos.h> #ifdef __SASC # define SAVEDS __saveds # define ASM __asm # define REG(x,y) register __##x y #elif defined(__GNUC__) # define SAVEDS __saveds # define ASM # define REG(x,y) y __asm(#x) #else # error add #defines for your compiler... #endif size_t strlen(const char *) ; int sprintf(char *, const char*, ...) ; int _main(int argc, char*argv[]) ; #define MAXARG 64 #define isspace(c) ((c == ' ')||(c == '\t') || (c == '\n')) #ifdef __NOLIBBASE__ struct Library *DOSBase = NULL ; struct Library *SysBase = NULL ; #else struct DosLibrary *DOSBase = NULL ; struct ExecBase *SysBase = NULL ; #endif BPTR stdout = 0L ; int ASM SAVEDS __startup(REG(a0, char *cmdline)) { int ret ; struct Process *me ; struct WBStartup *wb = NULL ; static int argc; /* arg count */ static char **targv, *argv[MAXARG+1]; /* arg pointers */ SysBase = (*((struct Library **) 4)); me=(struct Process *)FindTask( NULL) ; if (me->pr_CLI) { } else { WaitPort(&me->pr_MsgPort) ; wb = (struct WBStartup *)GetMsg(&me->pr_MsgPort) ; } DOSBase = OldOpenLibrary("dos.library") ; if (DOSBase) { char *text ; if (wb) { stdout = Open("CON:10/10/300/100/My prog without startup", MODE_NEWFILE) ; if (wb->sm_ToolWindow) { if (stdout) { char str[100] ; sprintf(str, "toolwindow \"%s\"\n", wb->sm_ToolWindow) ; Write(stdout, str, strlen(str)) ; } } } else { char **pargv; char *argbuf; char *line = cmdline ; /*** * Build argument pointer list ***/ while (argc < MAXARG) { while (isspace(*line)) line++; if (*line == '\0') break; pargv = &argv[argc++]; if (*line == '"') { argbuf = *pargv = ++line; /* ptr inside quoted string */ while (*line != '"' && *line != 0) { if (*line == '*') { line++; switch (*line) { case '\0': *argbuf = 0; goto linedone; case 'E': *argbuf++ = '\027' ; break; case 'N': *argbuf++ = '\n' ; break; default: *argbuf++ = *line; } line++; } else { *argbuf++ = *line++; } } line++; *argbuf++ = '\0'; /* terminate arg */ } else /* non-quoted arg */ { *pargv = line; while ((*line != '\0') && (!isspace(*line))) line++; if (*line == '\0') break; else *line++ = '\0'; /* terminate arg */ } } /* while */ linedone: targv = (argc == 0) ? (char **) wb : (char **) &argv[0]; stdout = Output() ; } /*** * Call user's main program ***/ ret = _main(argc, targv) ; if (wb) { Delay(100) ; if (stdout) { Close(stdout) ; stdout = 0L ; } } CloseLibrary((struct Library *)DOSBase) ; } if (wb) { Forbid() ; ReplyMsg(&wb->sm_Message) ; } me->pr_Result2 = ret ; return ret ; } size_t strlen(const char *str) { char *s = str ; while (*s) { s++ ; } return (size_t)(s - str) ; } int sprintf(char *buffer, const char *format_string, ...) { va_list args ; int len ; struct Library *SysBase = (*((struct Library **) 4)); va_start(args, format_string) ; RawDoFmt((UBYTE*)format_string, (APTR)args, (VOID(*)())"\x16\xc0\x4e\x75", /* move.b d0,(A3)+; rts */ (APTR)buffer) ; va_end(args) ; return (int)strlen(buffer) ; } // il y a un bug: argv[0] devrait être le nom du programme // // int _main(int argc, char *argv[]) { int i ; char buf[100] ; if (stdout) { char *text="Hello world\n" ; Write(stdout, text, strlen(text)) ; if (argc == 0) { text = "from Workbench\n" ; Write(stdout, text, strlen(text)) ; } else { for (i = 0 ; i < argc ; i ++ ) { sprintf(buf, "%ld : \"%s\"\n", i, argv[i]) ; Write(stdout, buf, strlen(buf)) ; } } } return 0 ; }
Le makefile pour GCC
SRC=.. OBJ=obj BIN=bin target: $(BIN)/hello $(BIN)/hello.info $(BIN)/hello: mystartup.s $(SRC)/nostartup.c gcc -s -Os -O3 -nostdlib -noixemul -fbaserel -fomit-frame-pointer -o $(BIN)/hello mystartup.s $(SRC)/nostartup.c $(BIN)/hello.info: res/hello.info copy res/hello.info $(BIN)/hello.info clean: del $(BIN)/#? $(OBJ)/#?make
Le makefile pour SAS/C
Pour le SAS/C, pas besoin de fichier assembleur, la première fonction définie sera considérée comme point d'entrée.
SRC= OBJ=obj BIN=bin COPTS= nostackcheck opt optpeep optgo optinline optloop opttime target: $(BIN)/hello $(OBJ)/nostartup.o: $(SRC)/nostartup.c sc $(COPTS) OBJNAME $(OBJ)/nostartup.o $(SRC)/nostartup.c $(BIN)/hello: $(OBJ)/nostartup.o slink $(OBJ)/nostartup.o\ to $(BIN)/hello\ verbose smallcode smalldata nodebugmake