Commit c64918c1 authored by Tamar Christina's avatar Tamar Christina Committed by Ben Gamari

linker: store entire link map and use it.

Summary:
This fixes a corner case in which we have seen the symbol multiple times in
different static libraries, but due to a depencency we end up loading the
symbol from a library other than the first one.

Previously the runtime linker would only track symbols from the first
library and did not store the full link map.  In this case it was unable
to find the address for the symbols in the second library during delay
loading.

This change stores the address of all symbols seen so a full link map
is generated, such that when we make a different decision later than what
was expected we're able to still correctly load the library.

Test Plan: ./validate, new testcase T15894

Reviewers: angerman, bgamari, erikd, simonmar

Reviewed By: bgamari

Subscribers: rwbarton, carter

GHC Trac Issues: #15894

Differential Revision: https://phabricator.haskell.org/D5353

(cherry picked from commit a8b7cef4)
parent bf074e3e
......@@ -961,7 +961,7 @@ void ghci_enquire(SymbolAddr* addr)
for (oc = objects; oc; oc = oc->next) {
for (i = 0; i < oc->n_symbols; i++) {
sym = oc->symbols[i];
sym = oc->symbols[i].name;
if (sym == NULL) continue;
a = NULL;
if (a == NULL) {
......@@ -1103,8 +1103,8 @@ static void removeOcSymbols (ObjectCode *oc)
// Remove all the mappings for the symbols within this object..
int i;
for (i = 0; i < oc->n_symbols; i++) {
if (oc->symbols[i] != NULL) {
ghciRemoveSymbolTable(symhash, oc->symbols[i], oc);
if (oc->symbols[i].name != NULL) {
ghciRemoveSymbolTable(symhash, oc->symbols[i].name, oc);
}
}
......@@ -1565,18 +1565,21 @@ int ocTryLoad (ObjectCode* oc) {
are to be loaded by this call.
This call is intended to have no side-effects when a non-duplicate
symbol is re-inserted.
symbol is re-inserted. A symbol is only a duplicate if the object file
it is defined in has had it's relocations resolved. A resolved object
file means the symbols inside it are required.
We set the Address to NULL since that is not used to distinguish
symbols. Duplicate symbols are distinguished by name and oc.
The symbol address is not used to distinguish symbols. Duplicate symbols
are distinguished by name, oc and attributes (weak symbols etc).
*/
int x;
SymbolName* symbol;
Symbol_t symbol;
for (x = 0; x < oc->n_symbols; x++) {
symbol = oc->symbols[x];
if ( symbol
&& !ghciInsertSymbolTable(oc->fileName, symhash, symbol, NULL,
isSymbolWeak(oc, symbol), oc)) {
if ( symbol.name
&& !ghciInsertSymbolTable(oc->fileName, symhash, symbol.name,
symbol.addr,
isSymbolWeak(oc, symbol.name), oc)) {
return 0;
}
}
......
......@@ -20,6 +20,14 @@
typedef void SymbolAddr;
typedef char SymbolName;
/* Hold extended information about a symbol in case we need to resolve it at a
late stage. */
typedef struct _Symbol
{
SymbolName *name;
SymbolAddr *addr;
} Symbol_t;
/* Indication of section kinds for loaded objects. Needed by
the GC for deciding whether or not a pointer on the stack
is a code pointer.
......@@ -144,7 +152,7 @@ typedef struct _ObjectCode {
this object into the global symbol hash table. This is so that
we know which parts of the latter mapping to nuke when this
object is removed from the system. */
char** symbols;
Symbol_t *symbols;
int n_symbols;
/* ptr to mem containing the object file image */
......
......@@ -816,7 +816,7 @@ ocGetNames_ELF ( ObjectCode* oc )
oc->n_symbols += symTab->n_symbols;
}
oc->symbols = stgCallocBytes(oc->n_symbols, sizeof(SymbolName*),
oc->symbols = stgCallocBytes(oc->n_symbols, sizeof(Symbol_t),
"ocGetNames_ELF(oc->symbols)");
// Note calloc: if we fail partway through initializing symbols, we need
// to undo the additions to the symbol table so far. We know which ones
......@@ -927,7 +927,8 @@ ocGetNames_ELF ( ObjectCode* oc )
) {
goto fail;
}
oc->symbols[curSymbol++] = nm;
oc->symbols[curSymbol++].name = nm;
oc->symbols[curSymbol].addr = symbol->addr;
}
} else {
/* Skip. */
......
......@@ -1608,7 +1608,7 @@ ocGetNames_MachO(ObjectCode* oc)
*/
IF_DEBUG(linker, debugBelch("ocGetNames_MachO: %d external symbols\n",
oc->n_symbols));
oc->symbols = stgMallocBytes(oc->n_symbols * sizeof(SymbolName*),
oc->symbols = stgMallocBytes(oc->n_symbols * sizeof(Symbol_t),
"ocGetNames_MachO(oc->symbols)");
if (oc->info->symCmd) {
......@@ -1639,7 +1639,8 @@ ocGetNames_MachO(ObjectCode* oc)
, HS_BOOL_FALSE
, oc);
oc->symbols[curSymbol] = nm;
oc->symbols[curSymbol].name = nm;
oc->symbols[curSymbol].addr = addr;
curSymbol++;
}
}
......@@ -1676,7 +1677,8 @@ ocGetNames_MachO(ObjectCode* oc)
IF_DEBUG(linker, debugBelch("ocGetNames_MachO: inserting common symbol: %s\n", nm));
ghciInsertSymbolTable(oc->fileName, symhash, nm,
(void*)commonCounter, HS_BOOL_FALSE, oc);
oc->symbols[curSymbol] = nm;
oc->symbols[curSymbol].name = nm;
oc->symbols[curSymbol].addr = oc->info->macho_symbols[i].addr;
curSymbol++;
commonCounter += sz;
......
......@@ -1467,7 +1467,7 @@ ocGetNames_PEi386 ( ObjectCode* oc )
/* Copy exported symbols into the ObjectCode. */
oc->n_symbols = info->numberOfSymbols;
oc->symbols = stgCallocBytes(sizeof(SymbolName*), oc->n_symbols,
oc->symbols = stgCallocBytes(sizeof(Symbol_t), oc->n_symbols,
"ocGetNames_PEi386(oc->symbols)");
/* Work out the size of the global BSS section */
......@@ -1623,8 +1623,8 @@ ocGetNames_PEi386 ( ObjectCode* oc )
/* debugBelch("addSymbol %p `%s' Weak:%lld \n", addr, sname, isWeak); */
IF_DEBUG(linker, debugBelch("addSymbol %p `%s'\n", addr,sname));
ASSERT(i < (uint32_t)oc->n_symbols);
/* cstring_from_COFF_symbol_name always succeeds. */
oc->symbols[i] = (SymbolName*)sname;
oc->symbols[i].name = sname;
oc->symbols[i].addr = addr;
if (isWeak) {
setWeakSymbol(oc, sname);
}
......@@ -1637,7 +1637,8 @@ ocGetNames_PEi386 ( ObjectCode* oc )
} else {
/* We're skipping the symbol, but if we ever load this
object file we'll want to skip it then too. */
oc->symbols[i] = NULL;
oc->symbols[i].name = NULL;
oc->symbols[i].addr = NULL;
# if 0
debugBelch(
......@@ -2202,7 +2203,7 @@ resolveSymbolAddr_PEi386 (pathchar* buffer, int size,
"resolveSymbolAddr");
int blanks = 0;
for (int i = 0; i < obj->n_symbols; i++) {
SymbolName* sym = obj->symbols[i];
SymbolName* sym = obj->symbols[i].name;
if (sym == NULL)
{
blanks++;
......
TOP=../../..
include $(TOP)/mk/boilerplate.mk
include $(TOP)/mk/test.mk
T15894:
'$(TEST_CC)' -O2 -fno-builtin -c copysign.c -o copysign.o
'$(AR)' rsc libcopysign.a copysign.o
echo main | LIBRARY_PATH="$(PWD)" '$(TEST_HC)' $(TEST_HC_OPTS_INTERACTIVE) main.hs -lcopysign
test('T15894',
[extra_files(['copysign.c', 'main.hs']), when(ghc_dynamic(), skip)],
run_command, ['$MAKE -s --no-print-directory T15894'])
double
copysign (double x, double y)
{
return x * y;
}
double
with_copysign (double x)
{
return copysign (x, x);
}
module Main where
foreign import ccall "with_copysign" c_with_copysign :: Double -> Double
main = print $ c_with_copysign 8.5
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment