summaryrefslogtreecommitdiff
path: root/rts/Linker.c
diff options
context:
space:
mode:
Diffstat (limited to 'rts/Linker.c')
-rw-r--r--rts/Linker.c232
1 files changed, 164 insertions, 68 deletions
diff --git a/rts/Linker.c b/rts/Linker.c
index 7e3c7b1167..9fb3f68fb9 100644
--- a/rts/Linker.c
+++ b/rts/Linker.c
@@ -131,7 +131,7 @@ static /*Str*/HashTable *stablehash;
ObjectCode *objects = NULL; /* initially empty */
static HsInt loadOc( ObjectCode* oc );
-static ObjectCode* mkOc( char *path, char *image, int imageSize,
+static ObjectCode* mkOc( pathchar *path, char *image, int imageSize,
char *archiveMemberName
#ifndef USE_MMAP
#ifdef darwin_HOST_OS
@@ -140,6 +140,40 @@ static ObjectCode* mkOc( char *path, char *image, int imageSize,
#endif
);
+// Use wchar_t for pathnames on Windows (#5697)
+#if defined(mingw32_HOST_OS)
+#define pathcmp wcscmp
+#define pathlen wcslen
+#define pathopen _wfopen
+#define pathstat _wstat
+#define struct_stat struct _stat
+#define open wopen
+#define WSTR(s) L##s
+#define PATH_FMT "S"
+#else
+#define pathcmp strcmp
+#define pathlen strlen
+#define pathopen fopen
+#define pathstat stat
+#define struct_stat struct stat
+#define WSTR(s) s
+#define PATH_FMT "s"
+#endif
+
+static pathchar* pathdup(pathchar *path)
+{
+ pathchar *ret;
+#if defined(mingw32_HOST_OS)
+ ret = wcsdup(path);
+#else
+ /* sigh, strdup() isn't a POSIX function, so do it the long way */
+ ret = stgMallocBytes( strlen(path)+1, "loadObj" );
+ strcpy(ret, path);
+#endif
+ return ret;
+}
+
+
#if defined(OBJFORMAT_ELF)
static int ocVerifyImage_ELF ( ObjectCode* oc );
static int ocGetNames_ELF ( ObjectCode* oc );
@@ -1097,12 +1131,11 @@ static RtsSymbolVal rtsSyms[] = {
};
-
/* -----------------------------------------------------------------------------
* Insert symbols into hash tables, checking for duplicates.
*/
-static void ghciInsertStrHashTable ( char* obj_name,
+static void ghciInsertStrHashTable ( pathchar* obj_name,
HashTable *table,
char* key,
void *data
@@ -1118,7 +1151,7 @@ static void ghciInsertStrHashTable ( char* obj_name,
"GHCi runtime linker: fatal error: I found a duplicate definition for symbol\n"
" %s\n"
"whilst processing object file\n"
- " %s\n"
+ " %" PATH_FMT "\n"
"This could be caused by:\n"
" * Loading two different object files which export the same symbol\n"
" * Specifying the same object file twice on the GHCi command line\n"
@@ -1175,7 +1208,7 @@ initLinker( void )
/* populate the symbol table with stuff from the RTS */
for (sym = rtsSyms; sym->lbl != NULL; sym++) {
- ghciInsertStrHashTable("(GHCi built-in symbols)",
+ ghciInsertStrHashTable(WSTR("(GHCi built-in symbols)"),
symhash, sym->lbl, sym->addr);
IF_DEBUG(linker, debugBelch("initLinker: inserting rts symbol %s, %p\n", sym->lbl, sym->addr));
}
@@ -1217,8 +1250,8 @@ initLinker( void )
* but are necessary for resolving symbols in GHCi, hence we load
* them manually here.
*/
- addDLL("msvcrt");
- addDLL("kernel32");
+ addDLL(WSTR("msvcrt"));
+ addDLL(WSTR("kernel32"));
#endif
IF_DEBUG(linker, debugBelch("initLinker: done\n"));
@@ -1263,7 +1296,7 @@ exitLinker( void ) {
typedef
struct _OpenedDLL {
- char* name;
+ pathchar* name;
struct _OpenedDLL* next;
HINSTANCE instance;
}
@@ -1313,7 +1346,7 @@ internal_dlopen(const char *dll_name)
# endif
const char *
-addDLL( char *dll_name )
+addDLL( pathchar *dll_name )
{
# if defined(OBJFORMAT_ELF) || defined(OBJFORMAT_MACHO)
/* ------------------- ELF DLL loader ------------------- */
@@ -1385,7 +1418,7 @@ addDLL( char *dll_name )
# elif defined(OBJFORMAT_PEi386)
/* ------------------- Win32 DLL loader ------------------- */
- char* buf;
+ pathchar* buf;
OpenedDLL* o_dll;
HINSTANCE instance;
@@ -1395,7 +1428,7 @@ addDLL( char *dll_name )
/* See if we've already got it, and ignore if so. */
for (o_dll = opened_dlls; o_dll != NULL; o_dll = o_dll->next) {
- if (0 == strcmp(o_dll->name, dll_name))
+ if (0 == pathcmp(o_dll->name, dll_name))
return NULL;
}
@@ -1409,19 +1442,19 @@ addDLL( char *dll_name )
point character (.) to indicate that the module name has no
extension. */
- buf = stgMallocBytes(strlen(dll_name) + 10, "addDLL");
- sprintf(buf, "%s.DLL", dll_name);
- instance = LoadLibrary(buf);
+ buf = stgMallocBytes((pathlen(dll_name) + 10) * sizeof(wchar_t), "addDLL");
+ swprintf(buf, L"%s.DLL", dll_name);
+ instance = LoadLibraryW(buf);
if (instance == NULL) {
if (GetLastError() != ERROR_MOD_NOT_FOUND) goto error;
// KAA: allow loading of drivers (like winspool.drv)
- sprintf(buf, "%s.DRV", dll_name);
- instance = LoadLibrary(buf);
+ swprintf(buf, L"%s.DRV", dll_name);
+ instance = LoadLibraryW(buf);
if (instance == NULL) {
if (GetLastError() != ERROR_MOD_NOT_FOUND) goto error;
// #1883: allow loading of unix-style libfoo.dll DLLs
- sprintf(buf, "lib%s.DLL", dll_name);
- instance = LoadLibrary(buf);
+ swprintf(buf, L"lib%s.DLL", dll_name);
+ instance = LoadLibraryW(buf);
if (instance == NULL) {
goto error;
}
@@ -1431,8 +1464,7 @@ addDLL( char *dll_name )
/* Add this DLL to the list of DLLs in which to search for symbols. */
o_dll = stgMallocBytes( sizeof(OpenedDLL), "addDLL" );
- o_dll->name = stgMallocBytes(1+strlen(dll_name), "addDLL");
- strcpy(o_dll->name, dll_name);
+ o_dll->name = pathdup(dll_name);
o_dll->instance = instance;
o_dll->next = opened_dlls;
opened_dlls = o_dll;
@@ -1441,7 +1473,7 @@ addDLL( char *dll_name )
error:
stgFree(buf);
- sysErrorBelch(dll_name);
+ sysErrorBelch("%" PATH_FMT, dll_name);
/* LoadLibrary failed; return a ptr to the error msg. */
return "addDLL: could not load DLL";
@@ -1456,7 +1488,7 @@ error:
*/
void
-insertStableSymbol(char* obj_name, char* key, StgPtr p)
+insertStableSymbol(pathchar* obj_name, char* key, StgPtr p)
{
ghciInsertStrHashTable(obj_name, stablehash, key, getStablePtr(p));
}
@@ -1466,7 +1498,7 @@ insertStableSymbol(char* obj_name, char* key, StgPtr p)
* insert a symbol in the hash table
*/
void
-insertSymbol(char* obj_name, char* key, void* data)
+insertSymbol(pathchar* obj_name, char* key, void* data)
{
ghciInsertStrHashTable(obj_name, symhash, key, data);
}
@@ -1492,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 {
@@ -1646,7 +1679,7 @@ mmap_again:
#endif // USE_MMAP
static ObjectCode*
-mkOc( char *path, char *image, int imageSize,
+mkOc( pathchar *path, char *image, int imageSize,
char *archiveMemberName
#ifndef USE_MMAP
#ifdef darwin_HOST_OS
@@ -1671,9 +1704,7 @@ mkOc( char *path, char *image, int imageSize,
# endif
oc->image = image;
- /* sigh, strdup() isn't a POSIX function, so do it the long way */
- oc->fileName = stgMallocBytes( strlen(path)+1, "loadObj" );
- strcpy(oc->fileName, path);
+ oc->fileName = pathdup(path);
if (archiveMemberName) {
oc->archiveMemberName = stgMallocBytes( strlen(archiveMemberName)+1, "loadObj" );
@@ -1703,7 +1734,7 @@ mkOc( char *path, char *image, int imageSize,
}
HsInt
-loadArchive( char *path )
+loadArchive( pathchar *path )
{
ObjectCode* oc;
char *image;
@@ -1741,7 +1772,7 @@ loadArchive( char *path )
#endif
IF_DEBUG(linker, debugBelch("loadArchive: start\n"));
- IF_DEBUG(linker, debugBelch("loadArchive: Loading archive `%s'\n", path));
+ IF_DEBUG(linker, debugBelch("loadArchive: Loading archive `%" PATH_FMT" '\n", path));
gnuFileIndex = NULL;
gnuFileIndexSize = 0;
@@ -1749,7 +1780,7 @@ loadArchive( char *path )
fileNameSize = 32;
fileName = stgMallocBytes(fileNameSize, "loadArchive(fileName)");
- f = fopen(path, "rb");
+ f = pathopen(path, WSTR("rb"));
if (!f)
barf("loadObj: can't read `%s'", path);
@@ -1829,7 +1860,7 @@ loadArchive( char *path )
n = fread ( fileName, 1, 16, f );
if (n != 16) {
if (feof(f)) {
- IF_DEBUG(linker, debugBelch("loadArchive: EOF while reading from '%s'\n", path));
+ IF_DEBUG(linker, debugBelch("loadArchive: EOF while reading from '%" PATH_FMT "'\n", path));
break;
}
else {
@@ -2018,9 +2049,9 @@ loadArchive( char *path )
barf("loadArchive: error whilst reading `%s'", path);
}
- archiveMemberName = stgMallocBytes(strlen(path) + thisFileNameSize + 3,
+ archiveMemberName = stgMallocBytes(pathlen(path) + thisFileNameSize + 3,
"loadArchive(file)");
- sprintf(archiveMemberName, "%s(%.*s)",
+ sprintf(archiveMemberName, "%" PATH_FMT "(%.*s)",
path, (int)thisFileNameSize, fileName);
oc = mkOc(path, image, memberSize, archiveMemberName
@@ -2102,12 +2133,12 @@ loadArchive( char *path )
* Returns: 1 if ok, 0 on error.
*/
HsInt
-loadObj( char *path )
+loadObj( pathchar *path )
{
ObjectCode* oc;
char *image;
int fileSize;
- struct stat st;
+ struct_stat st;
int r;
#ifdef USE_MMAP
int fd;
@@ -2117,7 +2148,7 @@ loadObj( char *path )
int misalignment;
# endif
#endif
- IF_DEBUG(linker, debugBelch("loadObj %s\n", path));
+ IF_DEBUG(linker, debugBelch("loadObj %" PATH_FMT "\n", path));
initLinker();
@@ -2129,7 +2160,7 @@ loadObj( char *path )
ObjectCode *o;
int is_dup = 0;
for (o = objects; o; o = o->next) {
- if (0 == strcmp(o->fileName, path)) {
+ if (0 == pathcmp(o->fileName, path)) {
is_dup = 1;
break; /* don't need to search further */
}
@@ -2138,14 +2169,14 @@ loadObj( char *path )
IF_DEBUG(linker, debugBelch(
"GHCi runtime linker: warning: looks like you're trying to load the\n"
"same object file twice:\n"
- " %s\n"
+ " %" PATH_FMT "\n"
"GHCi will ignore this, but be warned.\n"
, path));
return 1; /* success */
}
}
- r = stat(path, &st);
+ r = pathstat(path, &st);
if (r == -1) {
IF_DEBUG(linker, debugBelch("File doesn't exist\n"));
return 0;
@@ -2170,9 +2201,9 @@ loadObj( char *path )
#else /* !USE_MMAP */
/* load the image into memory */
- f = fopen(path, "rb");
+ f = pathopen(path, WSTR("rb"));
if (!f)
- barf("loadObj: can't read `%s'", path);
+ barf("loadObj: can't read `%" PATH_FMT "'", path);
# if defined(mingw32_HOST_OS)
// TODO: We would like to use allocateExec here, but allocateExec
@@ -2310,7 +2341,7 @@ resolveObjs( void )
* delete an object from the pool
*/
HsInt
-unloadObj( char *path )
+unloadObj( pathchar *path )
{
ObjectCode *oc, *prev;
HsBool unloadedAnyObj = HS_BOOL_FALSE;
@@ -2322,7 +2353,7 @@ unloadObj( char *path )
prev = NULL;
for (oc = objects; oc; prev = oc, oc = oc->next) {
- if (!strcmp(oc->fileName,path)) {
+ if (!pathcmp(oc->fileName,path)) {
/* Remove all the mappings for the symbols within this
* object..
@@ -2365,7 +2396,7 @@ unloadObj( char *path )
return 1;
}
else {
- errorBelch("unloadObj: can't find `%s' to unload", path);
+ errorBelch("unloadObj: can't find `%" PATH_FMT "' to unload", path);
return 0;
}
}
@@ -2938,23 +2969,23 @@ ocVerifyImage_PEi386 ( ObjectCode* oc )
+ hdr->NumberOfSymbols * sizeof_COFF_symbol;
if (hdr->Machine != 0x14c) {
- errorBelch("%s: Not x86 PEi386", oc->fileName);
+ errorBelch("%" PATH_FMT ": Not x86 PEi386", oc->fileName);
return 0;
}
if (hdr->SizeOfOptionalHeader != 0) {
- errorBelch("%s: PEi386 with nonempty optional header", oc->fileName);
+ errorBelch("%" PATH_FMT ": PEi386 with nonempty optional header", oc->fileName);
return 0;
}
if ( /* (hdr->Characteristics & MYIMAGE_FILE_RELOCS_STRIPPED) || */
(hdr->Characteristics & MYIMAGE_FILE_EXECUTABLE_IMAGE) ||
(hdr->Characteristics & MYIMAGE_FILE_DLL) ||
(hdr->Characteristics & MYIMAGE_FILE_SYSTEM) ) {
- errorBelch("%s: Not a PEi386 object file", oc->fileName);
+ errorBelch("%" PATH_FMT ": Not a PEi386 object file", oc->fileName);
return 0;
}
if ( (hdr->Characteristics & MYIMAGE_FILE_BYTES_REVERSED_HI)
/* || !(hdr->Characteristics & MYIMAGE_FILE_32BIT_MACHINE) */ ) {
- errorBelch("%s: Invalid PEi386 word size or endiannness: %d",
+ errorBelch("%" PATH_FMT ": Invalid PEi386 word size or endiannness: %d",
oc->fileName,
(int)(hdr->Characteristics));
return 0;
@@ -3229,7 +3260,7 @@ ocGetNames_PEi386 ( ObjectCode* oc )
&& 0!= strcmp(".reloc", (char*)secname)
&& 0 != strcmp(".rdata$zzz", (char*)secname)
) {
- errorBelch("Unknown PEi386 section name `%s' (while processing: %s)", secname, oc->fileName);
+ errorBelch("Unknown PEi386 section name `%s' (while processing: %" PATH_FMT")", secname, oc->fileName);
stgFree(secname);
return 0;
}
@@ -3448,7 +3479,7 @@ ocResolve_PEi386 ( ObjectCode* oc )
COFF_section* section_sym
= findPEi386SectionCalled ( oc, sym->Name );
if (!section_sym) {
- errorBelch("%s: can't find section `%s'", oc->fileName, sym->Name);
+ errorBelch("%" PATH_FMT ": can't find section `%s'", oc->fileName, sym->Name);
return 0;
}
S = ((UInt32)(oc->image))
@@ -3458,7 +3489,7 @@ ocResolve_PEi386 ( ObjectCode* oc )
copyName ( sym->Name, strtab, symbol, 1000-1 );
S = (UInt32) lookupSymbol( (char*)symbol );
if ((void*)S != NULL) goto foundit;
- errorBelch("%s: unknown symbol `%s'", oc->fileName, symbol);
+ errorBelch("%" PATH_FMT ": unknown symbol `%s'", oc->fileName, symbol);
return 0;
foundit:;
}
@@ -3496,7 +3527,7 @@ ocResolve_PEi386 ( ObjectCode* oc )
*pP = S - ((UInt32)pP) - 4 + A;
break;
default:
- debugBelch("%s: unhandled PEi386 relocation type %d",
+ debugBelch("%" PATH_FMT ": unhandled PEi386 relocation type %d",
oc->fileName, reltab_j->Type);
return 0;
}
@@ -3504,7 +3535,7 @@ ocResolve_PEi386 ( ObjectCode* oc )
}
}
- IF_DEBUG(linker, debugBelch("completed %s", oc->fileName));
+ IF_DEBUG(linker, debugBelch("completed %" PATH_FMT, oc->fileName));
return 1;
}
@@ -4735,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]];
@@ -4752,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);
@@ -4779,7 +4812,8 @@ resolveImports(
return 1;
}
-static unsigned long relocateAddress(
+static unsigned long
+relocateAddress(
ObjectCode* oc,
int nSections,
struct section* sections,
@@ -4802,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,
@@ -4827,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];
@@ -4840,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)
{
@@ -4868,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));
}
}