summaryrefslogtreecommitdiff
path: root/rts/Linker.c
diff options
context:
space:
mode:
authorGregory Wright <gwright@antiope.com>2012-01-07 09:58:00 -0500
committerIan Lynagh <igloo@earth.li>2012-01-11 17:37:04 +0000
commitb56e7b20605d742536441ed721a4fa21598782d5 (patch)
tree0e95ec612377721186c609e4350095209b25afa5 /rts/Linker.c
parenta83b02adcadef83ccc9ea66b1d9fc20bcd035214 (diff)
downloadhaskell-b56e7b20605d742536441ed721a4fa21598782d5.tar.gz
check for failed external symbol lookups (partial fix for #5748)
Diffstat (limited to 'rts/Linker.c')
-rw-r--r--rts/Linker.c96
1 files changed, 81 insertions, 15 deletions
diff --git a/rts/Linker.c b/rts/Linker.c
index 7fc6d0a804..9fb3f68fb9 100644
--- a/rts/Linker.c
+++ b/rts/Linker.c
@@ -1524,16 +1524,17 @@ lookupSymbol( char *lbl )
/* On OS X 10.3 and later, we use dlsym instead of the old legacy
interface.
- HACK: On OS X, global symbols are prefixed with an underscore.
+ HACK: On OS X, all symbols are prefixed with an underscore.
However, dlsym wants us to omit the leading underscore from the
- symbol name. For now, we simply strip it off here (and ONLY
+ symbol name -- the dlsym routine puts it back on before searching
+ for the symbol. For now, we simply strip it off here (and ONLY
here).
*/
IF_DEBUG(linker, debugBelch("lookupSymbol: looking up %s with dlsym\n", lbl));
- ASSERT(lbl[0] == '_');
- return dlsym(dl_prog_handle, lbl+1);
+ ASSERT(lbl[0] == '_');
+ return dlsym(dl_prog_handle, lbl + 1);
# else
- if(NSIsSymbolNameDefined(lbl)) {
+ if (NSIsSymbolNameDefined(lbl)) {
NSSymbol symbol = NSLookupAndBindSymbol(lbl);
return NSAddressOfSymbol(symbol);
} else {
@@ -4765,7 +4766,7 @@ resolveImports(
#endif
- for(i=0; i*itemSize < sect->size;i++)
+ for(i = 0; i * itemSize < sect->size; i++)
{
// according to otool, reserved1 contains the first index into the indirect symbol table
struct nlist *symbol = &nlist[indirectSyms[sect->reserved1+i]];
@@ -4782,9 +4783,11 @@ resolveImports(
addr = lookupSymbol(nm);
IF_DEBUG(linker, debugBelch("resolveImports: looking up %s, %p\n", nm, addr));
}
- if (!addr)
+
+ if (addr == NULL)
{
- errorBelch("\n%s: unknown symbol `%s'", oc->fileName, nm);
+ errorBelch("\nlookupSymbol failed in resolveImports\n"
+ "%s: unknown symbol `%s'", oc->fileName, nm);
return 0;
}
ASSERT(addr);
@@ -4809,7 +4812,8 @@ resolveImports(
return 1;
}
-static unsigned long relocateAddress(
+static unsigned long
+relocateAddress(
ObjectCode* oc,
int nSections,
struct section* sections,
@@ -4832,7 +4836,8 @@ static unsigned long relocateAddress(
return 0;
}
-static int relocateSection(
+static int
+relocateSection(
ObjectCode* oc,
char *image,
struct symtab_command *symLC, struct nlist *nlist,
@@ -4857,7 +4862,7 @@ static int relocateSection(
relocs = (struct relocation_info*) (image + sect->reloff);
- for(i=0;i<n;i++)
+ for(i = 0; i < n; i++)
{
#ifdef x86_64_HOST_ARCH
struct relocation_info *reloc = &relocs[i];
@@ -4870,6 +4875,15 @@ static int relocateSection(
uint64_t baseValue;
int type = reloc->r_type;
+ IF_DEBUG(linker, debugBelch("relocateSection: relocation %d\n", i));
+ IF_DEBUG(linker, debugBelch(" : type = %d\n", reloc->r_type));
+ IF_DEBUG(linker, debugBelch(" : address = %d\n", reloc->r_address));
+ IF_DEBUG(linker, debugBelch(" : symbolnum = %u\n", reloc->r_symbolnum));
+ IF_DEBUG(linker, debugBelch(" : pcrel = %d\n", reloc->r_pcrel));
+ IF_DEBUG(linker, debugBelch(" : length = %d\n", reloc->r_length));
+ IF_DEBUG(linker, debugBelch(" : extern = %d\n", reloc->r_extern));
+ IF_DEBUG(linker, debugBelch(" : type = %d\n", reloc->r_type));
+
checkProddableBlock(oc,thingPtr);
switch(reloc->r_length)
{
@@ -4898,34 +4912,86 @@ static int relocateSection(
reloc->r_length, thing, (char *)baseValue));
if (type == X86_64_RELOC_GOT
- || type == X86_64_RELOC_GOT_LOAD)
+ || type == X86_64_RELOC_GOT_LOAD)
{
struct nlist *symbol = &nlist[reloc->r_symbolnum];
char *nm = image + symLC->stroff + symbol->n_un.n_strx;
+ void *addr = NULL;
IF_DEBUG(linker, debugBelch("relocateSection: making jump island for %s, extern = %d, X86_64_RELOC_GOT\n", nm, reloc->r_extern));
+
ASSERT(reloc->r_extern);
- value = (uint64_t) &makeSymbolExtra(oc, reloc->r_symbolnum, (unsigned long)lookupSymbol(nm))->addr;
+ if (reloc->r_extern == 0) {
+ errorBelch("\nrelocateSection: global offset table relocation for symbol with r_extern == 0\n");
+ }
+
+ if (symbol->n_type & N_EXT) {
+ // The external bit is set, meaning the symbol is exported,
+ // and therefore can be looked up in this object module's
+ // symtab, or it is undefined, meaning dlsym must be used
+ // to resolve it.
+
+ addr = lookupSymbol(nm);
+ IF_DEBUG(linker, debugBelch("relocateSection: looked up %s, "
+ "external X86_64_RELOC_GOT or X86_64_RELOC_GOT_LOAD\n", nm));
+ IF_DEBUG(linker, debugBelch(" : addr = %p\n", addr));
+
+ if (addr == NULL) {
+ errorBelch("\nlookupSymbol failed in relocateSection (RELOC_GOT)\n"
+ "%s: unknown symbol `%s'", oc->fileName, nm);
+ return 0;
+ }
+ } else {
+ IF_DEBUG(linker, debugBelch("relocateSection: %s is not an exported symbol\n", nm));
+
+ // The symbol is not exported, or defined in another
+ // module, so it must be in the current object module,
+ // at the location given by the section index and
+ // symbol address (symbol->n_value)
+
+ if ((symbol->n_type & N_TYPE) == N_SECT) {
+ addr = (void *)relocateAddress(oc, nSections, sections, symbol->n_value);
+ IF_DEBUG(linker, debugBelch("relocateSection: calculated relocation %p of "
+ "non-external X86_64_RELOC_GOT or X86_64_RELOC_GOT_LOAD\n",
+ (void *)symbol->n_value));
+ IF_DEBUG(linker, debugBelch(" : addr = %p\n", addr));
+ } else {
+ errorBelch("\nrelocateSection: %s is not exported,"
+ " and should be defined in a section, but isn't!\n", nm);
+ }
+ }
+
+ value = (uint64_t) &makeSymbolExtra(oc, reloc->r_symbolnum, (unsigned long)addr)->addr;
type = X86_64_RELOC_SIGNED;
}
- else if(reloc->r_extern)
+ else if (reloc->r_extern)
{
struct nlist *symbol = &nlist[reloc->r_symbolnum];
char *nm = image + symLC->stroff + symbol->n_un.n_strx;
+ void *addr = NULL;
IF_DEBUG(linker, debugBelch("relocateSection: looking up external symbol %s\n", nm));
IF_DEBUG(linker, debugBelch(" : type = %d\n", symbol->n_type));
IF_DEBUG(linker, debugBelch(" : sect = %d\n", symbol->n_sect));
IF_DEBUG(linker, debugBelch(" : desc = %d\n", symbol->n_desc));
IF_DEBUG(linker, debugBelch(" : value = %p\n", (void *)symbol->n_value));
+
if ((symbol->n_type & N_TYPE) == N_SECT) {
value = relocateAddress(oc, nSections, sections,
symbol->n_value);
IF_DEBUG(linker, debugBelch("relocateSection, defined external symbol %s, relocated address %p\n", nm, (void *)value));
}
else {
- value = (uint64_t) lookupSymbol(nm);
+ addr = lookupSymbol(nm);
+ if (addr == NULL)
+ {
+ errorBelch("\nlookupSymbol failed in relocateSection (relocate external)\n"
+ "%s: unknown symbol `%s'", oc->fileName, nm);
+ return 0;
+ }
+
+ value = (uint64_t) addr;
IF_DEBUG(linker, debugBelch("relocateSection: external symbol %s, address %p\n", nm, (void *)value));
}
}