X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=ghc%2Frts%2FLinker.c;h=d9e2b91ce26bb83667d3b3011fec6b7e36ec515b;hb=7288088604bdec2d096ba11fd69571d27325d887;hp=4f2a456cccd0823b5bab34b713ba72122b31cba1;hpb=3cf7519556ab1b4c7aa49094a0a8d73f06828979;p=ghc-hetmet.git diff --git a/ghc/rts/Linker.c b/ghc/rts/Linker.c index 4f2a456..d9e2b91 100644 --- a/ghc/rts/Linker.c +++ b/ghc/rts/Linker.c @@ -1,5 +1,5 @@ /* ----------------------------------------------------------------------------- - * $Id: Linker.c,v 1.23 2001/02/12 12:22:01 simonmar Exp $ + * $Id: Linker.c,v 1.47 2001/06/28 14:26:58 sewardj Exp $ * * (c) The GHC Team, 2000 * @@ -29,9 +29,10 @@ #endif #if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS) || defined(freebsd_TARGET_OS) -#define OBJFORMAT_ELF +# define OBJFORMAT_ELF #elif defined(cygwin32_TARGET_OS) || defined (mingw32_TARGET_OS) -#define OBJFORMAT_PEi386 +# define OBJFORMAT_PEi386 +# include #endif /* Hash table mapping symbol names to Symbol */ @@ -51,6 +52,108 @@ static int ocResolve_PEi386 ( ObjectCode* oc ); * Built-in symbols from the RTS */ +typedef struct _RtsSymbolVal { + char *lbl; + void *addr; +} RtsSymbolVal; + + +#if !defined(PAR) +#define Maybe_ForeignObj SymX(mkForeignObjzh_fast) + +#define Maybe_Stable_Names SymX(mkWeakzh_fast) \ + SymX(makeStableNamezh_fast) \ + SymX(finalizzeWeakzh_fast) +#else +/* These are not available in GUM!!! -- HWL */ +#define Maybe_ForeignObj +#define Maybe_Stable_Names +#endif + +#if !defined (mingw32_TARGET_OS) + +#define RTS_POSIX_ONLY_SYMBOLS \ + SymX(stg_sig_install) \ + Sym(nocldstop) +#define RTS_MINGW_ONLY_SYMBOLS /**/ + +#else + +#define RTS_POSIX_ONLY_SYMBOLS + +/* 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(inet_ntoa) \ + SymX(inet_addr) \ + SymX(htonl) \ + SymX(recvfrom) \ + SymX(listen) \ + SymX(bind) \ + SymX(shutdown) \ + SymX(connect) \ + SymX(htons) \ + SymX(ntohs) \ + SymX(getservbyname) \ + SymX(getservbyport) \ + SymX(getprotobynumber) \ + SymX(getprotobyname) \ + SymX(gethostbyname) \ + SymX(gethostbyaddr) \ + SymX(gethostname) \ + SymX(strcpy) \ + SymX(strncpy) \ + SymX(abort) \ + Sym(_alloca) \ + Sym(isxdigit) \ + Sym(isupper) \ + Sym(ispunct) \ + Sym(islower) \ + Sym(isspace) \ + Sym(isprint) \ + Sym(isdigit) \ + Sym(iscntrl) \ + Sym(isalpha) \ + Sym(isalnum) \ + SymX(strcmp) \ + SymX(memmove) \ + SymX(realloc) \ + SymX(malloc) \ + SymX(pow) \ + SymX(tanh) \ + SymX(cosh) \ + SymX(sinh) \ + SymX(atan) \ + SymX(acos) \ + SymX(asin) \ + SymX(tan) \ + SymX(cos) \ + SymX(sin) \ + SymX(exp) \ + SymX(log) \ + SymX(sqrt) \ + SymX(memcpy) \ + Sym(mktime) \ + Sym(_imp___timezone) \ + Sym(_imp___tzname) \ + 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) \ + SymX(_errno) +#endif + + #define RTS_SYMBOLS \ SymX(MainRegTable) \ Sym(stg_gc_enter_1) \ @@ -60,12 +163,14 @@ static int ocResolve_PEi386 ( ObjectCode* oc ); 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) \ + SymX(stg_ap_1_upd_info) \ SymX(stg_ap_2_upd_info) \ SymX(stg_ap_3_upd_info) \ SymX(stg_ap_4_upd_info) \ @@ -105,6 +210,7 @@ static int ocResolve_PEi386 ( ObjectCode* oc ); SymX(newMVarzh_fast) \ SymX(takeMVarzh_fast) \ SymX(tryTakeMVarzh_fast) \ + SymX(tryPutMVarzh_fast) \ SymX(catchzh_fast) \ SymX(raisezh_fast) \ SymX(forkzh_fast) \ @@ -118,7 +224,7 @@ static int ocResolve_PEi386 ( ObjectCode* oc ); SymX(stackOverflow) \ SymX(int2Integerzh_fast) \ SymX(word2Integerzh_fast) \ - SymX(mkForeignObjzh_fast) \ + Maybe_ForeignObj \ SymX(__encodeDouble) \ SymX(decodeDoublezh_fast) \ SymX(decodeFloatzh_fast) \ @@ -139,9 +245,7 @@ static int ocResolve_PEi386 ( ObjectCode* oc ); SymX(orIntegerzh_fast) \ SymX(xorIntegerzh_fast) \ SymX(complementIntegerzh_fast) \ - SymX(mkWeakzh_fast) \ - SymX(makeStableNamezh_fast) \ - SymX(finalizzeWeakzh_fast) \ + Maybe_Stable_Names \ SymX(blockAsyncExceptionszh_fast) \ SymX(unblockAsyncExceptionszh_fast) \ SymX(isDoubleNaN) \ @@ -159,9 +263,12 @@ static int ocResolve_PEi386 ( ObjectCode* oc ); 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(resetNonBlockingFd) \ + SymX(performGC) \ SymX(getStablePtr) \ SymX(stable_ptr_table) \ SymX(shutdownHaskellAndExit) \ @@ -182,20 +289,47 @@ static int ocResolve_PEi386 ( ObjectCode* oc ); SymX(defaultsHook) \ SymX(PreTraceHook) \ SymX(PostTraceHook) \ - SymX(stg_sig_install) \ - Sym(nocldstop) \ 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_checkSchedStatus) \ - SymX(rts_getInt) + SymX(rts_evalLazyIO) \ + SymX(rts_checkSchedStatus) #ifndef SUPPORT_LONG_LONGS #define RTS_LONG_LONG_SYMS /* nothing */ #else -#define RTS_LONG_LONG_SYMS \ +#define RTS_LONG_LONG_SYMS \ SymX(stg_gtWord64) \ SymX(stg_geWord64) \ SymX(stg_eqWord64) \ @@ -239,6 +373,9 @@ static int ocResolve_PEi386 ( ObjectCode* oc ); #define Sym(vvv) extern void (vvv); #define SymX(vvv) /**/ RTS_SYMBOLS +RTS_LONG_LONG_SYMS +RTS_POSIX_ONLY_SYMBOLS +RTS_MINGW_ONLY_SYMBOLS #undef Sym #undef SymX @@ -252,30 +389,129 @@ RTS_SYMBOLS (void*)(&(vvv)) }, #define SymX(vvv) Sym(vvv) -static SymbolVal rtsSyms[] = { +static RtsSymbolVal rtsSyms[] = { RTS_SYMBOLS RTS_LONG_LONG_SYMS + RTS_POSIX_ONLY_SYMBOLS + RTS_MINGW_ONLY_SYMBOLS { 0, 0 } /* sentinel */ }; /* ----------------------------------------------------------------------------- * initialize the object linker */ +#if defined(OBJFORMAT_ELF) static void *dl_prog_handle; +#endif void initLinker( void ) { - SymbolVal *sym; + RtsSymbolVal *sym; symhash = allocStrHashTable(); /* populate the symbol table with stuff from the RTS */ for (sym = rtsSyms; sym->lbl != NULL; sym++) { - insertStrHashTable(symhash, sym->lbl, sym); + insertStrHashTable(symhash, sym->lbl, sym->addr); } - +# if defined(OBJFORMAT_ELF) dl_prog_handle = dlopen(NULL, RTLD_LAZY); +# endif +} + +/* ----------------------------------------------------------------------------- + * 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 -- + * lookupSymbol() will subsequently see them by dlsym on the program's + * dl-handle. Returns NULL if success, otherwise ptr to an err msg. + * + * 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. + */ + +#if defined(OBJFORMAT_PEi386) +/* A record for storing handles into DLLs. */ + +typedef + struct _OpenedDLL { + char* name; + struct _OpenedDLL* next; + HINSTANCE instance; + } + OpenedDLL; + +/* A list thereof. */ +static OpenedDLL* opened_dlls = NULL; +#endif + + + +char* +addDLL ( char* path, char* dll_name ) +{ +# if defined(OBJFORMAT_ELF) + void *hdl; + char *buf; + char *errmsg; + + if (path == NULL || strlen(path) == 0) { + buf = stgMallocBytes(strlen(dll_name) + 10, "addDll"); + sprintf(buf, "lib%s.so", dll_name); + } else { + buf = stgMallocBytes(strlen(path) + 1 + strlen(dll_name) + 10, "addDll"); + sprintf(buf, "%s/lib%s.so", path, dll_name); + } + hdl = dlopen(buf, RTLD_NOW | RTLD_GLOBAL ); + free(buf); + if (hdl == NULL) { + /* dlopen failed; return a ptr to the error msg. */ + errmsg = dlerror(); + if (errmsg == NULL) errmsg = "addDLL: unknown error"; + return errmsg; + } else { + return NULL; + } + /*NOTREACHED*/ + +# elif defined(OBJFORMAT_PEi386) + + /* 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); */ + + /* See if we've already got it, and ignore if so. */ + for (o_dll = opened_dlls; o_dll != NULL; o_dll = o_dll->next) { + if (0 == strcmp(o_dll->name, dll_name)) + return NULL; + } + + buf = stgMallocBytes(strlen(dll_name) + 10, "addDLL"); + sprintf(buf, "%s.DLL", dll_name); + instance = LoadLibrary(buf); + free(buf); + if (instance == NULL) { + /* LoadLibrary failed; return a ptr to the error msg. */ + return "addDLL: unknown error"; + } + + o_dll = stgMallocBytes( sizeof(OpenedDLL), "addDLL" ); + o_dll->name = stgMallocBytes(1+strlen(dll_name), "addDLL"); + strcpy(o_dll->name, dll_name); + o_dll->instance = instance; + o_dll->next = opened_dlls; + opened_dlls = o_dll; + + return NULL; +# else + barf("addDLL: not implemented on this platform"); +# endif } /* ----------------------------------------------------------------------------- @@ -284,17 +520,43 @@ initLinker( void ) void * lookupSymbol( char *lbl ) { - SymbolVal *val; + void *val; ASSERT(symhash != NULL); val = lookupStrHashTable(symhash, lbl); if (val == NULL) { +# if defined(OBJFORMAT_ELF) return dlsym(dl_prog_handle, lbl); +# elif defined(OBJFORMAT_PEi386) + 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); */ + sym = GetProcAddress(o_dll->instance, lbl); + if (sym != NULL) return sym; + } + return NULL; +# endif + } else { + return val; + } +} + +static +void * +lookupLocalSymbol( ObjectCode* oc, char *lbl ) +{ + void *val; + val = lookupStrHashTable(oc->lochash, lbl); + + if (val == NULL) { + return NULL; } else { - return val->addr; + return val; } } + /* ----------------------------------------------------------------------------- * Load an obj (populate the global symbol table, but don't resolve yet) * @@ -308,14 +570,15 @@ loadObj( char *path ) int r, n; FILE *f; -#ifdef DEBUG + /* fprintf(stderr, "loadObj %s\n", path ); */ +# ifdef DEBUG /* assert that we haven't already loaded this object */ { ObjectCode *o; for (o = objects; o; o = o->next) ASSERT(strcmp(o->fileName, path)); } -#endif /* DEBUG */ +# endif /* DEBUG */ oc = stgMallocBytes(sizeof(ObjectCode), "loadObj(oc)"); @@ -331,7 +594,7 @@ loadObj( char *path ) r = stat(path, &st); if (r == -1) { return 0; } - /* sigh, stdup() isn't a POSIX function, so do it the long way */ + /* sigh, strdup() isn't a POSIX function, so do it the long way */ oc->fileName = stgMallocBytes( strlen(path)+1, "loadObj" ); strcpy(oc->fileName, path); @@ -339,6 +602,7 @@ loadObj( char *path ) oc->image = stgMallocBytes( st.st_size, "loadObj(image)" ); oc->symbols = NULL; oc->sections = NULL; + oc->lochash = allocStrHashTable(); /* chain it onto the list of objects */ oc->next = objects; @@ -394,13 +658,13 @@ resolveObjs( void ) for (oc = objects; oc; oc = oc->next) { if (oc->status != OBJECT_RESOLVED) { -# if defined(OBJFORMAT_ELF) +# if defined(OBJFORMAT_ELF) r = ocResolve_ELF ( oc ); -# elif defined(OBJFORMAT_PEi386) +# elif defined(OBJFORMAT_PEi386) r = ocResolve_PEi386 ( oc ); -# else - barf("link: not implemented on this platform"); -# endif +# else + barf("resolveObjs: not implemented on this platform"); +# endif if (!r) { return r; } oc->status = OBJECT_RESOLVED; } @@ -427,13 +691,13 @@ unloadObj( char *path ) * object.. */ { - SymbolVal *s; - for (s = oc->symbols; s < oc->symbols + oc->n_symbols; s++) { - if (s->lbl != NULL) { - removeStrHashTable(symhash, s->lbl, NULL); - } - } - } + int i; + for (i = 0; i < oc->n_symbols; i++) { + if (oc->symbols[i] != NULL) { + removeStrHashTable(symhash, oc->symbols[i], NULL); + } + } + } if (prev == NULL) { objects = oc->next; @@ -447,6 +711,9 @@ unloadObj( char *path ) free(oc->fileName); free(oc->symbols); free(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); return 1; } @@ -537,26 +804,29 @@ typedef /* From PE spec doc, section 3.3.2 */ -#define IMAGE_FILE_RELOCS_STRIPPED 0x0001 -#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 -#define IMAGE_FILE_DLL 0x2000 -#define IMAGE_FILE_SYSTEM 0x1000 -#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 -#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 -#define IMAGE_FILE_32BIT_MACHINE 0x0100 +/* Note use of MYIMAGE_* since IMAGE_* are already defined in + windows.h -- for the same purpose, but I want to know what I'm + getting, here. */ +#define MYIMAGE_FILE_RELOCS_STRIPPED 0x0001 +#define MYIMAGE_FILE_EXECUTABLE_IMAGE 0x0002 +#define MYIMAGE_FILE_DLL 0x2000 +#define MYIMAGE_FILE_SYSTEM 0x1000 +#define MYIMAGE_FILE_BYTES_REVERSED_HI 0x8000 +#define MYIMAGE_FILE_BYTES_REVERSED_LO 0x0080 +#define MYIMAGE_FILE_32BIT_MACHINE 0x0100 /* From PE spec doc, section 5.4.2 and 5.4.4 */ -#define IMAGE_SYM_CLASS_EXTERNAL 2 -#define IMAGE_SYM_CLASS_STATIC 3 -#define IMAGE_SYM_UNDEFINED 0 +#define MYIMAGE_SYM_CLASS_EXTERNAL 2 +#define MYIMAGE_SYM_CLASS_STATIC 3 +#define MYIMAGE_SYM_UNDEFINED 0 /* From PE spec doc, section 4.1 */ -#define IMAGE_SCN_CNT_CODE 0x00000020 -#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 +#define MYIMAGE_SCN_CNT_CODE 0x00000020 +#define MYIMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 /* From PE spec doc, section 5.2.1 */ -#define IMAGE_REL_I386_DIR32 0x0006 -#define IMAGE_REL_I386_REL32 0x0014 +#define MYIMAGE_REL_I386_DIR32 0x0006 +#define MYIMAGE_REL_I386_REL32 0x0014 /* We use myindex to calculate array addresses, rather than @@ -568,7 +838,7 @@ typedef are just plain wrong. Sigh. */ static UChar * -myindex ( int scale, int index, void* base ) +myindex ( int scale, void* base, int index ) { return ((UChar*)base) + scale * index; @@ -629,11 +899,10 @@ cstring_from_COFF_symbol_name ( UChar* name, UChar* strtab ) /* The annoying case: 8 bytes. Copy into a temporary (which is never freed ...) */ - newstr = malloc(9); - if (newstr) { - strncpy(newstr,name,8); - newstr[8] = 0; - } + newstr = stgMallocBytes(9, "cstring_from_COFF_symbol_name"); + ASSERT(newstr); + strncpy(newstr,name,8); + newstr[8] = 0; return newstr; } @@ -655,7 +924,7 @@ findPEi386SectionCalled ( ObjectCode* oc, char* name ) UChar* n2; COFF_section* section_i = (COFF_section*) - myindex ( sizeof_COFF_section, i, sectab ); + myindex ( sizeof_COFF_section, sectab, i ); n1 = (UChar*) &(section_i->Name); n2 = name; if (n1[0]==n2[0] && n1[1]==n2[1] && n1[2]==n2[2] && @@ -671,14 +940,16 @@ findPEi386SectionCalled ( ObjectCode* oc, char* name ) static void zapTrailingAtSign ( UChar* sym ) { +# define my_isdigit(c) ((c) >= '0' && (c) <= '9') int i, j; if (sym[0] == 0) return; i = 0; while (sym[i] != 0) i++; i--; j = i; - while (j > 0 && isdigit(sym[j])) j--; + while (j > 0 && my_isdigit(sym[j])) j--; if (j > 0 && sym[j] == '@' && j != i) sym[j] = 0; +# undef my_isdigit } @@ -690,7 +961,7 @@ ocVerifyImage_PEi386 ( ObjectCode* oc ) COFF_section* sectab; COFF_symbol* symtab; UChar* strtab; - + /* fprintf(stderr, "\nLOADING %s\n", oc->fileName); */ hdr = (COFF_header*)(oc->image); sectab = (COFF_section*) ( ((UChar*)(oc->image)) @@ -700,33 +971,40 @@ ocVerifyImage_PEi386 ( ObjectCode* oc ) ((UChar*)(oc->image)) + hdr->PointerToSymbolTable ); - strtab = ((UChar*)(oc->image)) - + hdr->PointerToSymbolTable + strtab = ((UChar*)symtab) + hdr->NumberOfSymbols * sizeof_COFF_symbol; if (hdr->Machine != 0x14c) { - oc->errMsg("Not x86 PEi386"); - return FALSE; + belch("Not x86 PEi386"); + return 0; } if (hdr->SizeOfOptionalHeader != 0) { - oc->errMsg("PEi386 with nonempty optional header"); - return FALSE; + belch("PEi386 with nonempty optional header"); + return 0; + } + if ( /* (hdr->Characteristics & MYIMAGE_FILE_RELOCS_STRIPPED) || */ + (hdr->Characteristics & MYIMAGE_FILE_EXECUTABLE_IMAGE) || + (hdr->Characteristics & MYIMAGE_FILE_DLL) || + (hdr->Characteristics & MYIMAGE_FILE_SYSTEM) ) { + belch("Not a PEi386 object file"); + return 0; } - if ( /* (hdr->Characteristics & IMAGE_FILE_RELOCS_STRIPPED) || */ - (hdr->Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) || - (hdr->Characteristics & IMAGE_FILE_DLL) || - (hdr->Characteristics & IMAGE_FILE_SYSTEM) ) { - oc->errMsg("Not a PEi386 object file"); - return FALSE; + if ( (hdr->Characteristics & MYIMAGE_FILE_BYTES_REVERSED_HI) + /* || !(hdr->Characteristics & MYIMAGE_FILE_32BIT_MACHINE) */ ) { + belch("Invalid PEi386 word size or endiannness: %d", + (int)(hdr->Characteristics)); + return 0; } - if ( (hdr->Characteristics & IMAGE_FILE_BYTES_REVERSED_HI) || - !(hdr->Characteristics & IMAGE_FILE_32BIT_MACHINE) ) { - oc->errMsg("Invalid PEi386 word size or endiannness"); - return FALSE; + /* fprintf(stderr, "strtab size %d\n", * (UInt32*)strtab); */ + if (* (UInt32*)strtab > 510000) { + belch("PEi386 object has suspiciously large string table; > 64k relocs?"); + return 0; } - if (!verb) return TRUE; /* No further verification after this point; only debug printing. */ + i = 0; + IF_DEBUG(linker, i=1); + if (i == 0) return 1; fprintf ( stderr, "sectab offset = %d\n", ((UChar*)sectab) - ((UChar*)hdr) ); @@ -751,22 +1029,13 @@ ocVerifyImage_PEi386 ( ObjectCode* oc ) fprintf ( stderr, "characteristics: 0x%x\n", (UInt32)(hdr->Characteristics) ); - fprintf ( stderr, "\n" ); - fprintf ( stderr, "string table has size 0x%x\n", * (UInt32*)strtab ); - fprintf ( stderr, "---START of string table---\n"); - for (i = 4; i < *(UInt32*)strtab; i++) { - if (strtab[i] == 0) - fprintf ( stderr, "\n"); else - fprintf( stderr, "%c", strtab[i] ); - } - fprintf ( stderr, "--- END of string table---\n"); - + /* Print the section table. */ fprintf ( stderr, "\n" ); for (i = 0; i < hdr->NumberOfSections; i++) { COFF_reloc* reltab; COFF_section* sectab_i = (COFF_section*) - myindex ( sizeof_COFF_section, i, sectab ); + myindex ( sizeof_COFF_section, sectab, i ); fprintf ( stderr, "\n" "section %d\n" @@ -792,30 +1061,40 @@ ocVerifyImage_PEi386 ( ObjectCode* oc ) reltab = (COFF_reloc*) ( ((UChar*)(oc->image)) + sectab_i->PointerToRelocations ); + for (j = 0; j < sectab_i->NumberOfRelocations; j++) { COFF_symbol* sym; COFF_reloc* rel = (COFF_reloc*) - myindex ( sizeof_COFF_reloc, j, reltab ); + myindex ( sizeof_COFF_reloc, reltab, j ); fprintf ( stderr, " type 0x%-4x vaddr 0x%-8x name `", (UInt32)rel->Type, rel->VirtualAddress ); sym = (COFF_symbol*) - myindex ( sizeof_COFF_symbol, rel->SymbolTableIndex, symtab ); - printName ( sym->Name, strtab ); + myindex ( sizeof_COFF_symbol, symtab, rel->SymbolTableIndex ); + printName ( sym->Name, strtab -10 ); fprintf ( stderr, "'\n" ); } fprintf ( stderr, "\n" ); } + fprintf ( stderr, "\n" ); + fprintf ( stderr, "string table has size 0x%x\n", * (UInt32*)strtab ); + fprintf ( stderr, "---START of string table---\n"); + for (i = 4; i < *(Int32*)strtab; i++) { + if (strtab[i] == 0) + fprintf ( stderr, "\n"); else + fprintf( stderr, "%c", strtab[i] ); + } + fprintf ( stderr, "--- END of string table---\n"); fprintf ( stderr, "\n" ); i = 0; while (1) { COFF_symbol* symtab_i; - if (i >= hdr->NumberOfSymbols) break; + if (i >= (Int32)(hdr->NumberOfSymbols)) break; symtab_i = (COFF_symbol*) - myindex ( sizeof_COFF_symbol, i, symtab ); + myindex ( sizeof_COFF_symbol, symtab, i ); fprintf ( stderr, "symbol %d\n" " name `", @@ -840,8 +1119,7 @@ ocVerifyImage_PEi386 ( ObjectCode* oc ) } fprintf ( stderr, "\n" ); - - return TRUE; + return 1; } @@ -871,51 +1149,59 @@ ocGetNames_PEi386 ( ObjectCode* oc ) + hdr->NumberOfSymbols * sizeof_COFF_symbol; /* Copy exported symbols into the ObjectCode. */ + + oc->n_symbols = hdr->NumberOfSymbols; + oc->symbols = stgMallocBytes(oc->n_symbols * sizeof(char*), + "ocGetNames_PEi386(oc->symbols)"); + /* Call me paranoid; I don't care. */ + for (i = 0; i < oc->n_symbols; i++) + oc->symbols[i] = NULL; + i = 0; while (1) { COFF_symbol* symtab_i; - if (i >= hdr->NumberOfSymbols) break; + if (i >= (Int32)(hdr->NumberOfSymbols)) break; symtab_i = (COFF_symbol*) - myindex ( sizeof_COFF_symbol, i, symtab ); + myindex ( sizeof_COFF_symbol, symtab, i ); - if (symtab_i->StorageClass == IMAGE_SYM_CLASS_EXTERNAL && - symtab_i->SectionNumber != IMAGE_SYM_UNDEFINED) { + if (symtab_i->StorageClass == MYIMAGE_SYM_CLASS_EXTERNAL && + symtab_i->SectionNumber != MYIMAGE_SYM_UNDEFINED) { /* This symbol is global and defined, viz, exported */ COFF_section* sectabent; - sname = cstring_from_COFF_symbol_name ( - symtab_i->Name, strtab - ); - if (!sname) { - oc->errMsg("Out of memory when copying PEi386 symbol"); - return FALSE; - } + /* cstring_from_COFF_symbol_name always succeeds. */ + sname = cstring_from_COFF_symbol_name ( symtab_i->Name, strtab ); - /* for IMAGE_SYMCLASS_EXTERNAL - && !IMAGE_SYM_UNDEFINED, + /* for MYIMAGE_SYMCLASS_EXTERNAL + && !MYIMAGE_SYM_UNDEFINED, the address of the symbol is: address of relevant section + offset in section */ sectabent = (COFF_section*) myindex ( sizeof_COFF_section, - symtab_i->SectionNumber-1, - sectab ); + sectab, + symtab_i->SectionNumber-1 ); addr = ((UChar*)(oc->image)) + (sectabent->PointerToRawData + symtab_i->Value); - /* fprintf ( stderr, "addSymbol %p `%s'\n", addr,sname); */ - if (!addSymbol(oc,sname,addr)) return FALSE; + /* 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); + oc->symbols[i] = sname; + insertStrHashTable(symhash, sname, addr); } i += symtab_i->NumberOfAuxSymbols; i++; } - oc->sections = stgMallocBytes( NumberOfSections * sizeof(Section), - "ocGetNamesPEi386" ); - /* Copy section information into the ObjectCode. */ - for (i = 0; i < hdr->NumberOfSections; i++) { + + oc->n_sections = hdr->NumberOfSections; + oc->sections = stgMallocBytes( oc->n_sections * sizeof(Section), + "ocGetNamesPEi386" ); + + for (i = 0; i < oc->n_sections; i++) { UChar* start; UChar* end; @@ -923,16 +1209,16 @@ ocGetNames_PEi386 ( ObjectCode* oc ) = SECTIONKIND_OTHER; COFF_section* sectab_i = (COFF_section*) - myindex ( sizeof_COFF_section, i, sectab ); - /* fprintf ( stderr, "section name = %s\n", sectab_i->Name ); */ + myindex ( sizeof_COFF_section, sectab, i ); + IF_DEBUG(linker, belch("section name = %s\n", sectab_i->Name )); #if 0 /* I'm sure this is the Right Way to do it. However, the alternative of testing the sectab_i->Name field seems to work ok with Cygwin. */ - if (sectab_i->Characteristics & IMAGE_SCN_CNT_CODE || - sectab_i->Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) + if (sectab_i->Characteristics & MYIMAGE_SCN_CNT_CODE || + sectab_i->Characteristics & MYIMAGE_SCN_CNT_INITIALIZED_DATA) kind = SECTIONKIND_CODE_OR_RODATA; #endif @@ -947,22 +1233,22 @@ ocGetNames_PEi386 ( ObjectCode* oc ) end = start + sectab_i->SizeOfRawData - 1; - if (kind != SECTIONKIND_OTHER) { - addSection ( oc, start, end, kind ); - } else { - fprintf ( stderr, "unknown section name = `%s'\n", - sectab_i->Name); - oc->errMsg("Unknown PEi386 section name"); - return FALSE; + if (kind == SECTIONKIND_OTHER) { + belch("Unknown PEi386 section name `%s'", sectab_i->Name); + return 0; } + + oc->sections[i].start = start; + oc->sections[i].end = end; + oc->sections[i].kind = kind; } - return TRUE; + return 1; } static int -ocResolve_PEi386 ( ObjectCode* oc, int verb ) +ocResolve_PEi386 ( ObjectCode* oc ) { COFF_header* hdr; COFF_section* sectab; @@ -974,8 +1260,12 @@ ocResolve_PEi386 ( ObjectCode* oc, int verb ) UInt32* pP; int i, j; - char symbol[1000]; // ToDo - + + /* ToDo: should be variable-sized? But is at least safe in the + sense of buffer-overrun-proof. */ + char symbol[1000]; + /* fprintf(stderr, "resolving for %s\n", oc->fileName); */ + hdr = (COFF_header*)(oc->image); sectab = (COFF_section*) ( ((UChar*)(oc->image)) @@ -992,7 +1282,7 @@ ocResolve_PEi386 ( ObjectCode* oc, int verb ) for (i = 0; i < hdr->NumberOfSections; i++) { COFF_section* sectab_i = (COFF_section*) - myindex ( sizeof_COFF_section, i, sectab ); + myindex ( sizeof_COFF_section, sectab, i ); COFF_reloc* reltab = (COFF_reloc*) ( ((UChar*)(oc->image)) + sectab_i->PointerToRelocations @@ -1001,59 +1291,60 @@ ocResolve_PEi386 ( ObjectCode* oc, int verb ) COFF_symbol* sym; COFF_reloc* reltab_j = (COFF_reloc*) - myindex ( sizeof_COFF_reloc, j, reltab ); + myindex ( sizeof_COFF_reloc, reltab, j ); /* the location to patch */ pP = (UInt32*)( ((UChar*)(oc->image)) + (sectab_i->PointerToRawData - + reltab_j->VirtualAddress) + + reltab_j->VirtualAddress + - sectab_i->VirtualAddress ) ); /* the existing contents of pP */ A = *pP; /* the symbol to connect to */ sym = (COFF_symbol*) myindex ( sizeof_COFF_symbol, - reltab_j->SymbolTableIndex, symtab ); - if (verb) { - fprintf ( stderr, - "reloc sec %2d num %3d: type 0x%-4x " - "vaddr 0x%-8x name `", - i, j, - (UInt32)reltab_j->Type, - reltab_j->VirtualAddress ); - printName ( sym->Name, strtab ); - fprintf ( stderr, "'\n" ); - } - - if (sym->StorageClass == IMAGE_SYM_CLASS_STATIC) { + symtab, reltab_j->SymbolTableIndex ); + IF_DEBUG(linker, + fprintf ( stderr, + "reloc sec %2d num %3d: type 0x%-4x " + "vaddr 0x%-8x name `", + i, j, + (UInt32)reltab_j->Type, + reltab_j->VirtualAddress ); + printName ( sym->Name, strtab ); + fprintf ( stderr, "'\n" )); + + if (sym->StorageClass == MYIMAGE_SYM_CLASS_STATIC) { COFF_section* section_sym = findPEi386SectionCalled ( oc, sym->Name ); if (!section_sym) { fprintf ( stderr, "bad section = `%s'\n", sym->Name ); - oc->errMsg("Can't find abovementioned PEi386 section"); - return FALSE; + barf("Can't find abovementioned PEi386 section"); + return 0; } S = ((UInt32)(oc->image)) + (section_sym->PointerToRawData + sym->Value); } else { - copyName ( sym->Name, strtab, symbol, 1000 ); - zapTrailingAtSign ( symbol ); - S = (UInt32) ocLookupSym ( oc, symbol ); - if (S == 0) - S = (UInt32)(oc->clientLookup ( symbol )); - if (S == 0) { - belch("%s: unresolvable reference to `%s'", oc->fileName, symbol); - return FALSE; - } + copyName ( sym->Name, strtab, symbol, 1000-1 ); + zapTrailingAtSign ( symbol ); + (void*)S = lookupLocalSymbol( oc, symbol ); + if ((void*)S == NULL) + (void*)S = lookupSymbol( symbol ); + if (S == 0) { + belch("ocResolve_PEi386: %s: unknown symbol `%s'", + oc->fileName, symbol); + return 0; + } } switch (reltab_j->Type) { - case IMAGE_REL_I386_DIR32: + case MYIMAGE_REL_I386_DIR32: *pP = A + S; break; - case IMAGE_REL_I386_REL32: + case MYIMAGE_REL_I386_REL32: /* Tricky. We have to insert a displacement at pP which, when added to the PC for the _next_ insn, gives the address of the target (S). @@ -1072,14 +1363,15 @@ ocResolve_PEi386 ( ObjectCode* oc, int verb ) fprintf(stderr, "unhandled PEi386 relocation type %d\n", reltab_j->Type); - oc->errMsg("unhandled PEi386 relocation type"); - return FALSE; + barf("unhandled PEi386 relocation type"); + return 0; } } } - return TRUE; + /* fprintf(stderr, "completed %s\n", oc->fileName); */ + return 1; } #endif /* defined(OBJFORMAT_PEi386) */ @@ -1302,11 +1594,11 @@ ocGetNames_ELF ( ObjectCode* oc ) } k = 0; - oc->sections = stgMallocBytes( ehdr->e_shnum * sizeof(Section), - "ocGetNames_ELF" ); oc->n_sections = ehdr->e_shnum; + oc->sections = stgMallocBytes( oc->n_sections * sizeof(Section), + "ocGetNames_ELF(oc->sections)" ); - for (i = 0; i < ehdr->e_shnum; i++) { + for (i = 0; i < oc->n_sections; i++) { /* make a section entry for relevant sections */ SectionKind kind = SECTIONKIND_OTHER; @@ -1328,47 +1620,57 @@ ocGetNames_ELF ( ObjectCode* oc ) /* copy stuff into this module's object symbol table */ stab = (Elf32_Sym*) (ehdrC + shdr[i].sh_offset); nent = shdr[i].sh_size / sizeof(Elf32_Sym); - oc->symbols = malloc(nent * sizeof(SymbolVal)); + oc->n_symbols = nent; + oc->symbols = stgMallocBytes(oc->n_symbols * sizeof(char*), + "ocGetNames_ELF(oc->symbols)"); + for (j = 0; j < nent; j++) { if ( ( ELF32_ST_BIND(stab[j].st_info)==STB_GLOBAL - /* || ELF32_ST_BIND(stab[j].st_info)==STB_LOCAL */ + || ELF32_ST_BIND(stab[j].st_info)==STB_LOCAL ) - /* and not an undefined symbol */ - && stab[j].st_shndx != SHN_UNDEF - && + /* and not an undefined symbol */ + && stab[j].st_shndx != SHN_UNDEF + /* and not in a "special section" */ + && stab[j].st_shndx < SHN_LORESERVE + && /* and it's a not a section or string table or anything silly */ ( ELF32_ST_TYPE(stab[j].st_info)==STT_FUNC || ELF32_ST_TYPE(stab[j].st_info)==STT_OBJECT || - ELF32_ST_TYPE(stab[j].st_info)==STT_NOTYPE ) - ) { + ELF32_ST_TYPE(stab[j].st_info)==STT_NOTYPE + ) + ) { char* nm = strtab + stab[j].st_name; char* ad = ehdrC + shdr[ stab[j].st_shndx ].sh_offset + stab[j].st_value; ASSERT(nm != NULL); ASSERT(ad != NULL); - IF_DEBUG(linker,belch( "addOTabName: %10p %s %s", - ad, oc->fileName, nm )); - oc->symbols[j].lbl = nm; - oc->symbols[j].addr = ad; - insertStrHashTable(symhash, nm, &(oc->symbols[j])); + 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); + } else { + IF_DEBUG(linker,belch( "addOTabName(GLOB): %10p %s %s", + ad, oc->fileName, nm )); + insertStrHashTable(symhash, nm, ad); + } + } + else { + IF_DEBUG(linker,belch( "skipping `%s'", + strtab + stab[j].st_name )); + /* + fprintf(stderr, + "skipping bind = %d, type = %d, shndx = %d `%s'\n", + (int)ELF32_ST_BIND(stab[j].st_info), + (int)ELF32_ST_TYPE(stab[j].st_info), + (int)stab[j].st_shndx, + strtab + stab[j].st_name + ); + */ + oc->symbols[j] = NULL; } - else { - IF_DEBUG(linker,belch( "skipping `%s'", - strtab + stab[j].st_name )); - /* - fprintf(stderr, - "skipping bind = %d, type = %d, shndx = %d `%s'\n", - (int)ELF32_ST_BIND(stab[j].st_info), - (int)ELF32_ST_TYPE(stab[j].st_info), - (int)stab[j].st_shndx, - strtab + stab[j].st_name - ); - */ - oc->symbols[j].lbl = NULL; - oc->symbols[j].addr = NULL; - } } } @@ -1415,9 +1717,12 @@ static int do_Elf32_Rel_relocations ( ObjectCode* oc, char* ehdrC, (ehdrC + shdr[stab[ELF32_R_SYM(info)].st_shndx ].sh_offset + stab[ELF32_R_SYM(info)].st_value); } else { - /* No? Should be in the symbol table then. */ + /* No? Should be in a symbol table then; first try the + local one. */ symbol = strtab+stab[ ELF32_R_SYM(info)].st_name; - (void *)S = lookupSymbol( symbol ); + (void*)S = lookupLocalSymbol( oc, symbol ); + if ((void*)S == NULL) + (void*)S = lookupSymbol( symbol ); } if (!S) { barf("do_Elf32_Rel_relocations: %s: unknown symbol `%s'", @@ -1428,12 +1733,14 @@ static int do_Elf32_Rel_relocations ( ObjectCode* oc, char* ehdrC, IF_DEBUG(linker,belch( "Reloc: P = %p S = %p A = %p", (void*)P, (void*)S, (void*)A )); switch (ELF32_R_TYPE(info)) { -#ifdef i386_TARGET_ARCH +# ifdef i386_TARGET_ARCH case R_386_32: *pP = S + A; break; case R_386_PC32: *pP = S + A - P; break; -#endif +# endif default: - barf("do_Elf32_Rel_relocations: unhandled ELF relocation(Rel) type %d\n", ELF32_R_TYPE(info)); + fprintf(stderr, "unhandled ELF relocation(Rel) type %d\n", + ELF32_R_TYPE(info)); + barf("do_Elf32_Rel_relocations: unhandled ELF relocation type"); return 0; } @@ -1487,12 +1794,15 @@ static int do_Elf32_Rela_relocations ( ObjectCode* oc, char* ehdrC, (ehdrC + shdr[stab[ELF32_R_SYM(info)].st_shndx ].sh_offset + stab[ELF32_R_SYM(info)].st_value); } else { - /* No? Should be in the symbol table then. */ + /* No? Should be in a symbol table then; first try the + local one. */ symbol = strtab+stab[ ELF32_R_SYM(info)].st_name; - (void *)S = lookupSymbol( symbol ); + (void*)S = lookupLocalSymbol( oc, symbol ); + if ((void*)S == NULL) + (void*)S = lookupSymbol( symbol ); } if (!S) { - barf("ocResolve_ELF: %s: unknown symbol `%s'", + barf("do_Elf32_Rela_relocations: %s: unknown symbol `%s'", oc->fileName, symbol); /* S = 0x11223344; @@ -1530,9 +1840,6 @@ static int do_Elf32_Rela_relocations ( ObjectCode* oc, char* ehdrC, w2 = (Elf32_Word)(S + A); *pP = w2; break; - case R_SPARC_NONE: belch("R_SPARC_NONE"); - break; - # endif default: fprintf(stderr, "unhandled ELF relocation(RelA) type %d\n", @@ -1582,6 +1889,10 @@ ocResolve_ELF ( ObjectCode* oc ) } } + /* Free the local symbol table; we won't need it again. */ + freeHashTable(oc->lochash, NULL); + oc->lochash = NULL; + return 1; }