X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=ghc%2Frts%2FLinker.c;h=1d4711e9c4ef4f6080ea42e0e726fab51f0c9350;hb=2cc5b907318f97e19b28b2ad8ed9ff8c1f401dcc;hp=8a3d680d13e71c218464718e59b660e904a7cf82;hpb=243f2a5cd6f311048a07fdc20dbcd1e5e9655c47;p=ghc-hetmet.git diff --git a/ghc/rts/Linker.c b/ghc/rts/Linker.c index 8a3d680..1d4711e 100644 --- a/ghc/rts/Linker.c +++ b/ghc/rts/Linker.c @@ -1,5 +1,5 @@ /* ----------------------------------------------------------------------------- - * $Id: Linker.c,v 1.64 2001/09/04 16:49:12 sewardj Exp $ + * $Id: Linker.c,v 1.83 2002/02/12 15:17:22 simonmar Exp $ * * (c) The GHC Team, 2000, 2001 * @@ -16,6 +16,7 @@ #include "LinkerInternals.h" #include "RtsUtils.h" #include "StoragePriv.h" +#include "Schedule.h" #ifdef HAVE_SYS_TYPES_H #include @@ -141,42 +142,170 @@ typedef struct _RtsSymbolVal { Sym(_imp___iob) \ Sym(localtime) \ Sym(gmtime) \ - SymX(getenv) \ - SymX(free) \ - SymX(rename) \ Sym(opendir) \ Sym(readdir) \ Sym(closedir) \ - SymX(GetCurrentProcess) \ - SymX(GetProcessTimes) \ - SymX(CloseHandle) \ - SymX(GetExitCodeProcess) \ - SymX(WaitForSingleObject) \ - SymX(CreateProcessA) \ Sym(__divdi3) \ Sym(__udivdi3) \ Sym(__moddi3) \ - Sym(__umoddi3) \ - SymX(_errno) + Sym(__umoddi3) #endif +#ifndef SMP +# define MAIN_CAP_SYM SymX(MainCapability) +#else +# define MAIN_CAP_SYM +#endif #define RTS_SYMBOLS \ - SymX(MainRegTable) \ - Sym(stg_gc_enter_1) \ - Sym(stg_gc_noregs) \ - Sym(stg_gc_seq_1) \ - Sym(stg_gc_d1) \ - Sym(stg_gc_f1) \ - Sym(stg_gc_ut_1_0) \ - Sym(stg_gc_ut_0_1) \ - Sym(stg_gc_unpt_r1) \ - Sym(stg_gc_unbx_r1) \ - Sym(stg_chk_0) \ - Sym(stg_chk_1) \ - Sym(stg_gen_chk) \ - SymX(stg_exit) \ - SymX(stg_update_PAP) \ + Maybe_ForeignObj \ + Maybe_Stable_Names \ + Sym(StgReturn) \ + Sym(__stginit_GHCziPrim) \ + Sym(init_stack) \ + SymX(__stg_chk_0) \ + SymX(__stg_chk_1) \ + Sym(stg_enterStackTop) \ + SymX(stg_gc_d1) \ + SymX(stg_gc_l1) \ + SymX(__stg_gc_enter_1) \ + SymX(stg_gc_f1) \ + SymX(stg_gc_noregs) \ + SymX(stg_gc_seq_1) \ + SymX(stg_gc_unbx_r1) \ + SymX(stg_gc_unpt_r1) \ + SymX(stg_gc_ut_0_1) \ + SymX(stg_gc_ut_1_0) \ + SymX(stg_gen_chk) \ + SymX(stg_yield_to_interpreter) \ + SymX(ErrorHdrHook) \ + MAIN_CAP_SYM \ + SymX(MallocFailHook) \ + SymX(NoRunnableThreadsHook) \ + SymX(OnExitHook) \ + SymX(OutOfHeapHook) \ + SymX(PatErrorHdrHook) \ + SymX(PostTraceHook) \ + SymX(PreTraceHook) \ + SymX(StackOverflowHook) \ + SymX(__encodeDouble) \ + SymX(__encodeFloat) \ + SymX(__gmpn_gcd_1) \ + SymX(__gmpz_cmp) \ + SymX(__gmpz_cmp_si) \ + SymX(__gmpz_cmp_ui) \ + SymX(__gmpz_get_si) \ + SymX(__gmpz_get_ui) \ + SymX(__int_encodeDouble) \ + SymX(__int_encodeFloat) \ + SymX(andIntegerzh_fast) \ + SymX(blockAsyncExceptionszh_fast) \ + SymX(catchzh_fast) \ + SymX(cmp_thread) \ + SymX(complementIntegerzh_fast) \ + SymX(cmpIntegerzh_fast) \ + SymX(cmpIntegerIntzh_fast) \ + SymX(createAdjustor) \ + SymX(decodeDoublezh_fast) \ + SymX(decodeFloatzh_fast) \ + SymX(defaultsHook) \ + SymX(delayzh_fast) \ + SymX(deRefWeakzh_fast) \ + SymX(deRefStablePtrzh_fast) \ + SymX(divExactIntegerzh_fast) \ + SymX(divModIntegerzh_fast) \ + SymX(forkzh_fast) \ + SymX(freeHaskellFunctionPtr) \ + SymX(freeStablePtr) \ + SymX(gcdIntegerzh_fast) \ + SymX(gcdIntegerIntzh_fast) \ + SymX(gcdIntzh_fast) \ + SymX(getProgArgv) \ + SymX(getStablePtr) \ + SymX(int2Integerzh_fast) \ + SymX(integer2Intzh_fast) \ + SymX(integer2Wordzh_fast) \ + SymX(isDoubleDenormalized) \ + SymX(isDoubleInfinite) \ + SymX(isDoubleNaN) \ + SymX(isDoubleNegativeZero) \ + SymX(isEmptyMVarzh_fast) \ + SymX(isFloatDenormalized) \ + SymX(isFloatInfinite) \ + SymX(isFloatNaN) \ + SymX(isFloatNegativeZero) \ + SymX(killThreadzh_fast) \ + SymX(makeStablePtrzh_fast) \ + SymX(minusIntegerzh_fast) \ + SymX(mkApUpd0zh_fast) \ + SymX(myThreadIdzh_fast) \ + SymX(newArrayzh_fast) \ + SymX(newBCOzh_fast) \ + SymX(newByteArrayzh_fast) \ + SymX(newCAF) \ + SymX(newMVarzh_fast) \ + SymX(newMutVarzh_fast) \ + SymX(newPinnedByteArrayzh_fast) \ + SymX(orIntegerzh_fast) \ + SymX(performGC) \ + SymX(plusIntegerzh_fast) \ + SymX(prog_argc) \ + SymX(prog_argv) \ + SymX(putMVarzh_fast) \ + SymX(quotIntegerzh_fast) \ + SymX(quotRemIntegerzh_fast) \ + SymX(raisezh_fast) \ + SymX(remIntegerzh_fast) \ + SymX(resetNonBlockingFd) \ + SymX(resumeThread) \ + SymX(rts_apply) \ + SymX(rts_checkSchedStatus) \ + SymX(rts_eval) \ + SymX(rts_evalIO) \ + SymX(rts_evalLazyIO) \ + SymX(rts_eval_) \ + SymX(rts_getAddr) \ + SymX(rts_getBool) \ + SymX(rts_getChar) \ + SymX(rts_getDouble) \ + SymX(rts_getFloat) \ + SymX(rts_getInt) \ + SymX(rts_getInt32) \ + SymX(rts_getPtr) \ + SymX(rts_getStablePtr) \ + SymX(rts_getThreadId) \ + SymX(rts_getWord) \ + SymX(rts_getWord32) \ + SymX(rts_mkAddr) \ + SymX(rts_mkBool) \ + SymX(rts_mkChar) \ + SymX(rts_mkDouble) \ + SymX(rts_mkFloat) \ + SymX(rts_mkInt) \ + SymX(rts_mkInt16) \ + SymX(rts_mkInt32) \ + SymX(rts_mkInt64) \ + SymX(rts_mkInt8) \ + SymX(rts_mkPtr) \ + SymX(rts_mkStablePtr) \ + SymX(rts_mkString) \ + SymX(rts_mkWord) \ + SymX(rts_mkWord16) \ + SymX(rts_mkWord32) \ + SymX(rts_mkWord64) \ + SymX(rts_mkWord8) \ + SymX(run_queue_hd) \ + SymX(setProgArgv) \ + SymX(shutdownHaskellAndExit) \ + SymX(stable_ptr_table) \ + SymX(stackOverflow) \ + SymX(stg_CAF_BLACKHOLE_info) \ + SymX(stg_CHARLIKE_closure) \ + SymX(stg_EMPTY_MVAR_info) \ + SymX(stg_IND_STATIC_info) \ + SymX(stg_INTLIKE_closure) \ + SymX(stg_MUT_ARR_PTRS_FROZEN_info) \ + SymX(stg_WEAK_info) \ SymX(stg_ap_1_upd_info) \ SymX(stg_ap_2_upd_info) \ SymX(stg_ap_3_upd_info) \ @@ -185,7 +314,14 @@ typedef struct _RtsSymbolVal { SymX(stg_ap_6_upd_info) \ SymX(stg_ap_7_upd_info) \ SymX(stg_ap_8_upd_info) \ + SymX(stg_exit) \ SymX(stg_sel_0_upd_info) \ + SymX(stg_sel_10_upd_info) \ + SymX(stg_sel_11_upd_info) \ + SymX(stg_sel_12_upd_info) \ + SymX(stg_sel_13_upd_info) \ + SymX(stg_sel_14_upd_info) \ + SymX(stg_sel_15_upd_info) \ SymX(stg_sel_1_upd_info) \ SymX(stg_sel_2_upd_info) \ SymX(stg_sel_3_upd_info) \ @@ -195,146 +331,21 @@ typedef struct _RtsSymbolVal { SymX(stg_sel_7_upd_info) \ SymX(stg_sel_8_upd_info) \ SymX(stg_sel_9_upd_info) \ - SymX(stg_sel_10_upd_info) \ - SymX(stg_sel_11_upd_info) \ - SymX(stg_sel_12_upd_info) \ - SymX(stg_sel_13_upd_info) \ - SymX(stg_sel_14_upd_info) \ - SymX(stg_sel_15_upd_info) \ - SymX(stg_upd_frame_info) \ SymX(stg_seq_frame_info) \ - SymX(stg_CAF_BLACKHOLE_info) \ - SymX(stg_IND_STATIC_info) \ - SymX(stg_EMPTY_MVAR_info) \ - SymX(stg_MUT_ARR_PTRS_FROZEN_info) \ - SymX(stg_WEAK_info) \ - SymX(stg_CHARLIKE_closure) \ - SymX(stg_INTLIKE_closure) \ - SymX(newCAF) \ - SymX(newBCOzh_fast) \ - SymX(mkApUpd0zh_fast) \ - SymX(putMVarzh_fast) \ - SymX(newMVarzh_fast) \ + SymX(stg_upd_frame_info) \ + SymX(__stg_update_PAP) \ + SymX(suspendThread) \ SymX(takeMVarzh_fast) \ - SymX(tryTakeMVarzh_fast) \ + SymX(timesIntegerzh_fast) \ SymX(tryPutMVarzh_fast) \ - SymX(catchzh_fast) \ - SymX(raisezh_fast) \ - SymX(forkzh_fast) \ - SymX(delayzh_fast) \ - SymX(yieldzh_fast) \ - SymX(killThreadzh_fast) \ + SymX(tryTakeMVarzh_fast) \ + SymX(unblockAsyncExceptionszh_fast) \ + SymX(unsafeThawArrayzh_fast) \ SymX(waitReadzh_fast) \ SymX(waitWritezh_fast) \ - SymX(suspendThread) \ - SymX(resumeThread) \ - SymX(stackOverflow) \ - SymX(int2Integerzh_fast) \ SymX(word2Integerzh_fast) \ - Maybe_ForeignObj \ - SymX(__encodeDouble) \ - SymX(decodeDoublezh_fast) \ - SymX(decodeFloatzh_fast) \ - SymX(gcdIntegerzh_fast) \ - SymX(newArrayzh_fast) \ - SymX(unsafeThawArrayzh_fast) \ - SymX(newByteArrayzh_fast) \ - SymX(newPinnedByteArrayzh_fast) \ - SymX(newMutVarzh_fast) \ - SymX(quotRemIntegerzh_fast) \ - SymX(quotIntegerzh_fast) \ - SymX(remIntegerzh_fast) \ - SymX(divExactIntegerzh_fast) \ - SymX(divModIntegerzh_fast) \ - SymX(timesIntegerzh_fast) \ - SymX(minusIntegerzh_fast) \ - SymX(plusIntegerzh_fast) \ - SymX(andIntegerzh_fast) \ - SymX(orIntegerzh_fast) \ SymX(xorIntegerzh_fast) \ - SymX(complementIntegerzh_fast) \ - Maybe_Stable_Names \ - SymX(blockAsyncExceptionszh_fast) \ - SymX(unblockAsyncExceptionszh_fast) \ - SymX(isDoubleNaN) \ - SymX(isDoubleInfinite) \ - SymX(isDoubleDenormalized) \ - SymX(isDoubleNegativeZero) \ - SymX(__encodeFloat) \ - SymX(isFloatNaN) \ - SymX(isFloatInfinite) \ - SymX(isFloatDenormalized) \ - SymX(isFloatNegativeZero) \ - SymX(__int_encodeFloat) \ - SymX(__int_encodeDouble) \ - SymX(__gmpz_cmp_si) \ - SymX(__gmpz_cmp_ui) \ - SymX(__gmpz_cmp) \ - SymX(__gmpn_gcd_1) \ - SymX(__gmpz_get_si) \ - SymX(__gmpz_get_ui) \ - SymX(prog_argv) \ - SymX(prog_argc) \ - SymX(getProgArgv) \ - SymX(setProgArgv) \ - SymX(resetNonBlockingFd) \ - SymX(performGC) \ - SymX(getStablePtr) \ - SymX(stable_ptr_table) \ - SymX(shutdownHaskellAndExit) \ - Sym(stg_enterStackTop) \ - Sym(stg_yield_to_interpreter) \ - Sym(StgReturn) \ - Sym(init_stack) \ - SymX(cmp_thread) \ - Sym(__init_PrelGHC) \ - SymX(freeHaskellFunctionPtr) \ - SymX(OnExitHook) \ - SymX(ErrorHdrHook) \ - SymX(NoRunnableThreadsHook) \ - SymX(StackOverflowHook) \ - SymX(OutOfHeapHook) \ - SymX(MallocFailHook) \ - SymX(PatErrorHdrHook) \ - SymX(defaultsHook) \ - SymX(PreTraceHook) \ - SymX(PostTraceHook) \ - SymX(createAdjustor) \ - SymX(rts_mkChar) \ - SymX(rts_mkInt) \ - SymX(rts_mkInt8) \ - SymX(rts_mkInt16) \ - SymX(rts_mkInt32) \ - SymX(rts_mkInt64) \ - SymX(rts_mkWord) \ - SymX(rts_mkWord8) \ - SymX(rts_mkWord16) \ - SymX(rts_mkWord32) \ - SymX(rts_mkWord64) \ - SymX(rts_mkPtr) \ - SymX(rts_mkFloat) \ - SymX(rts_mkDouble) \ - SymX(rts_mkStablePtr) \ - SymX(rts_mkBool) \ - SymX(rts_mkString) \ - SymX(rts_apply) \ - SymX(rts_mkAddr) \ - SymX(rts_getChar) \ - SymX(rts_getInt) \ - SymX(rts_getInt32) \ - SymX(rts_getWord) \ - SymX(rts_getWord32) \ - SymX(rts_getPtr) \ - SymX(rts_getFloat) \ - SymX(rts_getDouble) \ - SymX(rts_getStablePtr) \ - SymX(rts_getBool) \ - SymX(rts_getAddr) \ - SymX(rts_eval) \ - SymX(rts_eval_) \ - SymX(rts_evalIO) \ - SymX(rts_evalLazyIO) \ - SymX(rts_checkSchedStatus) + SymX(yieldzh_fast) #ifndef SUPPORT_LONG_LONGS #define RTS_LONG_LONG_SYMS /* nothing */ @@ -373,6 +384,40 @@ static RtsSymbolVal rtsSyms[] = { }; /* ----------------------------------------------------------------------------- + * Insert symbols into hash tables, checking for duplicates. + */ +static void ghciInsertStrHashTable ( char* obj_name, + HashTable *table, + char* key, + void *data + ) +{ + if (lookupHashTable(table, (StgWord)key) == NULL) + { + insertStrHashTable(table, (StgWord)key, data); + return; + } + fprintf(stderr, + "\n\n" + "GHCi runtime linker: fatal error: I found a duplicate definition for symbol\n" + " %s\n" + "whilst processing object file\n" + " %s\n" + "This could be caused by:\n" + " * Loading two different object files which export the same symbol\n" + " * Specifying the same object file twice on the GHCi command line\n" + " * An incorrect `package.conf' entry, causing some object to be\n" + " loaded twice.\n" + "GHCi cannot safely continue in this situation. Exiting now. Sorry.\n" + "\n", + (char*)key, + obj_name + ); + exit(1); +} + + +/* ----------------------------------------------------------------------------- * initialize the object linker */ #if defined(OBJFORMAT_ELF) @@ -388,7 +433,8 @@ initLinker( void ) /* populate the symbol table with stuff from the RTS */ for (sym = rtsSyms; sym->lbl != NULL; sym++) { - insertStrHashTable(symhash, sym->lbl, sym->addr); + ghciInsertStrHashTable("(GHCi built-in symbols)", + symhash, sym->lbl, sym->addr); } # if defined(OBJFORMAT_ELF) dl_prog_handle = dlopen(NULL, RTLD_LAZY); @@ -506,7 +552,7 @@ lookupSymbol( char *lbl ) OpenedDLL* o_dll; void* sym; for (o_dll = opened_dlls; o_dll != NULL; o_dll = o_dll->next) { - /* fprintf(stderr, "look in %s for %s\n", o_dll->name, lbl); */ + /* fprintf(stderr, "look in %s for %s\n", o_dll->name, lbl); */ if (lbl[0] == '_') { /* HACK: if the name has an initial underscore, try stripping it off & look that up first. I've yet to verify whether there's @@ -514,10 +560,16 @@ lookupSymbol( char *lbl ) stripped off when mapping from import lib name to the DLL name. */ sym = GetProcAddress(o_dll->instance, (lbl+1)); - if (sym != NULL) return sym; + if (sym != NULL) { + /*fprintf(stderr, "found %s in %s\n", lbl+1,o_dll->name); fflush(stderr);*/ + return sym; + } } sym = GetProcAddress(o_dll->instance, lbl); - if (sym != NULL) return sym; + if (sym != NULL) { + /*fprintf(stderr, "found %s in %s\n", lbl,o_dll->name); fflush(stderr);*/ + return sym; + } } return NULL; # else @@ -530,6 +582,7 @@ lookupSymbol( char *lbl ) } static +__attribute((unused)) void * lookupLocalSymbol( ObjectCode* oc, char *lbl ) { @@ -545,6 +598,42 @@ lookupLocalSymbol( ObjectCode* oc, char *lbl ) /* ----------------------------------------------------------------------------- + * Debugging aid: look in GHCi's object symbol tables for symbols + * within DELTA bytes of the specified address, and show their names. + */ +#ifdef DEBUG +void ghci_enquire ( char* addr ); + +void ghci_enquire ( char* addr ) +{ + int i; + char* sym; + char* a; + const int DELTA = 64; + ObjectCode* oc; + 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); */ + a = NULL; + if (oc->lochash != NULL) + a = lookupStrHashTable(oc->lochash, sym); + if (a == NULL) + a = lookupStrHashTable(symhash, sym); + if (a == NULL) { + /* 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); + } + } + } +} +#endif + + +/* ----------------------------------------------------------------------------- * Load an obj (populate the global symbol table, but don't resolve yet) * * Returns: 1 if ok, 0 on error. @@ -558,14 +647,27 @@ loadObj( char *path ) FILE *f; /* fprintf(stderr, "loadObj %s\n", path ); */ -# ifdef DEBUG - /* assert that we haven't already loaded this object */ + + /* Check that we haven't already loaded this object. Don't give up + at this stage; ocGetNames_* will barf later. */ { ObjectCode *o; - for (o = objects; o; o = o->next) - ASSERT(strcmp(o->fileName, path)); + int is_dup = 0; + for (o = objects; o; o = o->next) { + if (0 == strcmp(o->fileName, path)) + is_dup = 1; + } + if (is_dup) { + fprintf(stderr, + "\n\n" + "GHCi runtime linker: warning: looks like you're trying to load the\n" + "same object file twice:\n" + " %s\n" + "GHCi will continue, but a duplicate-symbol error may shortly follow.\n" + "\n" + , path); + } } -# endif /* DEBUG */ oc = stgMallocBytes(sizeof(ObjectCode), "loadObj(oc)"); @@ -755,6 +857,10 @@ static void addSection ( ObjectCode* oc, SectionKind kind, s->kind = kind; s->next = oc->sections; oc->sections = s; + /* + fprintf(stderr, "addSection: %p-%p (size %d), kind %d\n", + start, ((char*)end)-1, end - start + 1, kind ); + */ } @@ -768,6 +874,33 @@ static void addSection ( ObjectCode* oc, SectionKind kind, and Common Object File Format Specification revision 5.1 January 1998 which SimonM says comes from the MS Developer Network CDs. + + It can be found there (on older CDs), but can also be found + online at: + + http://www.microsoft.com/hwdev/hardware/PECOFF.asp + + (this is Rev 6.0 from February 1999). + + Things move, so if that fails, try searching for it via + + http://www.google.com/search?q=PE+COFF+specification + + The ultimate reference for the PE format is the Winnt.h + header file that comes with the Platform SDKs; as always, + implementations will drift wrt their documentation. + + A good background article on the PE format is Matt Pietrek's + March 1994 article in Microsoft System Journal (MSJ) + (Vol.9, No. 3): "Peering Inside the PE: A Tour of the + Win32 Portable Executable File Format." The info in there + has recently been updated in a two part article in + MSDN magazine, issues Feb and March 2002, + "Inside Windows: An In-Depth Look into the Win32 Portable + Executable File Format" + + John Levine's book "Linkers and Loaders" contains useful + info on PE too. */ @@ -859,6 +992,7 @@ typedef /* From PE spec doc, section 4.1 */ #define MYIMAGE_SCN_CNT_CODE 0x00000020 #define MYIMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 +#define MYIMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 /* From PE spec doc, section 5.2.1 */ #define MYIMAGE_REL_I386_DIR32 0x0006 @@ -992,7 +1126,8 @@ zapTrailingAtSign ( UChar* sym ) static int ocVerifyImage_PEi386 ( ObjectCode* oc ) { - int i, j; + int i; + UInt32 j, noRelocs; COFF_header* hdr; COFF_section* sectab; COFF_symbol* symtab; @@ -1035,13 +1170,15 @@ ocVerifyImage_PEi386 ( ObjectCode* oc ) there are more than 64k relocations, despite claims to the contrary. Hence this test. */ /* fprintf(stderr, "strtab size %d\n", * (UInt32*)strtab); */ - if (* (UInt32*)strtab > 600000) { +#if 0 + if ( (*(UInt32*)strtab) > 600000 ) { /* Note that 600k has no special significance other than being big enough to handle the almost-2MB-sized lumps that constitute HSwin32*.o. */ belch("PEi386 object has suspiciously large string table; > 64k relocs?"); return 0; } +#endif /* No further verification after this point; only debug printing. */ i = 0; @@ -1105,8 +1242,23 @@ ocVerifyImage_PEi386 ( ObjectCode* oc ) reltab = (COFF_reloc*) ( ((UChar*)(oc->image)) + sectab_i->PointerToRelocations ); + + if ( sectab_i->Characteristics & MYIMAGE_SCN_LNK_NRELOC_OVFL ) { + /* If the relocation field (a short) has overflowed, the + * real count can be found in the first reloc entry. + * + * See Section 4.1 (last para) of the PE spec (rev6.0). + */ + COFF_reloc* rel = (COFF_reloc*) + myindex ( sizeof_COFF_reloc, reltab, 0 ); + noRelocs = rel->VirtualAddress; + j = 1; + } else { + noRelocs = sectab_i->NumberOfRelocations; + j = 0; + } - for (j = 0; j < sectab_i->NumberOfRelocations; j++) { + for (; j < noRelocs; j++) { COFF_symbol* sym; COFF_reloc* rel = (COFF_reloc*) myindex ( sizeof_COFF_reloc, reltab, j ); @@ -1116,6 +1268,7 @@ ocVerifyImage_PEi386 ( ObjectCode* oc ) rel->VirtualAddress ); sym = (COFF_symbol*) myindex ( sizeof_COFF_symbol, symtab, rel->SymbolTableIndex ); + /* Hmm..mysterious looking offset - what's it for? SOF */ printName ( sym->Name, strtab -10 ); fprintf ( stderr, "'\n" ); } @@ -1249,12 +1402,17 @@ ocGetNames_PEi386 ( ObjectCode* oc ) start = ((UChar*)(oc->image)) + sectab_i->PointerToRawData; end = start + sz - 1; - if (kind == SECTIONKIND_OTHER) { + if (kind == SECTIONKIND_OTHER + /* Ignore sections called which contain stabs debugging + information. */ + && 0 != strcmp(".stab", sectab_i->Name) + && 0 != strcmp(".stabstr", sectab_i->Name) + ) { belch("Unknown PEi386 section name `%s'", sectab_i->Name); return 0; } - if (end >= start) { + if (kind != SECTIONKIND_OTHER && end >= start) { addSection(oc, kind, start, end); addProddableBlock(oc, start, end - start + 1); } @@ -1307,14 +1465,14 @@ ocGetNames_PEi386 ( ObjectCode* oc ) /* fprintf(stderr, "BSS section at 0x%x\n", addr); */ } - if (addr != NULL) { + if (addr != NULL ) { sname = cstring_from_COFF_symbol_name ( symtab_i->Name, strtab ); - /* fprintf(stderr,"addSymbol %p `%s'\n", addr,sname); */ + /* fprintf(stderr,"addSymbol %p `%s \n", addr,sname); */ IF_DEBUG(linker, belch("addSymbol %p `%s'\n", addr,sname);) ASSERT(i >= 0 && i < oc->n_symbols); /* cstring_from_COFF_symbol_name always succeeds. */ oc->symbols[i] = sname; - insertStrHashTable(symhash, sname, addr); + ghciInsertStrHashTable(oc->fileName, symhash, sname, addr); } else { # if 0 fprintf ( stderr, @@ -1359,7 +1517,8 @@ ocResolve_PEi386 ( ObjectCode* oc ) UInt32 S; UInt32* pP; - int i, j; + int i; + UInt32 j, noRelocs; /* ToDo: should be variable-sized? But is at least safe in the sense of buffer-overrun-proof. */ @@ -1387,7 +1546,31 @@ ocResolve_PEi386 ( ObjectCode* oc ) = (COFF_reloc*) ( ((UChar*)(oc->image)) + sectab_i->PointerToRelocations ); - for (j = 0; j < sectab_i->NumberOfRelocations; j++) { + + /* Ignore sections called which contain stabs debugging + information. */ + if (0 == strcmp(".stab", sectab_i->Name) + || 0 == strcmp(".stabstr", sectab_i->Name)) + continue; + + if ( sectab_i->Characteristics & MYIMAGE_SCN_LNK_NRELOC_OVFL ) { + /* If the relocation field (a short) has overflowed, the + * real count can be found in the first reloc entry. + * + * See Section 4.1 (last para) of the PE spec (rev6.0). + */ + COFF_reloc* rel = (COFF_reloc*) + myindex ( sizeof_COFF_reloc, reltab, 0 ); + noRelocs = rel->VirtualAddress; + fprintf(stderr, "Overflown relocs: %u\n", noRelocs); + j = 1; + } else { + noRelocs = sectab_i->NumberOfRelocations; + j = 0; + } + + + for (; j < noRelocs; j++) { COFF_symbol* sym; COFF_reloc* reltab_j = (COFF_reloc*) @@ -1496,18 +1679,25 @@ ocResolve_PEi386 ( ObjectCode* oc ) */ #include +#include static char * findElfSection ( void* objImage, Elf32_Word sh_type ) { int i; char* ehdrC = (char*)objImage; - Elf32_Ehdr* ehdr = ( Elf32_Ehdr*)ehdrC; - Elf32_Shdr* shdr = (Elf32_Shdr*) (ehdrC + ehdr->e_shoff); + Elf32_Ehdr* ehdr = (Elf32_Ehdr*)ehdrC; + Elf32_Shdr* shdr = (Elf32_Shdr*)(ehdrC + ehdr->e_shoff); + char* sh_strtab = ehdrC + shdr[ehdr->e_shstrndx].sh_offset; char* ptr = NULL; for (i = 0; i < ehdr->e_shnum; i++) { - if (shdr[i].sh_type == sh_type && - i != ehdr->e_shstrndx) { + if (shdr[i].sh_type == sh_type + /* Ignore the section header's string table. */ + && i != ehdr->e_shstrndx + /* Ignore string tables named .stabstr, as they contain + debugging info. */ + && 0 != strncmp(".stabstr", sh_strtab + shdr[i].sh_name, 8) + ) { ptr = ehdrC + shdr[i].sh_offset; break; } @@ -1611,9 +1801,14 @@ ocVerifyImage_ELF ( ObjectCode* oc ) strtab = NULL; nstrtab = 0; for (i = 0; i < ehdr->e_shnum; i++) { - if (shdr[i].sh_type == SHT_STRTAB && - i != ehdr->e_shstrndx) { - IF_DEBUG(linker,belch(" section %d is a normal string table", i )); + if (shdr[i].sh_type == SHT_STRTAB + /* Ignore the section header's string table. */ + && i != ehdr->e_shstrndx + /* Ignore string tables named .stabstr, as they contain + debugging info. */ + && 0 != strncmp(".stabstr", sh_strtab + shdr[i].sh_name, 8) + ) { + IF_DEBUG(linker,belch(" section %d is a normal string table", i )); strtab = ehdrC + shdr[i].sh_offset; nstrtab++; } @@ -1689,7 +1884,6 @@ ocGetNames_ELF ( ObjectCode* oc ) Elf32_Ehdr* ehdr = (Elf32_Ehdr*)ehdrC; char* strtab = findElfSection ( ehdrC, SHT_STRTAB ); Elf32_Shdr* shdr = (Elf32_Shdr*) (ehdrC + ehdr->e_shoff); - char* sh_strtab = ehdrC + shdr[ehdr->e_shstrndx].sh_offset; ASSERT(symhash != NULL); @@ -1700,36 +1894,57 @@ ocGetNames_ELF ( ObjectCode* oc ) k = 0; for (i = 0; i < ehdr->e_shnum; i++) { + /* Figure out what kind of section it is. Logic derived from + Figure 1.14 ("Special Sections") of the ELF document + ("Portable Formats Specification, Version 1.1"). */ + Elf32_Shdr hdr = shdr[i]; + SectionKind kind = SECTIONKIND_OTHER; + int is_bss = FALSE; + + if (hdr.sh_type == SHT_PROGBITS + && (hdr.sh_flags & SHF_ALLOC) && (hdr.sh_flags & SHF_EXECINSTR)) { + /* .text-style section */ + kind = SECTIONKIND_CODE_OR_RODATA; + } + else + if (hdr.sh_type == SHT_PROGBITS + && (hdr.sh_flags & SHF_ALLOC) && (hdr.sh_flags & SHF_WRITE)) { + /* .data-style section */ + kind = SECTIONKIND_RWDATA; + } + else + if (hdr.sh_type == SHT_PROGBITS + && (hdr.sh_flags & SHF_ALLOC) && !(hdr.sh_flags & SHF_WRITE)) { + /* .rodata-style section */ + kind = SECTIONKIND_CODE_OR_RODATA; + } + else + if (hdr.sh_type == SHT_NOBITS + && (hdr.sh_flags & SHF_ALLOC) && (hdr.sh_flags & SHF_WRITE)) { + /* .bss-style section */ + kind = SECTIONKIND_RWDATA; + is_bss = TRUE; + } - /* make a section entry for relevant sections */ - SectionKind kind = SECTIONKIND_OTHER; - if (!strcmp(".data",sh_strtab+shdr[i].sh_name) || - !strcmp(".data1",sh_strtab+shdr[i].sh_name) || - !strcmp(".bss",sh_strtab+shdr[i].sh_name)) - kind = SECTIONKIND_RWDATA; - if (!strcmp(".text",sh_strtab+shdr[i].sh_name) || - !strcmp(".rodata",sh_strtab+shdr[i].sh_name) || - !strcmp(".rodata1",sh_strtab+shdr[i].sh_name)) - kind = SECTIONKIND_CODE_OR_RODATA; - - if (!strcmp(".bss",sh_strtab+shdr[i].sh_name) && shdr[i].sh_size > 0) { + if (is_bss && shdr[i].sh_size > 0) { /* This is a non-empty .bss section. Allocate zeroed space for it, and set its .sh_offset field such that ehdrC + .sh_offset == addr_of_zeroed_space. */ char* zspace = stgCallocBytes(1, shdr[i].sh_size, - "ocGetNames_ELF(anonymous bss)"); + "ocGetNames_ELF(BSS)"); shdr[i].sh_offset = ((char*)zspace) - ((char*)ehdrC); - /* + /* fprintf(stderr, "BSS section at 0x%x, size %d\n", zspace, shdr[i].sh_size); - */ + */ } /* fill in the section info */ - addSection(oc, kind, ehdrC + shdr[i].sh_offset, - ehdrC + shdr[i].sh_offset + shdr[i].sh_size - 1); - if (kind != SECTIONKIND_OTHER && shdr[i].sh_size > 0) + if (kind != SECTIONKIND_OTHER && shdr[i].sh_size > 0) { addProddableBlock(oc, ehdrC + shdr[i].sh_offset, shdr[i].sh_size); + addSection(oc, kind, ehdrC + shdr[i].sh_offset, + ehdrC + shdr[i].sh_offset + shdr[i].sh_size - 1); + } if (shdr[i].sh_type != SHT_SYMTAB) continue; @@ -1742,6 +1957,26 @@ ocGetNames_ELF ( ObjectCode* oc ) "ocGetNames_ELF(oc->symbols)"); for (j = 0; j < nent; j++) { + + char isLocal = FALSE; /* avoids uninit-var warning */ + char* ad = NULL; + char* nm = strtab + stab[j].st_name; + int secno = stab[j].st_shndx; + + /* Figure out if we want to add it; if so, set ad to its + address. Otherwise leave ad == NULL. */ + + if (secno == SHN_COMMON) { + isLocal = FALSE; + ad = stgCallocBytes(1, stab[j].st_size, "ocGetNames_ELF(COMMON)"); + /* + fprintf(stderr, "COMMON symbol, size %d name %s\n", + stab[j].st_size, nm); + */ + /* Pointless to do addProddableBlock() for this area, + since the linker should never poke around in it. */ + } + else if ( ( ELF32_ST_BIND(stab[j].st_info)==STB_GLOBAL || ELF32_ST_BIND(stab[j].st_info)==STB_LOCAL ) @@ -1756,33 +1991,37 @@ ocGetNames_ELF ( ObjectCode* oc ) ELF32_ST_TYPE(stab[j].st_info)==STT_NOTYPE ) ) { - char* nm; - char* ad; - int secno = stab[j].st_shndx; /* Section 0 is the undefined section, hence > and not >=. */ ASSERT(secno > 0 && secno < ehdr->e_shnum); - nm = strtab + stab[j].st_name; - /* + /* if (shdr[secno].sh_type == SHT_NOBITS) { - fprintf(stderr, "bss symbol, size %d off %d name %s\n", - stab[j].st_size, stab[j].st_value, nm); + fprintf(stderr, " BSS symbol, size %d off %d name %s\n", + stab[j].st_size, stab[j].st_value, nm); } */ ad = ehdrC + shdr[ secno ].sh_offset + stab[j].st_value; - ASSERT(nm != NULL); - ASSERT(ad != NULL); - oc->symbols[j] = nm; if (ELF32_ST_BIND(stab[j].st_info)==STB_LOCAL) { - IF_DEBUG(linker,belch( "addOTabName(LOCL): %10p %s %s", - ad, oc->fileName, nm )); - insertStrHashTable(oc->lochash, nm, ad); + isLocal = TRUE; } else { IF_DEBUG(linker,belch( "addOTabName(GLOB): %10p %s %s", ad, oc->fileName, nm )); - insertStrHashTable(symhash, nm, ad); + isLocal = FALSE; } } - else { + + /* And the decision is ... */ + + if (ad != NULL) { + ASSERT(nm != NULL); + oc->symbols[j] = nm; + /* Acquire! */ + if (isLocal) { + /* Ignore entirely. */ + } else { + ghciInsertStrHashTable(oc->fileName, symhash, nm, ad); + } + } else { + /* Skip. */ IF_DEBUG(linker,belch( "skipping `%s'", strtab + stab[j].st_name )); /* @@ -1796,6 +2035,7 @@ ocGetNames_ELF ( ObjectCode* oc ) */ oc->symbols[j] = NULL; } + } } @@ -1836,20 +2076,21 @@ do_Elf32_Rel_relocations ( ObjectCode* oc, char* ehdrC, IF_DEBUG(linker,belch( " ZERO" )); S = 0; } else { - /* First see if it is a nameless local symbol. */ - if (stab[ ELF32_R_SYM(info)].st_name == 0) { - symbol = "(noname)"; + Elf32_Sym sym = stab[ELF32_R_SYM(info)]; + /* First see if it is a local symbol. */ + if (ELF32_ST_BIND(sym.st_info) == STB_LOCAL) { + /* Yes, so we can get the address directly from the ELF symbol + table. */ + symbol = sym.st_name==0 ? "(noname)" : strtab+sym.st_name; S = (Elf32_Addr) - (ehdrC + shdr[stab[ELF32_R_SYM(info)].st_shndx ].sh_offset + (ehdrC + shdr[ sym.st_shndx ].sh_offset + stab[ELF32_R_SYM(info)].st_value); - } else { - /* No? Should be in a symbol table then; first try the - local one. */ - symbol = strtab+stab[ ELF32_R_SYM(info)].st_name; - (void*)S = lookupLocalSymbol( oc, symbol ); - if ((void*)S == NULL) - (void*)S = lookupSymbol( symbol ); - } + + } else { + /* No, so look up the name in our global table. */ + symbol = strtab + sym.st_name; + (void*)S = lookupSymbol( symbol ); + } if (!S) { belch("%s: unknown symbol `%s'", oc->fileName, symbol); return 0; @@ -1896,12 +2137,12 @@ do_Elf32_Rela_relocations ( ObjectCode* oc, char* ehdrC, for (j = 0; j < nent; j++) { Elf32_Addr offset = rtab[j].r_offset; Elf32_Word info = rtab[j].r_info; + Elf32_Sword addend = rtab[j].r_addend; Elf32_Addr P = ((Elf32_Addr)targ) + offset; + Elf32_Addr A = addend; /* Do not delete this; it is used on sparc. */ Elf32_Addr S; # if defined(sparc_TARGET_ARCH) /* This #ifdef only serves to avoid unused-var warnings. */ - Elf32_Sword addend = rtab[j].r_addend; - Elf32_Addr A = addend; Elf32_Word* pP = (Elf32_Word*)P; Elf32_Word w1, w2; # endif @@ -1913,20 +2154,21 @@ do_Elf32_Rela_relocations ( ObjectCode* oc, char* ehdrC, IF_DEBUG(linker,belch( " ZERO" )); S = 0; } else { - /* First see if it is a nameless local symbol. */ - if (stab[ ELF32_R_SYM(info)].st_name == 0) { - symbol = "(noname)"; + Elf32_Sym sym = stab[ELF32_R_SYM(info)]; + /* First see if it is a local symbol. */ + if (ELF32_ST_BIND(sym.st_info) == STB_LOCAL) { + /* Yes, so we can get the address directly from the ELF symbol + table. */ + symbol = sym.st_name==0 ? "(noname)" : strtab+sym.st_name; S = (Elf32_Addr) - (ehdrC + shdr[stab[ELF32_R_SYM(info)].st_shndx ].sh_offset + (ehdrC + shdr[ sym.st_shndx ].sh_offset + stab[ELF32_R_SYM(info)].st_value); - } else { - /* No? Should be in a symbol table then; first try the - local one. */ - symbol = strtab+stab[ ELF32_R_SYM(info)].st_name; - (void*)S = lookupLocalSymbol( oc, symbol ); - if ((void*)S == NULL) - (void*)S = lookupSymbol( symbol ); - } + + } else { + /* No, so look up the name in our global table. */ + symbol = strtab + sym.st_name; + (void*)S = lookupSymbol( symbol ); + } if (!S) { belch("%s: unknown symbol `%s'", oc->fileName, symbol); return 0; @@ -1999,6 +2241,7 @@ ocResolve_ELF ( ObjectCode* oc ) char* ehdrC = (char*)(oc->image); Elf32_Ehdr* ehdr = (Elf32_Ehdr*) ehdrC; Elf32_Shdr* shdr = (Elf32_Shdr*) (ehdrC + ehdr->e_shoff); + char* sh_strtab = ehdrC + shdr[ehdr->e_shstrndx].sh_offset; /* first find "the" symbol table */ stab = (Elf32_Sym*) findElfSection ( ehdrC, SHT_SYMTAB ); @@ -2013,6 +2256,14 @@ ocResolve_ELF ( ObjectCode* oc ) /* Process the relocation sections. */ for (shnum = 0; shnum < ehdr->e_shnum; shnum++) { + + /* Skip sections called ".rel.stab". These appear to contain + relocation entries that, when done, make the stabs debugging + info point at the right places. We ain't interested in all + dat jazz, mun. */ + if (0 == strncmp(".rel.stab", sh_strtab + shdr[shnum].sh_name, 9)) + continue; + if (shdr[shnum].sh_type == SHT_REL ) { ok = do_Elf32_Rel_relocations ( oc, ehdrC, shdr, shnum, stab, strtab ); @@ -2024,6 +2275,7 @@ ocResolve_ELF ( ObjectCode* oc ) shnum, stab, strtab ); if (!ok) return ok; } + } /* Free the local symbol table; we won't need it again. */