X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=rts%2FLinker.c;h=d2fb4f7a5d06969e68c41868842ac2bdd992746d;hb=be895313ba42d0bff295a2d4dbc1c5b388a3e760;hp=0bbd869386b3a969616336e1c2e3d87369ed6290;hpb=dea74f1966c4ccaa765911baa11749335d35b2aa;p=ghc-hetmet.git diff --git a/rts/Linker.c b/rts/Linker.c index 0bbd869..d2fb4f7 100644 --- a/rts/Linker.c +++ b/rts/Linker.c @@ -13,8 +13,8 @@ /* Linux needs _GNU_SOURCE to get RTLD_DEFAULT from and MREMAP_MAYMOVE from . */ -#ifdef __linux__ -#define _GNU_SOURCE +#if defined(__linux__) || defined(__GLIBC__) +#define _GNU_SOURCE 1 #endif #include "Rts.h" @@ -40,6 +40,7 @@ #include #endif +#include #include #include #include @@ -72,7 +73,8 @@ #if defined(linux_HOST_OS ) || defined(freebsd_HOST_OS) || \ defined(dragonfly_HOST_OS) || defined(netbsd_HOST_OS ) || \ defined(openbsd_HOST_OS ) || \ - ( defined(darwin_HOST_OS ) && !defined(powerpc_HOST_ARCH) ) + ( defined(darwin_HOST_OS ) && !defined(powerpc_HOST_ARCH) ) || \ + defined(kfreebsdgnu_HOST_OS) /* Don't use mmap on powerpc-apple-darwin as mmap doesn't support * reallocating but we need to allocate jump islands just after each * object images. Otherwise relative branches to jump islands can fail @@ -88,7 +90,7 @@ #endif -#if defined(linux_HOST_OS) || defined(solaris2_HOST_OS) || defined(freebsd_HOST_OS) || defined(dragonfly_HOST_OS) || defined(netbsd_HOST_OS) || defined(openbsd_HOST_OS) +#if defined(linux_HOST_OS) || defined(solaris2_HOST_OS) || defined(freebsd_HOST_OS) || defined(kfreebsdgnu_HOST_OS) || defined(dragonfly_HOST_OS) || defined(netbsd_HOST_OS) || defined(openbsd_HOST_OS) # define OBJFORMAT_ELF # include // regex is already used by dlopen() so this is OK // to use here without requiring an additional lib @@ -270,6 +272,7 @@ typedef struct _RtsSymbolVal { SymI_HasProto(signal_handlers) \ SymI_HasProto(stg_sig_install) \ SymI_HasProto(rtsTimerSignal) \ + SymI_HasProto(atexit) \ SymI_NeedsProto(nocldstop) #endif @@ -979,7 +982,7 @@ typedef struct _RtsSymbolVal { SymI_HasProto(stg_yieldzh) \ SymI_NeedsProto(stg_interp_constr_entry) \ SymI_HasProto(stg_arg_bitmaps) \ - SymI_HasProto(alloc_blocks_lim) \ + SymI_HasProto(large_alloc_lim) \ SymI_HasProto(g0) \ SymI_HasProto(allocate) \ SymI_HasProto(allocateExec) \ @@ -1562,6 +1565,7 @@ mmapForLinker (size_t bytes, nat flags, int fd) int pagesize, size; static nat fixed = 0; + IF_DEBUG(linker, debugBelch("mmapForLinker: start\n")); pagesize = getpagesize(); size = ROUND_UP(bytes, pagesize); @@ -1573,6 +1577,8 @@ mmap_again: } #endif + IF_DEBUG(linker, debugBelch("mmapForLinker: \tprotection %#0x\n", PROT_EXEC | PROT_READ | PROT_WRITE)); + IF_DEBUG(linker, debugBelch("mmapForLinker: \tflags %#0x\n", MAP_PRIVATE | TRY_MAP_32BIT | fixed | flags)); result = mmap(map_addr, size, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_PRIVATE|TRY_MAP_32BIT|fixed|flags, fd, 0); @@ -1589,7 +1595,7 @@ mmap_again: } else { if ((W_)result > 0x80000000) { // oops, we were given memory over 2Gb -#if defined(freebsd_HOST_OS) || defined(dragonfly_HOST_OS) +#if defined(freebsd_HOST_OS) || defined(kfreebsdgnu_HOST_OS) || defined(dragonfly_HOST_OS) // Some platforms require MAP_FIXED. This is normally // a bad idea, because MAP_FIXED will overwrite // existing mappings. @@ -1620,6 +1626,8 @@ mmap_again: } #endif + IF_DEBUG(linker, debugBelch("mmapForLinker: mapped %lu bytes starting at %p\n", (lnat)size, result)); + IF_DEBUG(linker, debugBelch("mmapForLinker: done\n")); return result; } #endif // USE_MMAP @@ -1635,6 +1643,7 @@ mkOc( char *path, char *image, int imageSize, ) { ObjectCode* oc; + IF_DEBUG(linker, debugBelch("mkOc: start\n")); oc = stgMallocBytes(sizeof(ObjectCode), "loadArchive(oc)"); # if defined(OBJFORMAT_ELF) @@ -1676,6 +1685,7 @@ mkOc( char *path, char *image, int imageSize, oc->next = objects; objects = oc; + IF_DEBUG(linker, debugBelch("mkOc: done\n")); return oc; } @@ -1698,6 +1708,7 @@ loadArchive( char *path ) int misalignment; #endif + IF_DEBUG(linker, debugBelch("loadArchive: start\n")); IF_DEBUG(linker, debugBelch("loadArchive: Loading archive `%s'\n", path)); gnuFileIndex = NULL; @@ -1711,19 +1722,32 @@ loadArchive( char *path ) barf("loadObj: can't read `%s'", path); n = fread ( tmp, 1, 8, f ); - if (strncmp(tmp, "!\n", 8) != 0) + if (strncmp(tmp, "!\n", 8) != 0) { barf("loadArchive: Not an archive: `%s'", path); + } + + IF_DEBUG(linker, debugBelch("loadArchive: loading archive contents\n")); while(1) { n = fread ( fileName, 1, 16, f ); if (n != 16) { if (feof(f)) { + IF_DEBUG(linker, debugBelch("loadArchive: EOF while reading from '%s'\n", path)); break; } else { barf("loadArchive: Failed reading file name from `%s'", path); } } +#if defined(darwin_HOST_OS) + else { + if (strncmp(fileName, "!\n", 8) == 0) { + IF_DEBUG(linker, debugBelch("loadArchive: found the start of another archive, breaking\n")); + break; + } + } +#endif + n = fread ( tmp, 1, 12, f ); if (n != 12) barf("loadArchive: Failed reading mod time from `%s'", path); @@ -1743,6 +1767,8 @@ loadArchive( char *path ) for (n = 0; isdigit(tmp[n]); n++); tmp[n] = '\0'; memberSize = atoi(tmp); + + IF_DEBUG(linker, debugBelch("loadArchive: size of this archive member is %d\n", memberSize)); n = fread ( tmp, 1, 2, f ); if (strncmp(tmp, "\x60\x0A", 2) != 0) barf("loadArchive: Failed reading magic from `%s' at %ld. Got %c%c", @@ -1769,6 +1795,11 @@ loadArchive( char *path ) path); } fileName[thisFileNameSize] = 0; + + /* On OS X at least, thisFileNameSize is the size of the + fileName field, not the length of the fileName + itself. */ + thisFileNameSize = strlen(fileName); } else { barf("loadArchive: BSD-variant filename size not found while reading filename from `%s'", path); @@ -1854,6 +1885,9 @@ loadArchive( char *path ) && fileName[thisFileNameSize - 2] == '.' && fileName[thisFileNameSize - 1] == 'o'; + IF_DEBUG(linker, debugBelch("loadArchive: \tthisFileNameSize = %d\n", (int)thisFileNameSize)); + IF_DEBUG(linker, debugBelch("loadArchive: \tisObject = %d\n", isObject)); + if (isObject) { char *archiveMemberName; @@ -1919,23 +1953,29 @@ loadArchive( char *path ) gnuFileIndexSize = memberSize; } else { + IF_DEBUG(linker, debugBelch("loadArchive: '%s' does not appear to be an object file\n", fileName)); n = fseek(f, memberSize, SEEK_CUR); if (n != 0) barf("loadArchive: error whilst seeking by %d in `%s'", memberSize, path); } + /* .ar files are 2-byte aligned */ if (memberSize % 2) { + IF_DEBUG(linker, debugBelch("loadArchive: trying to read one pad byte\n")); n = fread ( tmp, 1, 1, f ); if (n != 1) { if (feof(f)) { + IF_DEBUG(linker, debugBelch("loadArchive: found EOF while reading one pad byte\n")); break; } else { barf("loadArchive: Failed reading padding from `%s'", path); } } + IF_DEBUG(linker, debugBelch("loadArchive: successfully read one pad byte\n")); } + IF_DEBUG(linker, debugBelch("loadArchive: reached end of archive loading while loop\n")); } fclose(f); @@ -1949,6 +1989,7 @@ loadArchive( char *path ) #endif } + IF_DEBUG(linker, debugBelch("loadArchive: done\n")); return 1; } @@ -2076,18 +2117,18 @@ static HsInt loadOc( ObjectCode* oc ) { int r; - IF_DEBUG(linker, debugBelch("loadOc\n")); + IF_DEBUG(linker, debugBelch("loadOc: start\n")); # if defined(OBJFORMAT_MACHO) && (defined(powerpc_HOST_ARCH) || defined(x86_64_HOST_ARCH)) r = ocAllocateSymbolExtras_MachO ( oc ); if (!r) { - IF_DEBUG(linker, debugBelch("ocAllocateSymbolExtras_MachO failed\n")); + IF_DEBUG(linker, debugBelch("loadOc: ocAllocateSymbolExtras_MachO failed\n")); return r; } # elif defined(OBJFORMAT_ELF) && (defined(powerpc_HOST_ARCH) || defined(x86_64_HOST_ARCH)) r = ocAllocateSymbolExtras_ELF ( oc ); if (!r) { - IF_DEBUG(linker, debugBelch("ocAllocateSymbolExtras_ELF failed\n")); + IF_DEBUG(linker, debugBelch("loadOc: ocAllocateSymbolExtras_ELF failed\n")); return r; } #endif @@ -2103,7 +2144,7 @@ loadOc( ObjectCode* oc ) { barf("loadObj: no verify method"); # endif if (!r) { - IF_DEBUG(linker, debugBelch("ocVerifyImage_* failed\n")); + IF_DEBUG(linker, debugBelch("loadOc: ocVerifyImage_* failed\n")); return r; } @@ -2118,13 +2159,13 @@ loadOc( ObjectCode* oc ) { barf("loadObj: no getNames method"); # endif if (!r) { - IF_DEBUG(linker, debugBelch("ocGetNames_* failed\n")); + IF_DEBUG(linker, debugBelch("loadOc: ocGetNames_* failed\n")); return r; } /* loaded, but not resolved yet */ oc->status = OBJECT_LOADED; - IF_DEBUG(linker, debugBelch("loadObj done.\n")); + IF_DEBUG(linker, debugBelch("loadOc: done.\n")); return 1; } @@ -2230,11 +2271,13 @@ unloadObj( char *path ) * which may be prodded during relocation, and abort if we try and write * outside any of these. */ -static void addProddableBlock ( ObjectCode* oc, void* start, int size ) +static void +addProddableBlock ( ObjectCode* oc, void* start, int size ) { ProddableBlock* pb = stgMallocBytes(sizeof(ProddableBlock), "addProddableBlock"); - IF_DEBUG(linker, debugBelch("addProddableBlock %p %p %d\n", oc, start, size)); + + IF_DEBUG(linker, debugBelch("addProddableBlock: %p %p %d\n", oc, start, size)); ASSERT(size > 0); pb->start = start; pb->size = size; @@ -2242,9 +2285,11 @@ static void addProddableBlock ( ObjectCode* oc, void* start, int size ) oc->proddables = pb; } -static void checkProddableBlock ( ObjectCode* oc, void* addr ) +static void +checkProddableBlock (ObjectCode *oc, void *addr ) { ProddableBlock* pb; + for (pb = oc->proddables; pb != NULL; pb = pb->next) { char* s = (char*)(pb->start); char* e = s + pb->size - 1; @@ -2260,7 +2305,8 @@ static void checkProddableBlock ( ObjectCode* oc, void* addr ) /* ----------------------------------------------------------------------------- * Section management. */ -static void addSection ( ObjectCode* oc, SectionKind kind, +static void +addSection ( ObjectCode* oc, SectionKind kind, void* start, void* end ) { Section* s = stgMallocBytes(sizeof(Section), "addSection"); @@ -2269,10 +2315,9 @@ static void addSection ( ObjectCode* oc, SectionKind kind, s->kind = kind; s->next = oc->sections; oc->sections = s; - /* - debugBelch("addSection: %p-%p (size %d), kind %d\n", - start, ((char*)end)-1, end - start + 1, kind ); - */ + + IF_DEBUG(linker, debugBelch("addSection: %p-%p (size %ld), kind %d\n", + start, ((char*)end)-1, (long)end - (long)start + 1, kind )); } @@ -2413,7 +2458,9 @@ static SymbolExtra* makeSymbolExtra( ObjectCode* oc, Because the PPC has split data/instruction caches, we have to do that whenever we modify code at runtime. */ -static void ocFlushInstructionCacheFrom(void* begin, size_t length) + +static void +ocFlushInstructionCacheFrom(void* begin, size_t length) { size_t n = (length + 3) / 4; unsigned long* p = begin; @@ -2432,7 +2479,9 @@ static void ocFlushInstructionCacheFrom(void* begin, size_t length) "isync" ); } -static void ocFlushInstructionCache( ObjectCode *oc ) + +static void +ocFlushInstructionCache( ObjectCode *oc ) { /* The main object code */ ocFlushInstructionCacheFrom(oc->image + oc->misalignment, oc->fileSize); @@ -2440,7 +2489,8 @@ static void ocFlushInstructionCache( ObjectCode *oc ) /* Jump Islands */ ocFlushInstructionCacheFrom(oc->symbol_extras, sizeof(SymbolExtra) * oc->n_symbol_extras); } -#endif +#endif /* powerpc_HOST_ARCH */ + /* -------------------------------------------------------------------------- * PEi386 specifics (Win32 targets) @@ -4410,79 +4460,100 @@ static int ocAllocateSymbolExtras_ELF( ObjectCode *oc ) #endif #ifdef powerpc_HOST_ARCH -static int ocAllocateSymbolExtras_MachO(ObjectCode* oc) +static int +ocAllocateSymbolExtras_MachO(ObjectCode* oc) { struct mach_header *header = (struct mach_header *) oc->image; struct load_command *lc = (struct load_command *) (header + 1); unsigned i; - for( i = 0; i < header->ncmds; i++ ) - { - if( lc->cmd == LC_SYMTAB ) - { + IF_DEBUG(linker, debugBelch("ocAllocateSymbolExtras_MachO: start\n")); + + for (i = 0; i < header->ncmds; i++) { + if (lc->cmd == LC_SYMTAB) { + // Find out the first and last undefined external // symbol, so we don't have to allocate too many - // jump islands. + // jump islands/GOT entries. + struct symtab_command *symLC = (struct symtab_command *) lc; unsigned min = symLC->nsyms, max = 0; struct nlist *nlist = symLC ? (struct nlist*) ((char*) oc->image + symLC->symoff) : NULL; - for(i=0;insyms;i++) - { - if(nlist[i].n_type & N_STAB) + + for (i = 0; i < symLC->nsyms; i++) { + + if (nlist[i].n_type & N_STAB) { ; - else if(nlist[i].n_type & N_EXT) - { + } else if (nlist[i].n_type & N_EXT) { + if((nlist[i].n_type & N_TYPE) == N_UNDF - && (nlist[i].n_value == 0)) - { - if(i < min) + && (nlist[i].n_value == 0)) { + + if (i < min) { min = i; - if(i > max) + } + + if (i > max) { max = i; } } } - if(max >= min) + } + + if (max >= min) { return ocAllocateSymbolExtras(oc, max - min + 1, min); + } break; } lc = (struct load_command *) ( ((char *)lc) + lc->cmdsize ); } + return ocAllocateSymbolExtras(oc,0,0); } + #endif #ifdef x86_64_HOST_ARCH -static int ocAllocateSymbolExtras_MachO(ObjectCode* oc) +static int +ocAllocateSymbolExtras_MachO(ObjectCode* oc) { struct mach_header *header = (struct mach_header *) oc->image; struct load_command *lc = (struct load_command *) (header + 1); unsigned i; - for( i = 0; i < header->ncmds; i++ ) - { - if( lc->cmd == LC_SYMTAB ) - { + IF_DEBUG(linker, debugBelch("ocAllocateSymbolExtras_MachO: start\n")); + + for (i = 0; i < header->ncmds; i++) { + if (lc->cmd == LC_SYMTAB) { + // Just allocate one entry for every symbol struct symtab_command *symLC = (struct symtab_command *) lc; + IF_DEBUG(linker, debugBelch("ocAllocateSymbolExtras_MachO: allocate %d symbols\n", symLC->nsyms)); + IF_DEBUG(linker, debugBelch("ocAllocateSymbolExtras_MachO: done\n")); return ocAllocateSymbolExtras(oc, symLC->nsyms, 0); } lc = (struct load_command *) ( ((char *)lc) + lc->cmdsize ); } + + IF_DEBUG(linker, debugBelch("ocAllocateSymbolExtras_MachO: allocated no symbols\n")); + IF_DEBUG(linker, debugBelch("ocAllocateSymbolExtras_MachO: done\n")); return ocAllocateSymbolExtras(oc,0,0); } #endif -static int ocVerifyImage_MachO(ObjectCode* oc) +static int +ocVerifyImage_MachO(ObjectCode * oc) { char *image = (char*) oc->image; struct mach_header *header = (struct mach_header*) image; + IF_DEBUG(linker, debugBelch("ocVerifyImage_MachO: start\n")); + #if x86_64_HOST_ARCH || powerpc64_HOST_ARCH if(header->magic != MH_MAGIC_64) { errorBelch("%s: Bad magic. Expected: %08x, got: %08x.\n", @@ -4496,11 +4567,14 @@ static int ocVerifyImage_MachO(ObjectCode* oc) return 0; } #endif + // FIXME: do some more verifying here + IF_DEBUG(linker, debugBelch("ocVerifyImage_MachO: done\n")); return 1; } -static int resolveImports( +static int +resolveImports( ObjectCode* oc, char *image, struct symtab_command *symLC, @@ -4515,12 +4589,13 @@ static int resolveImports( #if i386_HOST_ARCH int isJumpTable = 0; - if(!strcmp(sect->sectname,"__jump_table")) - { + + if (strcmp(sect->sectname,"__jump_table") == 0) { isJumpTable = 1; itemSize = 5; ASSERT(sect->reserved2 == itemSize); } + #endif for(i=0; i*itemSize < sect->size;i++) @@ -4531,6 +4606,7 @@ static int resolveImports( void *addr = NULL; IF_DEBUG(linker, debugBelch("resolveImports: resolving %s\n", nm)); + if ((symbol->n_type & N_TYPE) == N_UNDF && (symbol->n_type & N_EXT) && (symbol->n_value != 0)) { addr = (void*) (symbol->n_value); @@ -4547,10 +4623,10 @@ static int resolveImports( ASSERT(addr); #if i386_HOST_ARCH - if(isJumpTable) - { + if (isJumpTable) { checkProddableBlock(oc,image + sect->offset + i*itemSize); - *(image + sect->offset + i*itemSize) = 0xe9; // jmp + + *(image + sect->offset + i * itemSize) = 0xe9; // jmp opcode *(unsigned*)(image + sect->offset + i*itemSize + 1) = (char*)addr - (image + sect->offset + i*itemSize + 5); } @@ -4651,8 +4727,8 @@ static int relocateSection( } IF_DEBUG(linker, - debugBelch("relocateSection: length = %d, thing = %d, baseValue = %p\n", - reloc->r_length, thing, baseValue)); + debugBelch("relocateSection: length = %d, thing = %" PRId64 ", baseValue = %p\n", + reloc->r_length, thing, (char *)baseValue)); if (type == X86_64_RELOC_GOT || type == X86_64_RELOC_GOT_LOAD) @@ -4688,9 +4764,12 @@ static int relocateSection( } else { - value = sections[reloc->r_symbolnum-1].offset - - sections[reloc->r_symbolnum-1].addr - + (uint64_t) image; + // If the relocation is not through the global offset table + // or external, then set the value to the baseValue. This + // will leave displacements into the __const section + // unchanged (as they ought to be). + + value = baseValue; } IF_DEBUG(linker, debugBelch("relocateSection: value = %p\n", (void *)value));