diff options
author | Takano Akio <aljee@hyper.cx> | 2012-12-29 11:59:34 +0900 |
---|---|---|
committer | Austin Seipp <austin@well-typed.com> | 2013-10-25 09:14:30 -0500 |
commit | 41fb63668352eb4f04f4aaca27ef3ad09025afc3 (patch) | |
tree | 5f85db831765c6a772bd7ebc9c24b327963e4448 | |
parent | 736ed65532d12a3d2d8c79a1dcce1004499bc740 (diff) | |
download | haskell-41fb63668352eb4f04f4aaca27ef3ad09025afc3.tar.gz |
ghci: add support for ELF weak symbols
Signed-off-by: Austin Seipp <austin@well-typed.com>
-rw-r--r-- | rts/Linker.c | 100 |
1 files changed, 77 insertions, 23 deletions
diff --git a/rts/Linker.c b/rts/Linker.c index 74cac115ee..b918c8f3f1 100644 --- a/rts/Linker.c +++ b/rts/Linker.c @@ -137,7 +137,13 @@ #include <sys/tls.h> #endif -/* Hash table mapping symbol names to Symbol */ +typedef struct _RtsSymbolInfo { + void *value; + const ObjectCode *owner; + HsBool weak; +} RtsSymbolInfo; + +/* Hash table mapping symbol names to RtsSymbolInfo */ static /*Str*/HashTable *symhash; /* List of currently loaded objects */ @@ -1464,15 +1470,31 @@ static RtsSymbolVal rtsSyms[] = { * Insert symbols into hash tables, checking for duplicates. */ -static void ghciInsertStrHashTable ( pathchar* obj_name, - HashTable *table, - char* key, - void *data - ) +static void ghciInsertSymbolTable( + pathchar* obj_name, + HashTable *table, + char* key, + void *data, + HsBool weak, + ObjectCode *owner) { - if (lookupHashTable(table, (StgWord)key) == NULL) + RtsSymbolInfo *pinfo = lookupStrHashTable(table, key); + if (!pinfo) /* new entry */ + { + pinfo = stgMallocBytes(sizeof (*pinfo), "ghciInsertToSymbolTable"); + pinfo->value = data; + pinfo->owner = owner; + pinfo->weak = weak; + insertStrHashTable(table, key, pinfo); + return; + } else if ((!pinfo->weak || pinfo->value) && weak) { + return; /* duplicate weak symbol, throw it away */ + } else if (pinfo->weak) /* weak symbol is in the table */ { - insertStrHashTable(table, (StgWord)key, data); + /* override the weak definition with the non-weak one */ + pinfo->value = data; + pinfo->owner = owner; + pinfo->weak = HS_BOOL_FALSE; return; } debugBelch( @@ -1493,6 +1515,32 @@ static void ghciInsertStrHashTable ( pathchar* obj_name, ); stg_exit(1); } + +static HsBool ghciLookupSymbolTable(HashTable *table, + const char *key, void **result) +{ + RtsSymbolInfo *pinfo = lookupStrHashTable(table, key); + if (!pinfo) { + *result = NULL; + return HS_BOOL_FALSE; + } + if (pinfo->weak) + IF_DEBUG(linker, debugBelch("lookup: promoting %s\n", key)); + /* Once it's looked up, it can no longer be overridden */ + pinfo->weak = HS_BOOL_FALSE; + + *result = pinfo->value; + return HS_BOOL_TRUE; +} + +static void ghciRemoveSymbolTable(HashTable *table, const char *key, + ObjectCode *owner) +{ + RtsSymbolInfo *pinfo = lookupStrHashTable(table, key); + if (!pinfo || owner != pinfo->owner) return; + removeStrHashTable(table, key, NULL); + stgFree(pinfo); +} /* ----------------------------------------------------------------------------- * initialize the object linker */ @@ -1539,8 +1587,8 @@ initLinker( void ) /* populate the symbol table with stuff from the RTS */ for (sym = rtsSyms; sym->lbl != NULL; sym++) { - ghciInsertStrHashTable(WSTR("(GHCi built-in symbols)"), - symhash, sym->lbl, sym->addr); + ghciInsertSymbolTable(WSTR("(GHCi built-in symbols)"), + symhash, sym->lbl, sym->addr, HS_BOOL_FALSE, NULL); IF_DEBUG(linker, debugBelch("initLinker: inserting rts symbol %s, %p\n", sym->lbl, sym->addr)); } # if defined(OBJFORMAT_MACHO) && defined(powerpc_HOST_ARCH) @@ -1868,7 +1916,7 @@ error: void insertSymbol(pathchar* obj_name, char* key, void* data) { - ghciInsertStrHashTable(obj_name, symhash, key, data); + ghciInsertSymbolTable(obj_name, symhash, key, data, HS_BOOL_FALSE, NULL); } /* ----------------------------------------------------------------------------- @@ -1881,9 +1929,8 @@ lookupSymbol( char *lbl ) IF_DEBUG(linker, debugBelch("lookupSymbol: looking up %s\n", lbl)); initLinker() ; ASSERT(symhash != NULL); - val = lookupStrHashTable(symhash, lbl); - if (val == NULL) { + if (!ghciLookupSymbolTable(symhash, lbl, &val)) { IF_DEBUG(linker, debugBelch("lookupSymbol: symbol not found\n")); # if defined(OBJFORMAT_ELF) return internal_dlsym(dl_prog_handle, lbl); @@ -1986,7 +2033,7 @@ void ghci_enquire ( char* addr ) if (sym == NULL) continue; a = NULL; if (a == NULL) { - a = lookupStrHashTable(symhash, sym); + ghciLookupSymbolTable(symhash, sym, (void **)&a); } if (a == NULL) { // debugBelch("ghci_enquire: can't find %s\n", sym); @@ -2854,7 +2901,7 @@ unloadObj( pathchar *path ) int i; for (i = 0; i < oc->n_symbols; i++) { if (oc->symbols[i] != NULL) { - removeStrHashTable(symhash, oc->symbols[i], NULL); + ghciRemoveSymbolTable(symhash, oc->symbols[i], oc); } } } @@ -3978,7 +4025,8 @@ ocGetNames_PEi386 ( ObjectCode* oc ) ASSERT(i >= 0 && i < oc->n_symbols); /* cstring_from_COFF_symbol_name always succeeds. */ oc->symbols[i] = (char*)sname; - ghciInsertStrHashTable(oc->fileName, symhash, (char*)sname, addr); + ghciInsertSymbolTable(oc->fileName, symhash, (char*)sname, addr, + HS_BOOL_FALSE, oc); } else { # if 0 debugBelch( @@ -4820,6 +4868,7 @@ ocGetNames_ELF ( ObjectCode* oc ) for (j = 0; j < nent; j++) { char isLocal = FALSE; /* avoids uninit-var warning */ + HsBool isWeak = HS_BOOL_FALSE; char* ad = NULL; char* nm = strtab + stab[j].st_name; int secno = stab[j].st_shndx; @@ -4840,6 +4889,7 @@ ocGetNames_ELF ( ObjectCode* oc ) else if ( ( ELF_ST_BIND(stab[j].st_info)==STB_GLOBAL || ELF_ST_BIND(stab[j].st_info)==STB_LOCAL + || ELF_ST_BIND(stab[j].st_info)==STB_WEAK ) /* and not an undefined symbol */ && stab[j].st_shndx != SHN_UNDEF @@ -4863,7 +4913,8 @@ ocGetNames_ELF ( ObjectCode* oc ) ad = ehdrC + shdr[ secno ].sh_offset + stab[j].st_value; if (ELF_ST_BIND(stab[j].st_info)==STB_LOCAL) { isLocal = TRUE; - } else { + isWeak = FALSE; + } else { /* STB_GLOBAL or STB_WEAK */ #ifdef ELF_FUNCTION_DESC /* dlsym() and the initialisation table both give us function * descriptors, so to be consistent we store function descriptors @@ -4874,6 +4925,7 @@ ocGetNames_ELF ( ObjectCode* oc ) IF_DEBUG(linker,debugBelch( "addOTabName(GLOB): %10p %s %s\n", ad, oc->fileName, nm )); isLocal = FALSE; + isWeak = (ELF_ST_BIND(stab[j].st_info)==STB_WEAK); } } @@ -4886,7 +4938,7 @@ ocGetNames_ELF ( ObjectCode* oc ) if (isLocal) { /* Ignore entirely. */ } else { - ghciInsertStrHashTable(oc->fileName, symhash, nm, ad); + ghciInsertSymbolTable(oc->fileName, symhash, nm, ad, isWeak, oc); } } else { /* Skip. */ @@ -6579,11 +6631,13 @@ ocGetNames_MachO(ObjectCode* oc) else { IF_DEBUG(linker, debugBelch("ocGetNames_MachO: inserting %s\n", nm)); - ghciInsertStrHashTable(oc->fileName, symhash, nm, + ghciInsertSymbolTable(oc->fileName, symhash, nm, image + sections[nlist[i].n_sect-1].offset - sections[nlist[i].n_sect-1].addr - + nlist[i].n_value); + + nlist[i].n_value, + HS_BOOL_FALSE, + oc); oc->symbols[curSymbol++] = nm; } } @@ -6614,8 +6668,8 @@ ocGetNames_MachO(ObjectCode* oc) nlist[i].n_value = commonCounter; IF_DEBUG(linker, debugBelch("ocGetNames_MachO: inserting common symbol: %s\n", nm)); - ghciInsertStrHashTable(oc->fileName, symhash, nm, - (void*)commonCounter); + ghciInsertSymbolTable(oc->fileName, symhash, nm, + (void*)commonCounter, HS_BOOL_FALSE, oc); oc->symbols[curSymbol++] = nm; commonCounter += sz; @@ -6785,7 +6839,7 @@ machoInitSymbolsWithoutUnderscore(void) #undef SymI_NeedsProto #define SymI_NeedsProto(x) \ - ghciInsertStrHashTable("(GHCi built-in symbols)", symhash, #x, *p++); + ghciInsertSymbolTable("(GHCi built-in symbols)", symhash, #x, *p++, HS_BOOL_FALSE, NULL); RTS_MACHO_NOUNDERLINE_SYMBOLS |