#include #include #include #include #include #include #include "kprintf.h" #include "ixemul.h" #include #include #include #include #include #include #include #include #include #include //#include //#include #include #include #ifdef SHAREDL #include #include #include #include #include #include #include #include #include #include #endif #ifdef NATIVE_MORPHOS #include #include #endif #define FROM_CRT0 #include /* get the current revision number. Version control is automatically done by * OpenLibrary(), I just have to check the revision number */ #undef IX_VERSION #include "ix_internals_backup.h" #define MSTRING(x) STRING(x) #define STRING(x) #x struct ixemul_base *ixemulbase; // Used by the glue functions #ifdef NATIVE_MORPHOS int (**_ixbasearray)(); int __amigappc__ = 1; int __abox__ = 1; #ifdef SUPPORT_CTORS extern void (*__ctrslist[])() __attribute__((section(".ctors"))); extern void (*__dtrslist[])() __attribute__((section(".dtors"))); #endif /* SUPPORT_CTORS */ #ifdef SUPPORT_INIT static void call_init(); static void call_fini(); #endif /* SUPPORT_INIT */ #else struct Library *ixrealbase; // The real ixemul base (may be identical to ixemulbase, though) #endif /* NATIVE_MORPHOS */ /*static*/ int start_stdio(int, char **, char **); static int exec_entry(struct ixemul_base *ixembase, int argc, char *argv[], char *env[], long os); static int ENTRY(); int extend_stack_ix_exec_entry(int argc, char **argv, char **environ, int *real_errno, int (*main)(int, char **, char **)); int extend_stack_ix_startup(char *aline, int alen, int expand, char *wb_default_window, unsigned main, int *real_errno); void monstartup(char *lowpc, char *highpc); void __init_stk_limit(void **limit, unsigned long argbytes); /** * May 2009, Diego Casorran: Ixemul is now able to be loaded dinamically * depending which functions are used. That means, if you use V49 SDK and * only V48 functions are used, the requested ixemul.library will be V48. * Unfortunately, this only seems to work with no-baserel code.. Anyhow, * thats the 90% of the software, i guess. */ #ifdef CRT0 # define HANDLE_DINAMIC_IXEMUL_OPEN 1 #endif /* * Have to take care.. I may not use any library functions in this file, * since they are exactly then used, when the library itself couldn't be * opened... */ extern int main(); /* * This is the first code executed. Note that a_magic has to be at * a known offset from the start of the code section in order for * execve() to know that the program that it is starting uses the * ixemul library. * * The first instruction used to be a "jmp pc@(_ENTRY)", which when * assembled by gas 2.5.2 produces an 8 byte 68020 PC relative jump * rather than the desired 68000 short PC relative jump. Changing * it to "jmp pc@(_ENTRY:W)" generated the right instruction but * a bad jmp offset. So we use "jra _ENTRY" which seems to work * fine on all m68k. However, since programs are now in use * linked with crt0 files with the 8 byte instruction, we need to * maintain the hack in execve() that allows either jmp, and now * the jra, and we need to ensure that a 16 bit displacement is * required to reach ENTRY() or else we will have to add yet * another pattern to match in execve(). * */ #ifdef SHAREDL asm(" "); // Not used by ELF loader #define STACKSIZE 100000 #define str(s) #s #define sstr(s) str(s) asm(" .text extend_stack_ix_startup: /* stwu 1,-16(1) stw 5,12(1) lis 5,___stack@ha lwz 5,___stack@l(5) lwz 5,0(5) bl __stkext_startup lwz 5,12(1) addi 1,1,16*/ no_stkext1: b ix_startup .type extend_stack_ix_startup,@function .size extend_stack_ix_startup,$-extend_stack_ix_startup .data .globl ___stack .ascii \"StCk\" ___stack: .long " sstr(STACKSIZE) " .ascii \"sTcK\" "); #elif defined(NATIVE_MORPHOS) asm(" .section \".text\" b ENTRY /* by default jump to normal AmigaOS startup */ /* this is a struct exec, for now only OMAGIC is supported */ .globl exec exec: .short 1 /*__machtype /* a_mid */ .short 0407 /* a_magic = OMAGIC */ .long __text_size /* a_text */ data_size: .long __sdata_size /* a_data */ bss_size: .long __sbss_size /* a_bss */ .long 0 /* a_syms */ .long exec_entry /* a_entry */ .long 0 /* a_trsize */ .long 0 /* a_drsize */ /* word alignment is guaranteed */ .section \".sdata\" "); #else asm(" \n\ .text \n\ \n\ jra _ENTRY | by default jump to normal AmigaOS startup \n\ .align 2 | ensure exec starts at byte offset 4 \n\ \n\ | this is a struct exec, for now only OMAGIC is supported \n\ .globl exec \n\ exec: \n\ .word ___machtype | a_mid \n\ .word 0407 | a_magic = OMAGIC \n\ .long ___text_size | a_text \n\ .long ___data_size | a_data \n\ .long ___bss_size | a_bss \n\ .long 0 | a_syms \n\ .long _exec_entry | a_entry \n\ .long 0 | a_trsize \n\ .long 0 | a_drsize \n\ \n\ | word alignment is guaranteed \n\ "); #endif extern int ix_expand_cmd_line; /* expand wildcards ? */ int h_errno = 0; /* networking error code */ struct __res_state _res = { /* Resolver state default settings */ RES_TIMEOUT, /* retransmition time interval */ 4, /* number of times to retransmit */ RES_DEFAULT, /* options flags */ 1 /* number of name servers */ }; int _res_socket = -1; /* resolv socket used for communications */ char *ix_default_wb_window = 0; /* Default Workbench output window name. */ int errno = 0; /* error results from the library come in here.. */ char *_ctype_; /* we use a pointer into the library, this is static anyway */ int sys_nerr; /* number of system error codes */ struct ExecBase *SysBase; /* ExecBase or pOS_ExecBase pointer */ struct DosLibrary *DOSBase; /* DOSBase or pOS_DosBase pointer */ struct __sFILE **__sF; /* pointer to stdin/out/err */ static char *dummy_environ = 0; /* dummy environment */ char **environ = { &dummy_environ }; /* this is a default for programs not started via exec_entry */ char *__progname = ""; /* program name */ int ix_os = 0; /* the OS that the program is running under */ /* AmigaOS: 0 */ /* pOS: 'pOS\0' */ extern void *__stk_limit; extern unsigned long __stk_argbytes; #ifdef __MORPHOS__ #define GET_VA_ARRAY(x) __va_overflow(x) #else #define GET_VA_ARRAY(x) x #endif static void ix_panic(void *SysBase, const char *msg, ...) { struct IntuitionBase *IntuitionBase; va_list ap; /* Use address 4 instead of the SysBase global as globals may not yet be available (a4-handling) */ #undef EXEC_BASE_NAME #define EXEC_BASE_NAME *(void **)4 va_start(ap, msg); IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 0); if (IntuitionBase) { struct EasyStruct panic = { sizeof(struct EasyStruct), 0, "startup message", (char *)msg, "Abort" }; EasyRequestArgs(NULL, &panic, NULL, GET_VA_ARRAY(ap)); CloseLibrary((struct Library *) IntuitionBase); } va_end(ap); #undef EXEC_BASE_NAME #define EXEC_BASE_NAME SysBase } #ifdef BASECRT0 extern int __datadata_relocs(); /*#ifdef NATIVE_MORPHOS extern int __sdata_size, __sbss_size; #else extern int __data_size, __bss_size; #endif*/ #ifdef RCRT0 /* have to do this this way, or it is done base-relative.. */ #ifdef __PPC__ int __dbsize(void); asm(" .section \".text\" .type __dbsize,@function .globl __dbsize __dbsize: lis 3,data_size@ha lis 4,bss_size@ha lwz 3,data_size@l(3) lwz 4,bss_size@l(4) add 3,3,4 blr __end__dbsize: .size __dbsize,__end__dbsize-__dbsize "); #else int __dbsize(void) { int res; asm ("movel #___data_size,%0; addl #___bss_size,%0" : "=r" (res)); return res; } #endif static void inline ix_resident(struct ixemul_base *base, int num, int a4, int size, void *relocs) { #ifdef NATIVE_MORPHOS base->basearray[SYS_ix_resident-1](num, a4, size, relocs); #else typedef void (*func)(int, int, int, void *); ((func)((int)base - 6*(SYS_ix_resident + 4))) (num, a4, size, relocs); #endif } #else static void inline ix_resident(struct ixemul_base *base, int num, int a4) { #ifdef NATIVE_MORPHOS base->basearray[SYS_ix_resident-1](num, a4); #else typedef void (*func)(int, int); ((func)((int)base - 6*(SYS_ix_resident + 4))) (num, a4); #endif } #endif #endif /* BASECRT0 */ #if HANDLE_DINAMIC_IXEMUL_OPEN #define EXTLONG extern unsigned long #define OR , #define END ; #include "varjumbo_48.2.h" #include "varjumbo_49.17.h" #include "varjumbo_49.30.h" #undef END #undef OR #undef EXTLONG static __inline long RequiredIxemulLibrary(void *SysBase, struct ixemul_base *ibase) { struct Library * l = (struct Library *) ibase; long ixv = 48, ixr = 2, rc = 0; #define EXTLONG #define OR || #define END if ( #include "varjumbo_49.30.h" ) { ixv = 49; ixr = 30; } else if ( #include "varjumbo_49.17.h" ) { ixv = 49; ixr = 30; } /*if ( #include "varjumbo_48.2.h" ) { }*/ #undef END #undef OR #undef EXTLONG if((ixv > 48) && ((struct Library *)SysBase)->lib_Version > 49 && !FindResident("MorphOS")) { ix_panic(SysBase, "This Ixemul program cannot be run under AmigaOS 4.x"); } else if((!l)||( l->lib_Version < ixv ) || (( l->lib_Version == ixv ) && ( l->lib_Revision < ixr ))) { ix_panic(SysBase, "Need at least version %ld.%ld of " IX_NAME ".",ixv,ixr); } else { rc = 1; } return(rc); } #endif /* HANDLE_DINAMIC_IXEMUL_OPEN */ static int exec_entry(struct ixemul_base *ixembase, int argc, char *argv[], char *env[], long os) { struct ixemul_base *base = ixembase; #ifdef BASECRT0 register int a4 = 0; /* needed, so that data can be accessed. ix_resident might change this again afterwards */ #ifdef NATIVE_MORPHOS asm volatile ("lis 13,__r13_init@ha; addi 13,13,__r13_init@l" : "=r" (a4) : "0" (a4)); asm volatile ("mr %0,13" : "=r" (a4) : "0" (a4)); #else asm volatile ("lea ___a4_init,a4" : "=r" (a4) : "0" (a4)); asm volatile ("movel a4,%0" : "=r" (a4) : "0" (a4)); #endif #ifdef RCRT0 ix_resident(base, 4, a4, __dbsize(), __datadata_relocs); #else ix_resident(base, 2, a4); #endif #endif /* BASECRT0 */ ixemulbase = base; #ifndef NATIVE_MORPHOS ixrealbase = ixembase; #else _ixbasearray = base->basearray; #endif SysBase = *(void **)4; #if HANDLE_DINAMIC_IXEMUL_OPEN if( ! RequiredIxemulLibrary( SysBase, ixembase )) { return W_EXITCODE(20, 0); } #else /* HANDLE_DINAMIC_IXEMUL_OPEN */ if (ixembase->ix_lib.lib_Version < IX_VERSION) { ix_panic(SysBase, "Need at least version " MSTRING (IX_VERSION) " of " IX_NAME "."); return W_EXITCODE(20, 0); } #endif /* HANDLE_DINAMIC_IXEMUL_OPEN */ ix_os = os; /* * Set the limit variable to finish the initialization of the stackextend code. */ __init_stk_limit(&__stk_limit,__stk_argbytes); return extend_stack_ix_exec_entry(argc, argv, env, &errno, start_stdio); } /* this thing is best done with sprintf else, but it has to work without the * library as well ;-( */ __inline static char * itoa(int num) { short snum = num; /* how large can a long get...?? */ /* Answer (by ljr): best method to use (in terms of portability) involves number theory. The exact number of decimal digits needed to store a given number of binary digits is ceiling ( number_of_binary_digits * log(2) / log(10) ) or ceiling ( number_of_binary_digits * 0.301029996 ) Since sizeof evaluates to the number of bytes a given type takes instead of the number of bits, we need to multiply sizeof (type) by CHAR_BIT to obtain the number of bits. Since an array size specifier needs to be integer type, we multiply by 302 and divide by 1000 instead of multiplying by 0.301029996. Finally, we add 1 for the null terminator and 1 because we want the ceiling of the function instead of the floor. Funny thing about this whole affair is that you really wanted to know the size a short could expand to be and not a long... :-) I know comments get out of date, etc. The nice thing about this method is that the size of the array is picked at compile time based upon the number of bytes really needed by the local C implementation. */ static char buf[sizeof snum * CHAR_BIT * 302 / 1000 + 1 + 1]; char *cp; buf[sizeof buf - 1] = 0; cp = &buf[sizeof buf - 1]; do { *--cp = (snum % 10) + '0'; snum /= 10; } while (snum); return cp; } __inline static char * pstrcpy(char *start, char *arg) { while ((*start++ = *arg++)) ; return start - 1; } /* Note: This routine must be far enough away from the start of code so that the PC relative offset won't fit in a byte and the assembler will generate the right instruction pattern that execve() is looking for to know that this is a program that uses the ixemul.library. */ #ifdef NATIVE_MORPHOS static int ENTRY(UBYTE *aline, ULONG alen) { #else static int ENTRY(void) { register unsigned char *rega0 asm("a0"); register unsigned long regd0 asm("d0"); UBYTE *aline = rega0; ULONG alen = regd0; #endif #ifdef BASECRT0 register int a4 = 0; #endif /* BASECRT0 */ struct ixemul_base *ibase; int res; #ifdef BASECRT0 /* needed, so that data can be accessed. ix_resident() might change this again afterwards */ #ifdef NATIVE_MORPHOS asm volatile ("lis 13,__r13_init@ha; addi 13,13,__r13_init@l" : "=r" (a4) : "0" (a4)); asm volatile ("mr %0,13" : "=r" (a4) : "0" (a4)); #else asm volatile("lea ___a4_init,a4" : "=r" (a4) : "0" (a4)); asm volatile("movel a4,%0" : "=r" (a4) : "0" (a4)); #endif #endif /* BASECRT0 */ /* Use address 4 instead of the SysBase global as globals may not yet be available (a4-handling) */ #undef EXEC_BASE_NAME #define EXEC_BASE_NAME *(void **)4 #if HANDLE_DINAMIC_IXEMUL_OPEN ibase = (struct ixemul_base *)OpenLibrary(IX_NAME,0); if( ! RequiredIxemulLibrary(*(void **)4, ibase )) { CloseLibrary((struct Library *) ibase ); ibase = NULL; } #else /* HANDLE_DINAMIC_IXEMUL_OPEN */ ibase = (struct ixemul_base *)OpenLibrary(IX_NAME, IX_VERSION); #endif /* HANDLE_DINAMIC_IXEMUL_OPEN */ if (ibase) { struct ixemul_base *base = ibase; #ifdef BASECRT0 #ifdef RCRT0 ix_resident(base, 4, a4, __dbsize(), __datadata_relocs); #else ix_resident(base, 2, a4); #endif #endif /* BASECRT0 */ #ifdef NATIVE_MORPHOS _ixbasearray = base->basearray; #endif #ifndef NATIVE_MORPHOS ixrealbase = ibase; #endif ixemulbase = base; SysBase = *(void **)4; ix_os = 0; /* * Set the limit variable to finish the initialization of the stackextend code. */ __init_stk_limit(&__stk_limit,__stk_argbytes); res = extend_stack_ix_startup(aline, alen, ix_expand_cmd_line, ix_default_wb_window, (int)start_stdio, &errno); CloseLibrary((struct Library *)base); } else { struct Process *me = (struct Process *)((*(struct ExecBase **)4)->ThisTask); #if !HANDLE_DINAMIC_IXEMUL_OPEN ix_panic(SysBase, "Need at least version " MSTRING (IX_VERSION) " of " IX_NAME "."); #endif /* quickly deal with the WB startup message, as the library couldn't do * this for us. Nothing at all is done that isn't necessary to just shutup * workbench..*/ if (!me->pr_CLI) { Forbid(); ReplyMsg((WaitPort(&me->pr_MsgPort), GetMsg(&me->pr_MsgPort))); } res = 20; } return res; #undef EXEC_BASE_NAME #define EXEC_BASE_NAME SysBase } void ix_get_variables(int from_vfork_setup_child) { /* more to follow ;-) */ ix_get_vars(12, &_ctype_, &sys_nerr, (struct Library **)&SysBase, &DOSBase, &__sF, &environ, (from_vfork_setup_child ? &environ : NULL), (from_vfork_setup_child ? &errno : NULL), &h_errno, &_res, &_res_socket, NULL); } #ifdef NATIVE_MORPHOS #ifdef SUPPORT_CTORS void call_dtors(void) { int i, size; size = (int)__dtrslist[-2] / sizeof(__dtrslist[0]) - 2; for (i = 0; i < size; ++i) { if (__dtrslist[i]) __dtrslist[i](); } } #endif #endif int start_stdio(int argc, char **argv, char **env) { #ifndef BASECRT0 extern void _etext (); extern void _mcleanup (void); #endif /* BASECRT0 */ ix_get_variables(0); environ = env; #ifndef BASECRT0 #ifdef MCRT0 atexit(_mcleanup); monstartup((char *)start_stdio, (char *)_etext); #endif #endif /* not BASECRT0 */ if (argv[0]) if ((__progname = "" /*strrchr(argv[0], '/')*/)) __progname++; else __progname = argv[0]; else { __progname = alloca(40); if (!GetProgramName(__progname, 40)) __progname = ""; } #ifdef NATIVE_MORPHOS #ifdef SUPPORT_CTORS atexit(call_dtors); { int i, size; size = (int)__ctrslist[-2] / sizeof(__ctrslist[0]) - 2; for (i = 0; i < size; ++i) { if (__ctrslist[i]) __ctrslist[i](); } } #endif #endif #ifdef SUPPORT_INIT atexit(call_fini); call_init(); #endif return main(argc, argv, env); } #ifdef NATIVE_MORPHOS asm(" .section \".text\" .type extend_stack_ix_startup,@function extend_stack_ix_startup: " #ifdef BASECRT0 #ifdef LBASE " addis 11,13,__stack@drelha lwz 11,__stack@drell(11)" #else " lwz 11,__stack@sdarel(13)" #endif #else " lis 11,__stack@ha lwz 11,__stack@l(11)" #endif " lis 10,ix_startup@ha addi 10,10,ix_startup@l b __stkext_startup __end_extend_stack_ix_startup: .size extend_stack_ix_startup,__end_extend_stack_ix_startup-extend_stack_ix_startup .type extend_stack_ix_exec_entry,@function extend_stack_ix_exec_entry: " #ifdef BASECRT0 #ifdef LBASE " addis 11,13,__stack@drelha lwz 11,__stack@drell(11)" #else " lwz 11,__stack@sdarel(13)" #endif #else " lis 11,__stack@ha lwz 11,__stack@l(11)" #endif " lis 10,ix_exec_entry@ha addi 10,10,ix_exec_entry@l b __stkext_startup __end_extend_stack_ix_exec_entry: .size extend_stack_ix_exec_entry,__end_extend_stack_ix_exec_entry-extend_stack_ix_exec_entry "); #else asm(" \n\ .text \n\ \n\ _extend_stack_ix_startup: \n\ "); #ifdef BASECRT0 #ifdef LBASE asm(" \n\ movel a4@(___stack:L),d0 \n"); #else asm(" \n\ movel a4@(___stack:W),d0 \n"); #endif #else asm(" movel ___stack,d0 \n"); #endif asm (" \n\ beq no_stkext1 \n\ jbsr ___stkext_startup \n\ no_stkext1: \n\ jmp _ix_startup \n\ \n\ _extend_stack_ix_exec_entry: \n\ "); #ifdef BASECRT0 #ifdef LBASE asm(" movel a4@(___stack:L),d0 \n"); #else asm(" movel a4@(___stack:W),d0 \n"); #endif #else asm(" movel ___stack,d0 \n"); #endif asm (" \n\ beq no_stkext2 \n\ jbsr ___stkext_startup \n\ no_stkext2: \n\ jmp _ix_exec_entry \n\ "); #endif #ifdef NATIVE_MORPHOS #ifndef BASECRT0 #ifdef CRT0 /* * null mcount and moncontrol, * just in case some routine is compiled for profiling */ asm(".globl mcount"); asm(".globl _moncontrol"); asm("_moncontrol:"); asm("mcount: blr"); #endif /* CRT0 */ #endif /* not BASECRT0 */ #else /* NATIVE_MORPHOS */ #ifndef BASECRT0 #ifdef CRT0 /* * null mcount and moncontrol, * just in case some routine is compiled for profiling */ asm(".globl mcount \n"); asm(".globl _moncontrol \n"); asm("_moncontrol: \n"); asm("mcount: rts \n"); #endif /* CRT0 */ #endif /* not BASECRT0 */ #endif /* NATIVE_MORPHOS */ #ifndef BASECRT0 #ifdef MCRT0 #include "gmon.c" #endif #endif /* not BASECRT0 */ #ifdef NATIVE_MORPHOS #ifdef SUPPORT_CTORS asm(" .section \".ctors\",\"a\",@progbits __ctrslist: .long 0 "); asm(" .section \".dtors\",\"a\",@progbits __dtrslist: .long 0 "); #endif #ifdef SUPPORT_INIT asm("\n\ .section \".text\",\"ax\",@progbits\n\ .globl __init .globl __fini call_init: lis 9,__init@ha addi 9,9,__init@l mtctr 9 bctr call_fini: lis 9,__fini@ha addi 9,9,__fini@l mtctr 9 bctr "); #endif #endif