X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=ghc%2Frts%2FLinker.c;h=d9e2b91ce26bb83667d3b3011fec6b7e36ec515b;hb=7288088604bdec2d096ba11fd69571d27325d887;hp=12febd0642207fc9c30923d8de4ddd95996ef3b5;hpb=e610e61620c42dd7ea2ee6278888bc659d1909ad;p=ghc-hetmet.git diff --git a/ghc/rts/Linker.c b/ghc/rts/Linker.c index 12febd0..d9e2b91 100644 --- a/ghc/rts/Linker.c +++ b/ghc/rts/Linker.c @@ -1,5 +1,5 @@ /* ----------------------------------------------------------------------------- - * $Id: Linker.c,v 1.38 2001/04/24 11:20:50 sewardj Exp $ + * $Id: Linker.c,v 1.47 2001/06/28 14:26:58 sewardj Exp $ * * (c) The GHC Team, 2000 * @@ -32,6 +32,7 @@ # define OBJFORMAT_ELF #elif defined(cygwin32_TARGET_OS) || defined (mingw32_TARGET_OS) # define OBJFORMAT_PEi386 +# include #endif /* Hash table mapping symbol names to Symbol */ @@ -70,13 +71,89 @@ typedef struct _RtsSymbolVal { #endif #if !defined (mingw32_TARGET_OS) -#define RTS_POSIX_ONLY_SYMBOLS \ + +#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) \ @@ -86,6 +163,7 @@ typedef struct _RtsSymbolVal { 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) \ @@ -251,7 +329,7 @@ typedef struct _RtsSymbolVal { #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) \ @@ -295,6 +373,9 @@ typedef struct _RtsSymbolVal { #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 @@ -312,6 +393,7 @@ static RtsSymbolVal rtsSyms[] = { RTS_SYMBOLS RTS_LONG_LONG_SYMS RTS_POSIX_ONLY_SYMBOLS + RTS_MINGW_ONLY_SYMBOLS { 0, 0 } /* sentinel */ }; @@ -343,18 +425,45 @@ initLinker( void ) * 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 0 if fail, 1 if success. + * 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* dll_name ) +addDLL ( char* path, char* dll_name ) { # if defined(OBJFORMAT_ELF) void *hdl; char *buf; char *errmsg; - buf = stgMallocBytes(strlen(dll_name) + 10, "addDll"); - sprintf(buf, "lib%s.so", dll_name); + 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) { @@ -365,10 +474,41 @@ addDLL ( char* dll_name ) } else { return NULL; } - ASSERT(0); /*NOTREACHED*/ + /*NOTREACHED*/ + # elif defined(OBJFORMAT_PEi386) - barf("addDLL: not implemented on PEi386 yet"); - return 0; + + /* 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 @@ -388,7 +528,13 @@ lookupSymbol( char *lbl ) # if defined(OBJFORMAT_ELF) return dlsym(dl_prog_handle, lbl); # elif defined(OBJFORMAT_PEi386) - ASSERT(2+2 == 5); + 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 { @@ -424,6 +570,7 @@ loadObj( char *path ) int r, n; FILE *f; + /* fprintf(stderr, "loadObj %s\n", path ); */ # ifdef DEBUG /* assert that we haven't already loaded this object */ { @@ -657,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 @@ -811,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)) @@ -821,8 +971,7 @@ 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) { @@ -833,16 +982,22 @@ ocVerifyImage_PEi386 ( ObjectCode* oc ) belch("PEi386 with nonempty optional header"); 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) ) { + 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_BYTES_REVERSED_HI) || - !(hdr->Characteristics & IMAGE_FILE_32BIT_MACHINE) ) { - belch("Invalid PEi386 word size or endiannness"); + 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; + } + /* fprintf(stderr, "strtab size %d\n", * (UInt32*)strtab); */ + if (* (UInt32*)strtab > 510000) { + belch("PEi386 object has suspiciously large string table; > 64k relocs?"); return 0; } @@ -874,16 +1029,7 @@ 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 < *(Int32*)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; @@ -915,6 +1061,7 @@ 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*) @@ -925,12 +1072,21 @@ ocVerifyImage_PEi386 ( ObjectCode* oc ) rel->VirtualAddress ); sym = (COFF_symbol*) myindex ( sizeof_COFF_symbol, symtab, rel->SymbolTableIndex ); - printName ( sym->Name, strtab ); + 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; @@ -963,7 +1119,6 @@ ocVerifyImage_PEi386 ( ObjectCode* oc ) } fprintf ( stderr, "\n" ); - return 1; } @@ -1009,8 +1164,8 @@ ocGetNames_PEi386 ( ObjectCode* oc ) symtab_i = (COFF_symbol*) 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; @@ -1018,8 +1173,8 @@ ocGetNames_PEi386 ( ObjectCode* oc ) /* 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 */ @@ -1030,6 +1185,7 @@ ocGetNames_PEi386 ( ObjectCode* oc ) addr = ((UChar*)(oc->image)) + (sectabent->PointerToRawData + symtab_i->Value); + /* 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; @@ -1054,15 +1210,15 @@ ocGetNames_PEi386 ( ObjectCode* oc ) COFF_section* sectab_i = (COFF_section*) myindex ( sizeof_COFF_section, sectab, i ); - IF_DEBUG(linker, belchf("section name = %s\n", sectab_i->Name )); + 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 @@ -1108,7 +1264,8 @@ ocResolve_PEi386 ( ObjectCode* oc ) /* 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)) @@ -1140,7 +1297,8 @@ ocResolve_PEi386 ( ObjectCode* oc ) pP = (UInt32*)( ((UChar*)(oc->image)) + (sectab_i->PointerToRawData - + reltab_j->VirtualAddress) + + reltab_j->VirtualAddress + - sectab_i->VirtualAddress ) ); /* the existing contents of pP */ A = *pP; @@ -1158,7 +1316,7 @@ ocResolve_PEi386 ( ObjectCode* oc ) printName ( sym->Name, strtab ); fprintf ( stderr, "'\n" )); - if (sym->StorageClass == IMAGE_SYM_CLASS_STATIC) { + if (sym->StorageClass == MYIMAGE_SYM_CLASS_STATIC) { COFF_section* section_sym = findPEi386SectionCalled ( oc, sym->Name ); if (!section_sym) { @@ -1170,7 +1328,7 @@ ocResolve_PEi386 ( ObjectCode* oc ) + (section_sym->PointerToRawData + sym->Value); } else { - copyName ( sym->Name, strtab, symbol, 1000 ); + copyName ( sym->Name, strtab, symbol, 1000-1 ); zapTrailingAtSign ( symbol ); (void*)S = lookupLocalSymbol( oc, symbol ); if ((void*)S == NULL) @@ -1183,10 +1341,10 @@ ocResolve_PEi386 ( ObjectCode* oc ) } 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). @@ -1212,6 +1370,7 @@ ocResolve_PEi386 ( ObjectCode* oc ) } } + /* fprintf(stderr, "completed %s\n", oc->fileName); */ return 1; }