X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=ghc%2Frts%2FLinker.c;h=7d9a5500b11bba7682235521b45c58a5706dac78;hb=424774f4fc2ad8532dd4c135b00c33b578f80d97;hp=3812d726435af97030ba3d7e1d27ed077f6af8a3;hpb=5c002b21402f9b1f75650373b86f9d6f7b9bc6e4;p=ghc-hetmet.git diff --git a/ghc/rts/Linker.c b/ghc/rts/Linker.c index 3812d72..7d9a550 100644 --- a/ghc/rts/Linker.c +++ b/ghc/rts/Linker.c @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- - * $Id: Linker.c,v 1.92 2002/06/09 19:27:16 panne Exp $ + * $Id: Linker.c,v 1.120 2003/05/30 09:06:24 simonmar Exp $ * - * (c) The GHC Team, 2000, 2001 + * (c) The GHC Team, 2000-2003 * * RTS Object Linker * @@ -24,11 +24,16 @@ #include #endif +#include +#include + #ifdef HAVE_SYS_STAT_H #include #endif -#ifdef HAVE_DLFCN_H +#if defined(HAVE_FRAMEWORK_HASKELLSUPPORT) +#include +#elif defined(HAVE_DLFCN_H) #include #endif @@ -54,15 +59,25 @@ #include #endif -#if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS) || defined(freebsd_TARGET_OS) +#if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS) || defined(freebsd_TARGET_OS) || defined(netbsd_TARGET_OS) # define OBJFORMAT_ELF #elif defined(cygwin32_TARGET_OS) || defined (mingw32_TARGET_OS) # define OBJFORMAT_PEi386 # include +# include +#elif defined(darwin_TARGET_OS) +# include +# define OBJFORMAT_MACHO +# include +# include +# include #endif /* Hash table mapping symbol names to Symbol */ -/*Str*/HashTable *symhash; +static /*Str*/HashTable *symhash; + +/* List of currently loaded objects */ +ObjectCode *objects = NULL; /* initially empty */ #if defined(OBJFORMAT_ELF) static int ocVerifyImage_ELF ( ObjectCode* oc ); @@ -72,6 +87,12 @@ static int ocResolve_ELF ( ObjectCode* oc ); static int ocVerifyImage_PEi386 ( ObjectCode* oc ); static int ocGetNames_PEi386 ( ObjectCode* oc ); static int ocResolve_PEi386 ( ObjectCode* oc ); +#elif defined(OBJFORMAT_MACHO) +static int ocVerifyImage_MachO ( ObjectCode* oc ); +static int ocGetNames_MachO ( ObjectCode* oc ); +static int ocResolve_MachO ( ObjectCode* oc ); + +static void machoInitSymbolsWithoutUnderscore( void ); #endif /* ----------------------------------------------------------------------------- @@ -184,11 +205,7 @@ typedef struct _RtsSymbolVal { SymX(uname) \ SymX(unlink) \ SymX(utime) \ - SymX(waitpid) \ - Sym(__divdi3) \ - Sym(__udivdi3) \ - Sym(__moddi3) \ - Sym(__umoddi3) + SymX(waitpid) #elif !defined(mingw32_TARGET_OS) #define RTS_MINGW_ONLY_SYMBOLS /**/ @@ -197,10 +214,20 @@ typedef struct _RtsSymbolVal { #define RTS_POSIX_ONLY_SYMBOLS /**/ #define RTS_CYGWIN_ONLY_SYMBOLS /**/ +/* Extra syms gen'ed by mingw-2's gcc-3.2: */ +#if __GNUC__>=3 +#define RTS_MINGW_EXTRA_SYMS \ + Sym(_imp____mb_cur_max) \ + Sym(_imp___pctype) +#else +#define RTS_MINGW_EXTRA_SYMS +#endif + /* These are statically linked from the mingw libraries into the ghc executable, so we have to employ this hack. */ #define RTS_MINGW_ONLY_SYMBOLS \ - SymX(memset) \ + SymX(asyncReadzh_fast) \ + SymX(asyncWritezh_fast) \ SymX(memset) \ SymX(inet_ntoa) \ SymX(inet_addr) \ @@ -260,11 +287,8 @@ typedef struct _RtsSymbolVal { Sym(opendir) \ Sym(readdir) \ Sym(rewinddir) \ - Sym(closedir) \ - Sym(__divdi3) \ - Sym(__udivdi3) \ - Sym(__moddi3) \ - Sym(__umoddi3) + RTS_MINGW_EXTRA_SYMS \ + Sym(closedir) #endif #ifndef SMP @@ -277,41 +301,40 @@ typedef struct _RtsSymbolVal { Maybe_ForeignObj \ Maybe_Stable_Names \ Sym(StgReturn) \ - Sym(__stginit_GHCziPrim) \ - Sym(init_stack) \ - SymX(__stg_chk_0) \ - SymX(__stg_chk_1) \ - SymX(stg_chk_2) \ - SymX(stg_chk_3) \ - SymX(stg_chk_4) \ - SymX(stg_chk_5) \ - SymX(stg_chk_6) \ - SymX(stg_chk_7) \ - SymX(stg_chk_8) \ - Sym(stg_enterStackTop) \ - SymX(stg_gc_d1) \ - SymX(stg_gc_l1) \ + SymX(stg_enter_info) \ + SymX(stg_enter_ret) \ + SymX(stg_gc_void_info) \ SymX(__stg_gc_enter_1) \ - SymX(stg_gc_enter_2) \ - SymX(stg_gc_enter_3) \ - SymX(stg_gc_enter_4) \ - SymX(stg_gc_enter_5) \ - SymX(stg_gc_enter_6) \ - SymX(stg_gc_enter_7) \ - SymX(stg_gc_enter_8) \ - SymX(stg_gc_f1) \ SymX(stg_gc_noregs) \ - SymX(stg_gc_seq_1) \ - SymX(stg_gc_unbx_r1) \ + SymX(stg_gc_unpt_r1_info) \ SymX(stg_gc_unpt_r1) \ - SymX(stg_gc_ut_0_1) \ - SymX(stg_gc_ut_1_0) \ - SymX(stg_gen_chk) \ + SymX(stg_gc_unbx_r1_info) \ + SymX(stg_gc_unbx_r1) \ + SymX(stg_gc_f1_info) \ + SymX(stg_gc_f1) \ + SymX(stg_gc_d1_info) \ + SymX(stg_gc_d1) \ + SymX(stg_gc_l1_info) \ + SymX(stg_gc_l1) \ + SymX(__stg_gc_fun) \ + SymX(stg_gc_fun_info) \ + SymX(stg_gc_fun_ret) \ + SymX(stg_gc_gen) \ + SymX(stg_gc_gen_info) \ + SymX(stg_gc_gen_hp) \ + SymX(stg_gc_ut) \ + SymX(stg_gen_yield) \ + SymX(stg_yield_noregs) \ SymX(stg_yield_to_interpreter) \ + SymX(stg_gen_block) \ + SymX(stg_block_noregs) \ + SymX(stg_block_1) \ + SymX(stg_block_takemvar) \ + SymX(stg_block_putmvar) \ + SymX(stg_seq_frame_info) \ SymX(ErrorHdrHook) \ MAIN_CAP_SYM \ SymX(MallocFailHook) \ - SymX(NoRunnableThreadsHook) \ SymX(OnExitHook) \ SymX(OutOfHeapHook) \ SymX(PatErrorHdrHook) \ @@ -374,9 +397,10 @@ typedef struct _RtsSymbolVal { SymX(newArrayzh_fast) \ SymX(newBCOzh_fast) \ SymX(newByteArrayzh_fast) \ - SymX(newCAF) \ + SymX_redirect(newCAF, newDynCAF) \ SymX(newMVarzh_fast) \ SymX(newMutVarzh_fast) \ + SymX(atomicModifyMutVarzh_fast) \ SymX(newPinnedByteArrayzh_fast) \ SymX(orIntegerzh_fast) \ SymX(performGC) \ @@ -396,7 +420,6 @@ typedef struct _RtsSymbolVal { SymX(rts_evalIO) \ SymX(rts_evalLazyIO) \ SymX(rts_eval_) \ - SymX(rts_getAddr) \ SymX(rts_getBool) \ SymX(rts_getChar) \ SymX(rts_getDouble) \ @@ -404,11 +427,12 @@ typedef struct _RtsSymbolVal { SymX(rts_getInt) \ SymX(rts_getInt32) \ SymX(rts_getPtr) \ + SymX(rts_getFunPtr) \ SymX(rts_getStablePtr) \ SymX(rts_getThreadId) \ SymX(rts_getWord) \ SymX(rts_getWord32) \ - SymX(rts_mkAddr) \ + SymX(rts_lock) \ SymX(rts_mkBool) \ SymX(rts_mkChar) \ SymX(rts_mkDouble) \ @@ -419,6 +443,7 @@ typedef struct _RtsSymbolVal { SymX(rts_mkInt64) \ SymX(rts_mkInt8) \ SymX(rts_mkPtr) \ + SymX(rts_mkFunPtr) \ SymX(rts_mkStablePtr) \ SymX(rts_mkString) \ SymX(rts_mkWord) \ @@ -426,8 +451,11 @@ typedef struct _RtsSymbolVal { SymX(rts_mkWord32) \ SymX(rts_mkWord64) \ SymX(rts_mkWord8) \ + SymX(rts_unlock) \ SymX(run_queue_hd) \ SymX(setProgArgv) \ + SymX(startupHaskell) \ + SymX(shutdownHaskell) \ SymX(shutdownHaskellAndExit) \ SymX(stable_ptr_table) \ SymX(stackOverflow) \ @@ -438,6 +466,35 @@ typedef struct _RtsSymbolVal { SymX(stg_INTLIKE_closure) \ SymX(stg_MUT_ARR_PTRS_FROZEN_info) \ SymX(stg_WEAK_info) \ + SymX(stg_ap_v_info) \ + SymX(stg_ap_f_info) \ + SymX(stg_ap_d_info) \ + SymX(stg_ap_l_info) \ + SymX(stg_ap_n_info) \ + SymX(stg_ap_p_info) \ + SymX(stg_ap_pv_info) \ + SymX(stg_ap_pp_info) \ + SymX(stg_ap_ppv_info) \ + SymX(stg_ap_ppp_info) \ + SymX(stg_ap_pppp_info) \ + SymX(stg_ap_ppppp_info) \ + SymX(stg_ap_pppppp_info) \ + SymX(stg_ap_ppppppp_info) \ + SymX(stg_ap_0_ret) \ + SymX(stg_ap_v_ret) \ + SymX(stg_ap_f_ret) \ + SymX(stg_ap_d_ret) \ + SymX(stg_ap_l_ret) \ + SymX(stg_ap_n_ret) \ + SymX(stg_ap_p_ret) \ + SymX(stg_ap_pv_ret) \ + SymX(stg_ap_pp_ret) \ + SymX(stg_ap_ppv_ret) \ + SymX(stg_ap_ppp_ret) \ + SymX(stg_ap_pppp_ret) \ + SymX(stg_ap_ppppp_ret) \ + SymX(stg_ap_pppppp_ret) \ + SymX(stg_ap_ppppppp_ret) \ SymX(stg_ap_1_upd_info) \ SymX(stg_ap_2_upd_info) \ SymX(stg_ap_3_upd_info) \ @@ -463,9 +520,7 @@ typedef struct _RtsSymbolVal { SymX(stg_sel_7_upd_info) \ SymX(stg_sel_8_upd_info) \ SymX(stg_sel_9_upd_info) \ - SymX(stg_seq_frame_info) \ SymX(stg_upd_frame_info) \ - SymX(__stg_update_PAP) \ SymX(suspendThread) \ SymX(takeMVarzh_fast) \ SymX(timesIntegerzh_fast) \ @@ -487,6 +542,21 @@ typedef struct _RtsSymbolVal { #define RTS_LONG_LONG_SYMS /* nothing */ #endif +// 64-bit support functions in libgcc.a +#if defined(__GNUC__) && SIZEOF_VOID_P <= 4 +#define RTS_LIBGCC_SYMBOLS \ + Sym(__divdi3) \ + Sym(__udivdi3) \ + Sym(__moddi3) \ + Sym(__umoddi3) \ + Sym(__ashldi3) \ + Sym(__ashrdi3) \ + Sym(__lshrdi3) \ + Sym(__eprintf) +#else +#define RTS_LIBGCC_SYMBOLS +#endif + #ifdef ia64_TARGET_ARCH /* force these symbols to be present */ #define RTS_EXTRA_SYMBOLS \ @@ -495,17 +565,29 @@ typedef struct _RtsSymbolVal { #define RTS_EXTRA_SYMBOLS /* nothing */ #endif +#ifdef darwin_TARGET_OS + // Symbols that don't have a leading underscore + // on Mac OS X. They have to receive special treatment, + // see machoInitSymbolsWithoutUnderscore() +#define RTS_MACHO_NOUNDERLINE_SYMBOLS \ + Sym(saveFP) \ + Sym(restFP) +#endif + /* entirely bogus claims about types of these symbols */ #define Sym(vvv) extern void (vvv); #define SymX(vvv) /**/ +#define SymX_redirect(vvv,xxx) /**/ RTS_SYMBOLS RTS_LONG_LONG_SYMS RTS_EXTRA_SYMBOLS RTS_POSIX_ONLY_SYMBOLS RTS_MINGW_ONLY_SYMBOLS RTS_CYGWIN_ONLY_SYMBOLS +RTS_LIBGCC_SYMBOLS #undef Sym #undef SymX +#undef SymX_redirect #ifdef LEADING_UNDERSCORE #define MAYBE_LEADING_UNDERSCORE_STR(s) ("_" s) @@ -517,6 +599,12 @@ RTS_CYGWIN_ONLY_SYMBOLS (void*)(&(vvv)) }, #define SymX(vvv) Sym(vvv) +// SymX_redirect allows us to redirect references to one symbol to +// another symbol. See newCAF/newDynCAF for an example. +#define SymX_redirect(vvv,xxx) \ + { MAYBE_LEADING_UNDERSCORE_STR(#vvv), \ + (void*)(&(xxx)) }, + static RtsSymbolVal rtsSyms[] = { RTS_SYMBOLS RTS_LONG_LONG_SYMS @@ -524,6 +612,7 @@ static RtsSymbolVal rtsSyms[] = { RTS_POSIX_ONLY_SYMBOLS RTS_MINGW_ONLY_SYMBOLS RTS_CYGWIN_ONLY_SYMBOLS + RTS_LIBGCC_SYMBOLS { 0, 0 } /* sentinel */ }; @@ -564,7 +653,11 @@ static void ghciInsertStrHashTable ( char* obj_name, /* ----------------------------------------------------------------------------- * initialize the object linker */ -#if defined(OBJFORMAT_ELF) + + +static int linker_init_done = 0 ; + +#if defined(OBJFORMAT_ELF) || defined(OBJFORMAT_MACHO) static void *dl_prog_handle; #endif @@ -573,6 +666,13 @@ initLinker( void ) { RtsSymbolVal *sym; + /* Make initLinker idempotent, so we can call it + before evey relevant operation; that means we + don't need to initialise the linker separately */ + if (linker_init_done == 1) { return; } else { + linker_init_done = 1; + } + symhash = allocStrHashTable(); /* populate the symbol table with stuff from the RTS */ @@ -580,12 +680,19 @@ initLinker( void ) ghciInsertStrHashTable("(GHCi built-in symbols)", symhash, sym->lbl, sym->addr); } -# if defined(OBJFORMAT_ELF) +# if defined(OBJFORMAT_MACHO) + machoInitSymbolsWithoutUnderscore(); +# endif + +# if defined(OBJFORMAT_ELF) || defined(OBJFORMAT_MACHO) dl_prog_handle = dlopen(NULL, RTLD_LAZY); # endif } /* ----------------------------------------------------------------------------- + * Loading DLL or .so dynamic libraries + * ----------------------------------------------------------------------------- + * * Add a DLL from which symbols may be found. In the ELF case, just * do RTLD_GLOBAL-style add, so no further messing around needs to * happen in order that symbols in the loaded .so are findable -- @@ -594,7 +701,12 @@ initLinker( void ) * * In the PEi386 case, open the DLLs and put handles to them in a * linked list. When looking for a symbol, try all handles in the - * list. + * list. This means that we need to load even DLLs that are guaranteed + * to be in the ghc.exe image already, just so we can get a handle + * to give to loadSymbol, so that we can find the symbols. For such + * libraries, the LoadLibrary call should be a no-op except for returning + * the handle. + * */ #if defined(OBJFORMAT_PEi386) @@ -612,15 +724,16 @@ typedef static OpenedDLL* opened_dlls = NULL; #endif - - char * addDLL( char *dll_name ) { -# if defined(OBJFORMAT_ELF) +# if defined(OBJFORMAT_ELF) || defined(OBJFORMAT_MACHO) + /* ------------------- ELF DLL loader ------------------- */ void *hdl; char *errmsg; + initLinker(); + hdl= dlopen(dll_name, RTLD_NOW | RTLD_GLOBAL); if (hdl == NULL) { /* dlopen failed; return a ptr to the error msg. */ @@ -633,14 +746,15 @@ addDLL( char *dll_name ) /*NOTREACHED*/ # elif defined(OBJFORMAT_PEi386) + /* ------------------- Win32 DLL loader ------------------- */ - /* Add this DLL to the list of DLLs in which to search for symbols. - The path argument is ignored. */ char* buf; OpenedDLL* o_dll; HINSTANCE instance; - /* fprintf(stderr, "\naddDLL; path=`%s', dll_name = `%s'\n", path, dll_name); */ + initLinker(); + + /* fprintf(stderr, "\naddDLL; dll_name = `%s'\n", dll_name); */ /* See if we've already got it, and ignore if so. */ for (o_dll = opened_dlls; o_dll != NULL; o_dll = o_dll->next) { @@ -648,21 +762,32 @@ addDLL( char *dll_name ) return NULL; } + /* The file name has no suffix (yet) so that we can try + both foo.dll and foo.drv + + The documentation for LoadLibrary says: + If no file name extension is specified in the lpFileName + parameter, the default library extension .dll is + appended. However, the file name string can include a trailing + point character (.) to indicate that the module name has no + extension. */ + buf = stgMallocBytes(strlen(dll_name) + 10, "addDLL"); sprintf(buf, "%s.DLL", dll_name); instance = LoadLibrary(buf); if (instance == NULL) { - sprintf(buf, "%s.DRV", dll_name); // KAA: allow loading of drivers (like winspool.drv) + sprintf(buf, "%s.DRV", dll_name); // KAA: allow loading of drivers (like winspool.drv) instance = LoadLibrary(buf); if (instance == NULL) { - free(buf); + stgFree(buf); /* LoadLibrary failed; return a ptr to the error msg. */ return "addDLL: unknown error"; } } - free(buf); + stgFree(buf); + /* Add this DLL to the list of DLLs in which to search for symbols. */ o_dll = stgMallocBytes( sizeof(OpenedDLL), "addDLL" ); o_dll->name = stgMallocBytes(1+strlen(dll_name), "addDLL"); strcpy(o_dll->name, dll_name); @@ -683,11 +808,12 @@ void * lookupSymbol( char *lbl ) { void *val; + initLinker() ; ASSERT(symhash != NULL); val = lookupStrHashTable(symhash, lbl); if (val == NULL) { -# if defined(OBJFORMAT_ELF) +# if defined(OBJFORMAT_ELF) || defined(OBJFORMAT_MACHO) return dlsym(dl_prog_handle, lbl); # elif defined(OBJFORMAT_PEi386) OpenedDLL* o_dll; @@ -728,6 +854,7 @@ void * lookupLocalSymbol( ObjectCode* oc, char *lbl ) { void *val; + initLinker() ; val = lookupStrHashTable(oc->lochash, lbl); if (val == NULL) { @@ -752,18 +879,23 @@ void ghci_enquire ( char* addr ) char* a; const int DELTA = 64; ObjectCode* oc; + + initLinker(); + for (oc = objects; oc; oc = oc->next) { for (i = 0; i < oc->n_symbols; i++) { sym = oc->symbols[i]; if (sym == NULL) continue; - /* fprintf(stderr, "enquire %p %p\n", sym, oc->lochash); */ + // fprintf(stderr, "enquire %p %p\n", sym, oc->lochash); a = NULL; - if (oc->lochash != NULL) + if (oc->lochash != NULL) { a = lookupStrHashTable(oc->lochash, sym); - if (a == NULL) + } + if (a == NULL) { a = lookupStrHashTable(symhash, sym); + } if (a == NULL) { - /* fprintf(stderr, "ghci_enquire: can't find %s\n", sym); */ + // fprintf(stderr, "ghci_enquire: can't find %s\n", sym); } else if (addr-DELTA <= a && a <= addr+DELTA) { fprintf(stderr, "%p + %3d == `%s'\n", addr, a - addr, sym); @@ -795,6 +927,8 @@ loadObj( char *path ) FILE *f; #endif + initLinker(); + /* fprintf(stderr, "loadObj %s\n", path ); */ /* Check that we haven't already loaded this object. Don't give up @@ -824,8 +958,10 @@ loadObj( char *path ) oc->formatName = "ELF"; # elif defined(OBJFORMAT_PEi386) oc->formatName = "PEi386"; +# elif defined(OBJFORMAT_MACHO) + oc->formatName = "Mach-O"; # else - free(oc); + stgFree(oc); barf("loadObj: not implemented on this platform"); # endif @@ -897,6 +1033,8 @@ loadObj( char *path ) r = ocVerifyImage_ELF ( oc ); # elif defined(OBJFORMAT_PEi386) r = ocVerifyImage_PEi386 ( oc ); +# elif defined(OBJFORMAT_MACHO) + r = ocVerifyImage_MachO ( oc ); # else barf("loadObj: no verify method"); # endif @@ -907,6 +1045,8 @@ loadObj( char *path ) r = ocGetNames_ELF ( oc ); # elif defined(OBJFORMAT_PEi386) r = ocGetNames_PEi386 ( oc ); +# elif defined(OBJFORMAT_MACHO) + r = ocGetNames_MachO ( oc ); # else barf("loadObj: no getNames method"); # endif @@ -929,12 +1069,16 @@ resolveObjs( void ) ObjectCode *oc; int r; + initLinker(); + for (oc = objects; oc; oc = oc->next) { if (oc->status != OBJECT_RESOLVED) { # if defined(OBJFORMAT_ELF) r = ocResolve_ELF ( oc ); # elif defined(OBJFORMAT_PEi386) r = ocResolve_PEi386 ( oc ); +# elif defined(OBJFORMAT_MACHO) + r = ocResolve_MachO ( oc ); # else barf("resolveObjs: not implemented on this platform"); # endif @@ -956,6 +1100,8 @@ unloadObj( char *path ) ASSERT(symhash != NULL); ASSERT(objects != NULL); + initLinker(); + prev = NULL; for (oc = objects; oc; prev = oc, oc = oc->next) { if (!strcmp(oc->fileName,path)) { @@ -980,14 +1126,14 @@ unloadObj( char *path ) /* We're going to leave this in place, in case there are any pointers from the heap into it: */ - /* free(oc->image); */ - free(oc->fileName); - free(oc->symbols); - free(oc->sections); + /* stgFree(oc->image); */ + stgFree(oc->fileName); + stgFree(oc->symbols); + stgFree(oc->sections); /* The local hash table should have been freed at the end of the ocResolve_ call on it. */ ASSERT(oc->lochash == NULL); - free(oc); + stgFree(oc); return 1; } } @@ -1803,7 +1949,8 @@ ocResolve_PEi386 ( ObjectCode* oc ) if ((void*)S != NULL) goto foundit; (void*)S = lookupSymbol( symbol ); if ((void*)S != NULL) goto foundit; - belch("%s: unknown symbol `%s'", oc->fileName, symbol); + /* Newline first because the interactive linker has printed "linking..." */ + belch("\n%s: unknown symbol `%s'", oc->fileName, symbol); return 0; foundit: } @@ -2115,7 +2262,9 @@ ocVerifyImage_ELF ( ObjectCode* oc ) switch (ehdr->e_machine) { case EM_386: IF_DEBUG(linker,belch( "x86" )); break; case EM_SPARC: IF_DEBUG(linker,belch( "sparc" )); break; +#ifdef EM_IA_64 case EM_IA_64: IF_DEBUG(linker,belch( "ia64" )); break; +#endif default: IF_DEBUG(linker,belch( "unknown" )); belch("%s: unknown architecture", oc->fileName); return 0; @@ -2433,7 +2582,7 @@ do_Elf_Rel_relocations ( ObjectCode* oc, char* ehdrC, for (j = 0; j < nent; j++) { Elf_Addr offset = rtab[j].r_offset; - Elf_Word info = rtab[j].r_info; + Elf_Addr info = rtab[j].r_info; Elf_Addr P = ((Elf_Addr)targ) + offset; Elf_Word* pP = (Elf_Word*)P; @@ -2499,31 +2648,32 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC, { int j; char *symbol; - Elf_Addr* targ; + Elf_Addr targ; Elf_Rela* rtab = (Elf_Rela*) (ehdrC + shdr[shnum].sh_offset); int nent = shdr[shnum].sh_size / sizeof(Elf_Rela); int target_shndx = shdr[shnum].sh_info; int symtab_shndx = shdr[shnum].sh_link; stab = (Elf_Sym*) (ehdrC + shdr[ symtab_shndx ].sh_offset); - targ = (Elf_Addr*)(ehdrC + shdr[ target_shndx ].sh_offset); + targ = (Elf_Addr) (ehdrC + shdr[ target_shndx ].sh_offset); IF_DEBUG(linker,belch( "relocations for section %d using symtab %d", target_shndx, symtab_shndx )); for (j = 0; j < nent; j++) { #if defined(DEBUG) || defined(sparc_TARGET_ARCH) || defined(ia64_TARGET_ARCH) + /* This #ifdef only serves to avoid unused-var warnings. */ Elf_Addr offset = rtab[j].r_offset; + Elf_Addr P = targ + offset; #endif Elf_Addr info = rtab[j].r_info; Elf_Addr A = rtab[j].r_addend; Elf_Addr S; Elf_Addr value; # if defined(sparc_TARGET_ARCH) - /* This #ifdef only serves to avoid unused-var warnings. */ - Elf_Word* pP = (Elf_Word*)((Elf_Addr)targ + offset); + Elf_Word* pP = (Elf_Word*)P; Elf_Word w1, w2; # elif defined(ia64_TARGET_ARCH) - Elf64_Xword *pP = (Elf64_Xword *)((Elf_Addr)targ + offset); + Elf64_Xword *pP = (Elf64_Xword *)P; Elf_Addr addr; # endif @@ -2696,7 +2846,6 @@ ocResolve_ELF ( ObjectCode* oc ) return 1; } - /* * IA64 specifics * Instructions are 41 bits long, packed into 128 bit bundles with a 5-bit template @@ -2790,3 +2939,392 @@ ia64_reloc_pcrel21(Elf_Addr target, Elf_Addr value, ObjectCode *oc) #endif /* ia64 */ #endif /* ELF */ + +/* -------------------------------------------------------------------------- + * Mach-O specifics + * ------------------------------------------------------------------------*/ + +#if defined(OBJFORMAT_MACHO) + +/* + Initial support for MachO linking on Darwin/MacOS X on PowerPC chips + by Wolfgang Thaller (wolfgang.thaller@gmx.net) + + I hereby formally apologize for the hackish nature of this code. + Things that need to be done: + *) get common symbols and .bss sections to work properly. + Haskell modules seem to work, but C modules can cause problems + *) implement ocVerifyImage_MachO + *) add more sanity checks. The current code just has to segfault if there's a + broken .o file. +*/ + +static int ocVerifyImage_MachO(ObjectCode* oc) +{ + // FIXME: do some verifying here + return 1; +} + +static int resolveImports( + ObjectCode* oc, + char *image, + struct symtab_command *symLC, + struct section *sect, // ptr to lazy or non-lazy symbol pointer section + unsigned long *indirectSyms, + struct nlist *nlist) +{ + unsigned i; + + for(i=0;i*4size;i++) + { + // according to otool, reserved1 contains the first index into the indirect symbol table + struct nlist *symbol = &nlist[indirectSyms[sect->reserved1+i]]; + char *nm = image + symLC->stroff + symbol->n_un.n_strx; + void *addr = NULL; + + if((symbol->n_type & N_TYPE) == N_UNDF + && (symbol->n_type & N_EXT) && (symbol->n_value != 0)) + addr = (void*) (symbol->n_value); + else if((addr = lookupLocalSymbol(oc,nm)) != NULL) + ; + else + addr = lookupSymbol(nm); + if(!addr) + { + belch("\n%s: unknown symbol `%s'", oc->fileName, nm); + return 0; + } + ASSERT(addr); + ((void**)(image + sect->offset))[i] = addr; + } + + return 1; +} + +static int relocateSection(char *image, + struct symtab_command *symLC, struct nlist *nlist, + struct section* sections, struct section *sect) +{ + struct relocation_info *relocs; + int i,n; + + if(!strcmp(sect->sectname,"__la_symbol_ptr")) + return 1; + else if(!strcmp(sect->sectname,"__nl_symbol_ptr")) + return 1; + + n = sect->nreloc; + relocs = (struct relocation_info*) (image + sect->reloff); + + for(i=0;ir_pcrel) + { + if(scat->r_length == 2 && scat->r_type == GENERIC_RELOC_VANILLA) + { + unsigned long* word = (unsigned long*) (image + sect->offset + scat->r_address); + + *word = scat->r_value + sect->offset + ((long) image); + } + } + + continue; // FIXME: I hope it's OK to ignore all the others. + } + else + { + struct relocation_info *reloc = &relocs[i]; + if(reloc->r_pcrel && !reloc->r_extern) + continue; + + if(reloc->r_length == 2) + { + unsigned long word = 0; + + unsigned long* wordPtr = (unsigned long*) (image + sect->offset + reloc->r_address); + + if(reloc->r_type == GENERIC_RELOC_VANILLA) + { + word = *wordPtr; + } + else if(reloc->r_type == PPC_RELOC_LO16) + { + word = ((unsigned short*) wordPtr)[1]; + word |= ((unsigned long) relocs[i+1].r_address & 0xFFFF) << 16; + } + else if(reloc->r_type == PPC_RELOC_HI16) + { + word = ((unsigned short*) wordPtr)[1] << 16; + word |= ((unsigned long) relocs[i+1].r_address & 0xFFFF); + } + else if(reloc->r_type == PPC_RELOC_HA16) + { + word = ((unsigned short*) wordPtr)[1] << 16; + word += ((short)relocs[i+1].r_address & (short)0xFFFF); + } + else if(reloc->r_type == PPC_RELOC_BR24) + { + word = *wordPtr; + word = (word & 0x03FFFFFC) | (word & 0x02000000) ? 0xFC000000 : 0; + } + + + if(!reloc->r_extern) + { + long delta = + sections[reloc->r_symbolnum-1].offset + - sections[reloc->r_symbolnum-1].addr + + ((long) image); + + word += delta; + } + else + { + struct nlist *symbol = &nlist[reloc->r_symbolnum]; + char *nm = image + symLC->stroff + symbol->n_un.n_strx; + word = (unsigned long) (lookupSymbol(nm)); + if(!word) + { + belch("\nunknown symbol `%s'", nm); + return 0; + } + + if(reloc->r_pcrel) + word -= ((long)image) + sect->offset + reloc->r_address; + } + + if(reloc->r_type == GENERIC_RELOC_VANILLA) + { + *wordPtr = word; + continue; + } + else if(reloc->r_type == PPC_RELOC_LO16) + { + ((unsigned short*) wordPtr)[1] = word & 0xFFFF; + i++; continue; + } + else if(reloc->r_type == PPC_RELOC_HI16) + { + ((unsigned short*) wordPtr)[1] = (word >> 16) & 0xFFFF; + i++; continue; + } + else if(reloc->r_type == PPC_RELOC_HA16) + { + ((unsigned short*) wordPtr)[1] = ((word >> 16) & 0xFFFF) + + ((word & (1<<15)) ? 1 : 0); + i++; continue; + } + else if(reloc->r_type == PPC_RELOC_BR24) + { + *wordPtr = (*wordPtr & 0xFC000003) | (word & 0x03FFFFFC); + continue; + } + } + barf("\nunknown relocation %d",reloc->r_type); + return 0; + } + } + return 1; +} + +static int ocGetNames_MachO(ObjectCode* oc) +{ + char *image = (char*) oc->image; + struct mach_header *header = (struct mach_header*) image; + struct load_command *lc = (struct load_command*) (image + sizeof(struct mach_header)); + unsigned i,curSymbol; + struct segment_command *segLC = NULL; + struct section *sections, *la_ptrs = NULL, *nl_ptrs = NULL; + struct symtab_command *symLC = NULL; + struct dysymtab_command *dsymLC = NULL; + struct nlist *nlist; + unsigned long commonSize = 0; + char *commonStorage = NULL; + unsigned long commonCounter; + + for(i=0;incmds;i++) + { + if(lc->cmd == LC_SEGMENT) + segLC = (struct segment_command*) lc; + else if(lc->cmd == LC_SYMTAB) + symLC = (struct symtab_command*) lc; + else if(lc->cmd == LC_DYSYMTAB) + dsymLC = (struct dysymtab_command*) lc; + lc = (struct load_command *) ( ((char*)lc) + lc->cmdsize ); + } + + sections = (struct section*) (segLC+1); + nlist = (struct nlist*) (image + symLC->symoff); + + for(i=0;insects;i++) + { + if(!strcmp(sections[i].sectname,"__la_symbol_ptr")) + la_ptrs = §ions[i]; + else if(!strcmp(sections[i].sectname,"__nl_symbol_ptr")) + nl_ptrs = §ions[i]; + + // for now, only add __text and __const to the sections table + else if(!strcmp(sections[i].sectname,"__text")) + addSection(oc, SECTIONKIND_CODE_OR_RODATA, + (void*) (image + sections[i].offset), + (void*) (image + sections[i].offset + sections[i].size)); + else if(!strcmp(sections[i].sectname,"__const")) + addSection(oc, SECTIONKIND_RWDATA, + (void*) (image + sections[i].offset), + (void*) (image + sections[i].offset + sections[i].size)); + else if(!strcmp(sections[i].sectname,"__data")) + addSection(oc, SECTIONKIND_RWDATA, + (void*) (image + sections[i].offset), + (void*) (image + sections[i].offset + sections[i].size)); + } + + // count external symbols defined here + oc->n_symbols = 0; + for(i=dsymLC->iextdefsym;iiextdefsym+dsymLC->nextdefsym;i++) + { + if((nlist[i].n_type & N_TYPE) == N_SECT) + oc->n_symbols++; + } + for(i=0;insyms;i++) + { + if((nlist[i].n_type & N_TYPE) == N_UNDF + && (nlist[i].n_type & N_EXT) && (nlist[i].n_value != 0)) + { + commonSize += nlist[i].n_value; + oc->n_symbols++; + } + } + oc->symbols = stgMallocBytes(oc->n_symbols * sizeof(char*), + "ocGetNames_MachO(oc->symbols)"); + + // insert symbols into hash table + for(i=dsymLC->iextdefsym,curSymbol=0;iiextdefsym+dsymLC->nextdefsym;i++) + { + if((nlist[i].n_type & N_TYPE) == N_SECT) + { + char *nm = image + symLC->stroff + nlist[i].n_un.n_strx; + ghciInsertStrHashTable(oc->fileName, symhash, nm, image + + sections[nlist[i].n_sect-1].offset + - sections[nlist[i].n_sect-1].addr + + nlist[i].n_value); + oc->symbols[curSymbol++] = nm; + } + } + + // insert local symbols into lochash + for(i=dsymLC->ilocalsym;iilocalsym+dsymLC->nlocalsym;i++) + { + if((nlist[i].n_type & N_TYPE) == N_SECT) + { + char *nm = image + symLC->stroff + nlist[i].n_un.n_strx; + ghciInsertStrHashTable(oc->fileName, oc->lochash, nm, image + + sections[nlist[i].n_sect-1].offset + - sections[nlist[i].n_sect-1].addr + + nlist[i].n_value); + } + } + + + commonStorage = stgCallocBytes(1,commonSize,"ocGetNames_MachO(common symbols)"); + commonCounter = (unsigned long)commonStorage; + for(i=0;insyms;i++) + { + if((nlist[i].n_type & N_TYPE) == N_UNDF + && (nlist[i].n_type & N_EXT) && (nlist[i].n_value != 0)) + { + char *nm = image + symLC->stroff + nlist[i].n_un.n_strx; + unsigned long sz = nlist[i].n_value; + + nlist[i].n_value = commonCounter; + + ghciInsertStrHashTable(oc->fileName, symhash, nm, (void*)commonCounter); + oc->symbols[curSymbol++] = nm; + + commonCounter += sz; + } + } + return 1; +} + +static int ocResolve_MachO(ObjectCode* oc) +{ + char *image = (char*) oc->image; + struct mach_header *header = (struct mach_header*) image; + struct load_command *lc = (struct load_command*) (image + sizeof(struct mach_header)); + unsigned i; + struct segment_command *segLC = NULL; + struct section *sections, *la_ptrs = NULL, *nl_ptrs = NULL; + struct symtab_command *symLC = NULL; + struct dysymtab_command *dsymLC = NULL; + struct nlist *nlist; + unsigned long *indirectSyms; + + for(i=0;incmds;i++) + { + if(lc->cmd == LC_SEGMENT) + segLC = (struct segment_command*) lc; + else if(lc->cmd == LC_SYMTAB) + symLC = (struct symtab_command*) lc; + else if(lc->cmd == LC_DYSYMTAB) + dsymLC = (struct dysymtab_command*) lc; + lc = (struct load_command *) ( ((char*)lc) + lc->cmdsize ); + } + + sections = (struct section*) (segLC+1); + nlist = (struct nlist*) (image + symLC->symoff); + + for(i=0;insects;i++) + { + if(!strcmp(sections[i].sectname,"__la_symbol_ptr")) + la_ptrs = §ions[i]; + else if(!strcmp(sections[i].sectname,"__nl_symbol_ptr")) + nl_ptrs = §ions[i]; + } + + indirectSyms = (unsigned long*) (image + dsymLC->indirectsymoff); + + if(la_ptrs) + if(!resolveImports(oc,image,symLC,la_ptrs,indirectSyms,nlist)) + return 0; + if(nl_ptrs) + if(!resolveImports(oc,image,symLC,nl_ptrs,indirectSyms,nlist)) + return 0; + + for(i=0;insects;i++) + { + if(!relocateSection(image,symLC,nlist,sections,§ions[i])) + return 0; + } + + /* Free the local symbol table; we won't need it again. */ + freeHashTable(oc->lochash, NULL); + oc->lochash = NULL; + return 1; +} + +/* + * The Mach-O object format uses leading underscores. But not everywhere. + * There is a small number of runtime support functions defined in + * libcc_dynamic.a whose name does not have a leading underscore. + * As a consequence, we can't get their address from C code. + * We have to use inline assembler just to take the address of a function. + * Yuck. + */ + +static void machoInitSymbolsWithoutUnderscore() +{ + void *p; + +#undef Sym +#define Sym(x) \ + __asm__ ("lis %0,hi16(" #x ")\n\tori %0,%0,lo16(" #x ")" : "=r" (p)); \ + ghciInsertStrHashTable("(GHCi built-in symbols)", symhash, #x, p); + + RTS_MACHO_NOUNDERLINE_SYMBOLS + +} +#endif