summaryrefslogtreecommitdiff
path: root/rts/Linker.c
diff options
context:
space:
mode:
authorBen Gamari <ben@smart-cactus.org>2022-02-04 08:44:49 -0500
committerBen Gamari <ben@smart-cactus.org>2022-04-06 16:25:25 -0400
commitd286a55caebca8a4e5e73bbfeeb766e333271a09 (patch)
treed1c9c1dd3e34e2bd3661aae9719f094015799388 /rts/Linker.c
parent42bf7528559fb518092fef3902afb73af5de146e (diff)
downloadhaskell-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.c59
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;
}
}