X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=ghc%2Frts%2FLinker.c;h=d76e0425f9ee4fad3d1a78a79e06cc14746f997f;hb=3b6b5789852e84639be18d114cad4bde6139847e;hp=4f2a456cccd0823b5bab34b713ba72122b31cba1;hpb=3cf7519556ab1b4c7aa49094a0a8d73f06828979;p=ghc-hetmet.git diff --git a/ghc/rts/Linker.c b/ghc/rts/Linker.c index 4f2a456..d76e042 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.29 2001/02/14 11:02:36 sewardj Exp $ * * (c) The GHC Team, 2000 * @@ -279,6 +279,42 @@ initLinker( void ) } /* ----------------------------------------------------------------------------- + * 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 0 if fail, 1 if success. + */ +char* +addDLL ( 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); + 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; + } + ASSERT(0); /*NOTREACHED*/ +# elif defined(OBJFORMAT_PEi386) + barf("addDLL: not implemented on PEi386 yet"); + return 0; +# else + barf("addDLL: not implemented on this platform"); +# endif +} + +/* ----------------------------------------------------------------------------- * lookup a symbol in the hash table */ void * @@ -295,6 +331,21 @@ lookupSymbol( char *lbl ) } } +static +void * +lookupLocalSymbol( ObjectCode* oc, char *lbl ) +{ + SymbolVal *val; + val = lookupStrHashTable(oc->lochash, lbl); + + if (val == NULL) { + return NULL; + } else { + return val->addr; + } +} + + /* ----------------------------------------------------------------------------- * Load an obj (populate the global symbol table, but don't resolve yet) * @@ -308,14 +359,14 @@ loadObj( char *path ) int r, n; FILE *f; -#ifdef DEBUG +# 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 +382,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 +390,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 +446,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 +# else barf("link: not implemented on this platform"); -# endif +# endif if (!r) { return r; } oc->status = OBJECT_RESOLVED; } @@ -447,6 +499,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; } @@ -1332,27 +1387,36 @@ ocGetNames_ELF ( ObjectCode* oc ) oc->n_symbols = nent; 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])); + 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, &(oc->symbols[j])); + } else { + IF_DEBUG(linker,belch( "addOTabName(GLOB): %10p %s %s", + ad, oc->fileName, nm )); + insertStrHashTable(symhash, nm, &(oc->symbols[j])); + } } else { IF_DEBUG(linker,belch( "skipping `%s'", @@ -1415,9 +1479,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'", @@ -1487,9 +1554,12 @@ 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'", @@ -1530,9 +1600,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 +1649,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; }