summaryrefslogtreecommitdiff
path: root/rts/Linker.c
diff options
context:
space:
mode:
authorTakano Akio <aljee@hyper.cx>2012-12-29 11:59:34 +0900
committerAustin Seipp <austin@well-typed.com>2013-10-25 09:14:30 -0500
commit41fb63668352eb4f04f4aaca27ef3ad09025afc3 (patch)
tree5f85db831765c6a772bd7ebc9c24b327963e4448 /rts/Linker.c
parent736ed65532d12a3d2d8c79a1dcce1004499bc740 (diff)
downloadhaskell-41fb63668352eb4f04f4aaca27ef3ad09025afc3.tar.gz
ghci: add support for ELF weak symbols
Signed-off-by: Austin Seipp <austin@well-typed.com>
Diffstat (limited to 'rts/Linker.c')
-rw-r--r--rts/Linker.c100
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