diff options
author | Ben Gamari <ben@smart-cactus.org> | 2022-02-04 08:44:49 -0500 |
---|---|---|
committer | Ben Gamari <ben@smart-cactus.org> | 2022-04-06 16:25:25 -0400 |
commit | d286a55caebca8a4e5e73bbfeeb766e333271a09 (patch) | |
tree | d1c9c1dd3e34e2bd3661aae9719f094015799388 /rts/Linker.c | |
parent | 42bf7528559fb518092fef3902afb73af5de146e (diff) | |
download | haskell-d286a55caebca8a4e5e73bbfeeb766e333271a09.tar.gz |
rts/linker: Preserve information about symbol types
As noted in #20978, the linker would previously handle overflowed
relocations by creating a jump island. While this is fine in the case of
code symbols, it's very much not okay in the case of data symbols. To
fix this we must keep track of whether each symbol is code or data and
relocate them appropriately. This patch takes the first step in this
direction, adding a symbol type field to the linker's symbol table. It
doesn't yet change relocation behavior to take advantage of this
knowledge.
Fixes #20978.
Diffstat (limited to 'rts/Linker.c')
-rw-r--r-- | rts/Linker.c | 59 |
1 files changed, 50 insertions, 9 deletions
diff --git a/rts/Linker.c b/rts/Linker.c index 43eff730b8..c1918ecbba 100644 --- a/rts/Linker.c +++ b/rts/Linker.c @@ -185,6 +185,17 @@ static void ghciRemoveSymbolTable(StrHashTable *table, const SymbolName* key, stgFree(pinfo); } +static const char * +symbolTypeString (SymType type) +{ + switch (type) { + case SYM_TYPE_CODE: return "code"; + case SYM_TYPE_DATA: return "data"; + case SYM_TYPE_INDIRECT_DATA: return "indirect-data"; + default: barf("symbolTypeString: unknown symbol type"); + } +} + /* ----------------------------------------------------------------------------- * Insert symbols into hash tables, checking for duplicates. * @@ -212,6 +223,7 @@ int ghciInsertSymbolTable( const SymbolName* key, SymbolAddr* data, SymStrength strength, + SymType type, ObjectCode *owner) { RtsSymbolInfo *pinfo = lookupStrHashTable(table, key); @@ -221,9 +233,20 @@ int ghciInsertSymbolTable( pinfo->value = data; pinfo->owner = owner; pinfo->strength = strength; + pinfo->type = type; insertStrHashTable(table, key, pinfo); return 1; } + else if (pinfo->type != type) + { + debugBelch("Symbol type mismatch.\n"); + debugBelch("Symbol %s was defined by %" PATH_FMT " to be a %s symbol.\n", + key, obj_name, symbolTypeString(type)); + debugBelch(" yet was defined by %" PATH_FMT " to be a %s symbol.\n", + pinfo->owner ? pinfo->owner->fileName : WSTR("<builtin>"), + symbolTypeString(pinfo->type)); + return 1; + } else if (pinfo->strength == STRENGTH_STRONG) { /* The existing symbol is strong meaning we must never override it */ @@ -398,7 +421,7 @@ initLinker_ (int retain_cafs) for (const RtsSymbolVal *sym = rtsSyms; sym->lbl != NULL; sym++) { if (! ghciInsertSymbolTable(WSTR("(GHCi built-in symbols)"), symhash, sym->lbl, sym->addr, - sym->strength, NULL)) { + sym->strength, sym->type, NULL)) { barf("ghciInsertSymbolTable failed"); } IF_DEBUG(linker, debugBelch("initLinker: inserting rts symbol %s, %p\n", sym->lbl, sym->addr)); @@ -408,7 +431,7 @@ initLinker_ (int retain_cafs) if (! ghciInsertSymbolTable(WSTR("(GHCi built-in symbols)"), symhash, MAYBE_LEADING_UNDERSCORE_STR("newCAF"), retain_cafs ? newRetainedCAF : newGCdCAF, - HS_BOOL_FALSE, NULL)) { + HS_BOOL_FALSE, SYM_TYPE_CODE, NULL)) { barf("ghciInsertSymbolTable failed"); } @@ -775,14 +798,14 @@ HsBool removeLibrarySearchPath(HsPtr dll_path_index) } /* ----------------------------------------------------------------------------- - * insert a symbol in the hash table + * insert a code symbol in the hash table * * Returns: 0 on failure, nonzero on success */ HsInt insertSymbol(pathchar* obj_name, SymbolName* key, SymbolAddr* data) { return ghciInsertSymbolTable(obj_name, symhash, key, data, HS_BOOL_FALSE, - NULL); + SYM_TYPE_CODE, NULL); } /* ----------------------------------------------------------------------------- @@ -792,16 +815,16 @@ HsInt insertSymbol(pathchar* obj_name, SymbolName* key, SymbolAddr* data) * symbol. */ #if defined(OBJFORMAT_PEi386) -SymbolAddr* lookupDependentSymbol (SymbolName* lbl, ObjectCode *dependent) +SymbolAddr* lookupDependentSymbol (SymbolName* lbl, ObjectCode *dependent, SymType *type) { (void)dependent; // TODO ASSERT_LOCK_HELD(&linker_mutex); - return lookupSymbol_PEi386(lbl); + return lookupSymbol_PEi386(lbl, type); } #else -SymbolAddr* lookupDependentSymbol (SymbolName* lbl, ObjectCode *dependent) +SymbolAddr* lookupDependentSymbol (SymbolName* lbl, ObjectCode *dependent, SymType *type) { ASSERT_LOCK_HELD(&linker_mutex); IF_DEBUG(linker_verbose, debugBelch("lookupSymbol: looking up '%s'\n", lbl)); @@ -825,6 +848,11 @@ SymbolAddr* lookupDependentSymbol (SymbolName* lbl, ObjectCode *dependent) # if defined(OBJFORMAT_ELF) SymbolAddr *ret = internal_dlsym(lbl); + if (type) { + // We assume that the symbol is code since this is usually the case + // and dlsym doesn't tell us. + *type = SYM_TYPE_CODE; + } // Generally the dynamic linker would define _DYNAMIC, which is // supposed to point to various bits of dynamic linker state (see @@ -835,6 +863,9 @@ SymbolAddr* lookupDependentSymbol (SymbolName* lbl, ObjectCode *dependent) if (ret == NULL && strcmp(lbl, "_DYNAMIC") == 0) { static void *RTS_DYNAMIC = NULL; ret = (SymbolAddr *) &RTS_DYNAMIC; + if (type) { + *type = SYM_TYPE_DATA; + } } return ret; # elif defined(OBJFORMAT_MACHO) @@ -848,6 +879,11 @@ SymbolAddr* lookupDependentSymbol (SymbolName* lbl, ObjectCode *dependent) IF_DEBUG(linker, debugBelch("lookupSymbol: looking up %s with dlsym\n", lbl)); CHECK(lbl[0] == '_'); + if (type) { + // We assume that the symbol is code since this is usually the case + // and dlsym doesn't tell us. + *type = SYM_TYPE_CODE; + } return internal_dlsym(lbl + 1); # else @@ -857,6 +893,10 @@ SymbolAddr* lookupDependentSymbol (SymbolName* lbl, ObjectCode *dependent) static void *RTS_NO_FINI = NULL; if (strcmp(lbl, "__fini_array_end") == 0) { return (SymbolAddr *) &RTS_NO_FINI; } if (strcmp(lbl, "__fini_array_start") == 0) { return (SymbolAddr *) &RTS_NO_FINI; } + if (type) { + // This is an assumption + *type = pinfo->type; + } if (dependent) { // Add dependent as symbol's owner's dependency @@ -945,7 +985,7 @@ SymbolAddr* lookupSymbol( SymbolName* lbl ) ACQUIRE_LOCK(&linker_mutex); // NULL for "don't add dependent". When adding a dependency we call // lookupDependentSymbol directly. - SymbolAddr* r = lookupDependentSymbol(lbl, NULL); + SymbolAddr* r = lookupDependentSymbol(lbl, NULL, NULL); if (!r) { errorBelch("^^ Could not load '%s', dependency unresolved. " "See top entry above.\n", lbl); @@ -1562,7 +1602,8 @@ int ocTryLoad (ObjectCode* oc) { if ( symbol.name && !ghciInsertSymbolTable(oc->fileName, symhash, symbol.name, symbol.addr, - isSymbolWeak(oc, symbol.name), oc)) { + isSymbolWeak(oc, symbol.name), + symbol.type, oc)) { return 0; } } |