X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=ghc%2Frts%2FLinker.c;h=85d5809210524e1540380b85c3a5129bd699d6ef;hb=920a3de7d913f9f369ffb8e5f0892ef7c9aeacde;hp=28adf49140a15f27db32339b1ef247c4fd9453dd;hpb=42dbb063e04ad00e2da7d29b65a27e8dcee0a0cb;p=ghc-hetmet.git diff --git a/ghc/rts/Linker.c b/ghc/rts/Linker.c index 28adf49..85d5809 100644 --- a/ghc/rts/Linker.c +++ b/ghc/rts/Linker.c @@ -1,5 +1,4 @@ /* ----------------------------------------------------------------------------- - * $Id: Linker.c,v 1.125 2003/07/20 21:28:04 panne Exp $ * * (c) The GHC Team, 2000-2003 * @@ -59,7 +58,7 @@ #include #endif -#if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS) || defined(freebsd_TARGET_OS) || defined(netbsd_TARGET_OS) +#if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS) || defined(freebsd_TARGET_OS) || defined(netbsd_TARGET_OS) || defined(openbsd_TARGET_OS) # define OBJFORMAT_ELF #elif defined(cygwin32_TARGET_OS) || defined (mingw32_TARGET_OS) # define OBJFORMAT_PEi386 @@ -71,6 +70,7 @@ # include # include # include +# include #endif /* Hash table mapping symbol names to Symbol */ @@ -88,6 +88,7 @@ static int ocVerifyImage_PEi386 ( ObjectCode* oc ); static int ocGetNames_PEi386 ( ObjectCode* oc ); static int ocResolve_PEi386 ( ObjectCode* oc ); #elif defined(OBJFORMAT_MACHO) +static int ocAllocateJumpIslands_MachO ( ObjectCode* oc ); static int ocVerifyImage_MachO ( ObjectCode* oc ); static int ocGetNames_MachO ( ObjectCode* oc ); static int ocResolve_MachO ( ObjectCode* oc ); @@ -228,6 +229,7 @@ typedef struct _RtsSymbolVal { #define RTS_MINGW_ONLY_SYMBOLS \ SymX(asyncReadzh_fast) \ SymX(asyncWritezh_fast) \ + SymX(asyncDoProczh_fast) \ SymX(memset) \ SymX(inet_ntoa) \ SymX(inet_addr) \ @@ -368,17 +370,20 @@ typedef struct _RtsSymbolVal { SymX(divExactIntegerzh_fast) \ SymX(divModIntegerzh_fast) \ SymX(forkzh_fast) \ - SymX(forkProcesszh_fast) \ + SymX(forkProcess) \ + SymX(forkOS_createThread) \ SymX(freeHaskellFunctionPtr) \ SymX(freeStablePtr) \ SymX(gcdIntegerzh_fast) \ SymX(gcdIntegerIntzh_fast) \ SymX(gcdIntzh_fast) \ + SymX(genSymZh) \ SymX(getProgArgv) \ SymX(getStablePtr) \ SymX(int2Integerzh_fast) \ SymX(integer2Intzh_fast) \ SymX(integer2Wordzh_fast) \ + SymX(isCurrentThreadBoundzh_fast) \ SymX(isDoubleDenormalized) \ SymX(isDoubleInfinite) \ SymX(isDoubleNaN) \ @@ -420,6 +425,7 @@ typedef struct _RtsSymbolVal { SymX(rts_eval) \ SymX(rts_evalIO) \ SymX(rts_evalLazyIO) \ + SymX(rts_evalStableIO) \ SymX(rts_eval_) \ SymX(rts_getBool) \ SymX(rts_getChar) \ @@ -453,7 +459,10 @@ typedef struct _RtsSymbolVal { SymX(rts_mkWord64) \ SymX(rts_mkWord8) \ SymX(rts_unlock) \ + SymX(rtsSupportsBoundThreads) \ SymX(run_queue_hd) \ + SymX(__hscore_get_saved_termios) \ + SymX(__hscore_set_saved_termios) \ SymX(setProgArgv) \ SymX(startupHaskell) \ SymX(shutdownHaskell) \ @@ -545,6 +554,13 @@ typedef struct _RtsSymbolVal { #define RTS_LONG_LONG_SYMS /* nothing */ #endif +#ifdef HAVE_TERMIOS_H +#define RTS_TERMIOS_SYMS \ + Sym(saved_termios) +#else +#define RTS_TERMIOS_SYMS /* nothing */ +#endif + // 64-bit support functions in libgcc.a #if defined(__GNUC__) && SIZEOF_VOID_P <= 4 #define RTS_LIBGCC_SYMBOLS \ @@ -586,6 +602,7 @@ RTS_LONG_LONG_SYMS RTS_POSIX_ONLY_SYMBOLS RTS_MINGW_ONLY_SYMBOLS RTS_CYGWIN_ONLY_SYMBOLS +RTS_TERMIOS_SYMS RTS_LIBGCC_SYMBOLS #undef Sym #undef SymX @@ -736,6 +753,7 @@ addDLL( char *dll_name ) initLinker(); hdl= dlopen(dll_name, RTLD_NOW | RTLD_GLOBAL); + if (hdl == NULL) { /* dlopen failed; return a ptr to the error msg. */ errmsg = dlerror(); @@ -814,8 +832,15 @@ lookupSymbol( char *lbl ) val = lookupStrHashTable(symhash, lbl); if (val == NULL) { -# if defined(OBJFORMAT_ELF) || defined(OBJFORMAT_MACHO) +# if defined(OBJFORMAT_ELF) return dlsym(dl_prog_handle, lbl); +# elif defined(OBJFORMAT_MACHO) + if(NSIsSymbolNameDefined(lbl)) { + NSSymbol symbol = NSLookupAndBindSymbol(lbl); + return NSAddressOfSymbol(symbol); + } else { + return NULL; + } # elif defined(OBJFORMAT_PEi386) OpenedDLL* o_dll; void* sym; @@ -1029,6 +1054,11 @@ loadObj( char *path ) #endif /* USE_MMAP */ +# if defined(OBJFORMAT_MACHO) + r = ocAllocateJumpIslands_MachO ( oc ); + if (!r) { return r; } +#endif + /* verify the in-memory image */ # if defined(OBJFORMAT_ELF) r = ocVerifyImage_ELF ( oc ); @@ -1888,11 +1918,16 @@ ocResolve_PEi386 ( ObjectCode* oc ) * real count can be found in the first reloc entry. * * See Section 4.1 (last para) of the PE spec (rev6.0). + * + * Nov2003 update: the GNU linker still doesn't correctly + * handle the generation of relocatable object files with + * overflown relocations. Hence the output to warn of potential + * troubles. */ COFF_reloc* rel = (COFF_reloc*) myindex ( sizeof_COFF_reloc, reltab, 0 ); noRelocs = rel->VirtualAddress; - fprintf(stderr, "Overflown relocs: %u\n", noRelocs); + fprintf(stderr, "WARNING: Overflown relocation field (# relocs found: %u)\n", noRelocs); fflush(stderr); j = 1; } else { noRelocs = sectab_i->NumberOfRelocations; @@ -2004,6 +2039,9 @@ ocResolve_PEi386 ( ObjectCode* oc ) # define ELF_TARGET_SPARC /* Used inside */ #elif defined(i386_TARGET_ARCH) # define ELF_TARGET_386 /* Used inside */ +#elif defined(x86_64_TARGET_ARCH) +# define ELF_TARGET_X64_64 +# define ELF_64BIT #elif defined (ia64_TARGET_ARCH) # define ELF_TARGET_IA64 /* Used inside */ # define ELF_64BIT @@ -2012,7 +2050,15 @@ ocResolve_PEi386 ( ObjectCode* oc ) # define ELF_NEED_PLT /* needs Procedure Linkage Tables */ #endif +#if !defined(openbsd_TARGET_OS) #include +#else +/* openbsd elf has things in different places, with diff names */ +#include +#include +#define R_386_32 RELOC_32 +#define R_386_PC32 RELOC_PC32 +#endif /* * Define a set of types which can be used for both ELF32 and ELF64 @@ -2964,18 +3010,70 @@ ia64_reloc_pcrel21(Elf_Addr target, Elf_Addr value, ObjectCode *oc) #if defined(OBJFORMAT_MACHO) /* - Initial support for MachO linking on Darwin/MacOS X on PowerPC chips + Support for MachO linking on Darwin/MacOS X on PowerPC chips by Wolfgang Thaller (wolfgang.thaller@gmx.net) I hereby formally apologize for the hackish nature of this code. Things that need to be done: - *) get common symbols and .bss sections to work properly. - Haskell modules seem to work, but C modules can cause problems *) implement ocVerifyImage_MachO - *) add more sanity checks. The current code just has to segfault if there's a - broken .o file. + *) add still more sanity checks. +*/ + + +/* + ocAllocateJumpIslands_MachO + + Allocate additional space at the end of the object file image to make room + for jump islands. + + PowerPC relative branch instructions have a 24 bit displacement field. + As PPC code is always 4-byte-aligned, this yields a +-32MB range. + If a particular imported symbol is outside this range, we have to redirect + the jump to a short piece of new code that just loads the 32bit absolute + address and jumps there. + This function just allocates space for one 16 byte jump island for every + undefined symbol in the object file. The code for the islands is filled in by + makeJumpIsland below. */ +static const int islandSize = 16; + +static int ocAllocateJumpIslands_MachO(ObjectCode* oc) +{ + char *image = (char*) oc->image; + struct mach_header *header = (struct mach_header*) image; + struct load_command *lc = (struct load_command*) (image + sizeof(struct mach_header)); + unsigned i; + + for(i=0;incmds;i++) + { + if(lc->cmd == LC_DYSYMTAB) + { + struct dysymtab_command *dsymLC = (struct dysymtab_command*) lc; + unsigned long nundefsym = dsymLC->nundefsym; + oc->island_start_symbol = dsymLC->iundefsym; + oc->n_islands = nundefsym; + + if(nundefsym > 0) + { +#ifdef USE_MMAP + #error ocAllocateJumpIslands_MachO doesnt want USE_MMAP to be defined +#else + oc->image = stgReallocBytes( + image, oc->fileSize + islandSize * nundefsym, + "ocAllocateJumpIslands_MachO"); +#endif + oc->jump_islands = oc->image + oc->fileSize; + memset(oc->jump_islands, 0, islandSize * nundefsym); + } + + break; // there can be only one LC_DSYMTAB + } + lc = (struct load_command *) ( ((char*)lc) + lc->cmdsize ); + } + return 1; +} + static int ocVerifyImage_MachO(ObjectCode* oc) { // FIXME: do some verifying here @@ -3012,15 +3110,63 @@ static int resolveImports( return 0; } ASSERT(addr); + checkProddableBlock(oc,((void**)(image + sect->offset)) + i); ((void**)(image + sect->offset))[i] = addr; } return 1; } -static int relocateSection(char *image, +static void* makeJumpIsland( + ObjectCode* oc, + unsigned long symbolNumber, + void* target) +{ + if(symbolNumber < oc->island_start_symbol || + symbolNumber - oc->island_start_symbol > oc->n_islands) + return NULL; + symbolNumber -= oc->island_start_symbol; + + void *island = (void*) ((char*)oc->jump_islands + islandSize * symbolNumber); + unsigned long *p = (unsigned long*) island; + + // lis r12, hi16(target) + *p++ = 0x3d800000 | ( ((unsigned long) target) >> 16 ); + // ori r12, r12, lo16(target) + *p++ = 0x618c0000 | ( ((unsigned long) target) & 0xFFFF ); + // mtctr r12 + *p++ = 0x7d8903a6; + // bctr + *p++ = 0x4e800420; + + return (void*) island; +} + +static char* relocateAddress( + ObjectCode* oc, + int nSections, + struct section* sections, + unsigned long address) +{ + int i; + for(i = 0; i < nSections; i++) + { + if(sections[i].addr <= address + && address < sections[i].addr + sections[i].size) + { + return oc->image + sections[i].offset + address - sections[i].addr; + } + } + barf("Invalid Mach-O file:" + "Address out of bounds while relocating object file"); + return NULL; +} + +static int relocateSection( + ObjectCode* oc, + char *image, struct symtab_command *symLC, struct nlist *nlist, - struct section* sections, struct section *sect) + int nSections, struct section* sections, struct section *sect) { struct relocation_info *relocs; int i,n; @@ -3042,11 +3188,55 @@ static int relocateSection(char *image, if(!scat->r_pcrel) { - if(scat->r_length == 2 && scat->r_type == GENERIC_RELOC_VANILLA) + if(scat->r_length == 2) { - unsigned long* word = (unsigned long*) (image + sect->offset + scat->r_address); + unsigned long word = 0; + unsigned long* wordPtr = (unsigned long*) (image + sect->offset + scat->r_address); + checkProddableBlock(oc,wordPtr); - *word = scat->r_value + sect->offset + ((long) image); + // Step 1: Figure out what the relocated value should be + if(scat->r_type == GENERIC_RELOC_VANILLA) + { + word = scat->r_value + sect->offset + ((long) image); + } + else if(scat->r_type == PPC_RELOC_SECTDIFF + || scat->r_type == PPC_RELOC_LO16_SECTDIFF + || scat->r_type == PPC_RELOC_HI16_SECTDIFF + || scat->r_type == PPC_RELOC_HA16_SECTDIFF) + { + struct scattered_relocation_info *pair = + (struct scattered_relocation_info*) &relocs[i+1]; + + if(!pair->r_scattered || pair->r_type != PPC_RELOC_PAIR) + barf("Invalid Mach-O file: " + "PPC_RELOC_*_SECTDIFF not followed by PPC_RELOC_PAIR"); + + word = (unsigned long) + (relocateAddress(oc, nSections, sections, scat->r_value) + - relocateAddress(oc, nSections, sections, pair->r_value)); + i++; + } + else + continue; // ignore the others + + if(scat->r_type == GENERIC_RELOC_VANILLA + || scat->r_type == PPC_RELOC_SECTDIFF) + { + *wordPtr = word; + } + else if(scat->r_type == PPC_RELOC_LO16_SECTDIFF) + { + ((unsigned short*) wordPtr)[1] = word & 0xFFFF; + } + else if(scat->r_type == PPC_RELOC_HI16_SECTDIFF) + { + ((unsigned short*) wordPtr)[1] = (word >> 16) & 0xFFFF; + } + else if(scat->r_type == PPC_RELOC_HA16_SECTDIFF) + { + ((unsigned short*) wordPtr)[1] = ((word >> 16) & 0xFFFF) + + ((word & (1<<15)) ? 1 : 0); + } } } @@ -3061,8 +3251,11 @@ static int relocateSection(char *image, if(reloc->r_length == 2) { unsigned long word = 0; - + unsigned long jumpIsland = 0; + long offsetToJumpIsland; + unsigned long* wordPtr = (unsigned long*) (image + sect->offset + reloc->r_address); + checkProddableBlock(oc,wordPtr); if(reloc->r_type == GENERIC_RELOC_VANILLA) { @@ -3111,7 +3304,15 @@ static int relocateSection(char *image, } if(reloc->r_pcrel) + { + jumpIsland = (long) makeJumpIsland(oc,reloc->r_symbolnum,(void*)word); word -= ((long)image) + sect->offset + reloc->r_address; + if(jumpIsland != 0) + { + offsetToJumpIsland = jumpIsland + - (((long)image) + sect->offset + reloc->r_address); + } + } } if(reloc->r_type == GENERIC_RELOC_VANILLA) @@ -3137,6 +3338,19 @@ static int relocateSection(char *image, } else if(reloc->r_type == PPC_RELOC_BR24) { + if((long)word > (long)0x01FFFFFF || (long)word < (long)0xFFE00000) + { + // The branch offset is too large. + // Therefore, we try to use a jump island. + if(jumpIsland == 0) + barf("unconditional relative branch out of range: " + "no jump island available"); + + word = offsetToJumpIsland; + if((long)word > (long)0x01FFFFFF || (long)word < (long)0xFFE00000) + barf("unconditional relative branch out of range: " + "jump island out of range"); + } *wordPtr = (*wordPtr & 0xFC000003) | (word & 0x03FFFFFC); continue; } @@ -3155,7 +3369,7 @@ static int ocGetNames_MachO(ObjectCode* oc) struct load_command *lc = (struct load_command*) (image + sizeof(struct mach_header)); unsigned i,curSymbol; struct segment_command *segLC = NULL; - struct section *sections, *la_ptrs = NULL, *nl_ptrs = NULL; + struct section *sections; struct symtab_command *symLC = NULL; struct dysymtab_command *dsymLC = NULL; struct nlist *nlist; @@ -3179,13 +3393,17 @@ static int ocGetNames_MachO(ObjectCode* oc) for(i=0;insects;i++) { - if(!strcmp(sections[i].sectname,"__la_symbol_ptr")) - la_ptrs = §ions[i]; - else if(!strcmp(sections[i].sectname,"__nl_symbol_ptr")) - nl_ptrs = §ions[i]; - - // for now, only add __text and __const to the sections table - else if(!strcmp(sections[i].sectname,"__text")) + if(sections[i].size == 0) + continue; + + if((sections[i].flags & SECTION_TYPE) == S_ZEROFILL) + { + char * zeroFillArea = stgCallocBytes(1,sections[i].size, + "ocGetNames_MachO(common symbols)"); + sections[i].offset = zeroFillArea - image; + } + + if(!strcmp(sections[i].sectname,"__text")) addSection(oc, SECTIONKIND_CODE_OR_RODATA, (void*) (image + sections[i].offset), (void*) (image + sections[i].offset + sections[i].size)); @@ -3197,6 +3415,14 @@ static int ocGetNames_MachO(ObjectCode* oc) addSection(oc, SECTIONKIND_RWDATA, (void*) (image + sections[i].offset), (void*) (image + sections[i].offset + sections[i].size)); + else if(!strcmp(sections[i].sectname,"__bss") + || !strcmp(sections[i].sectname,"__common")) + addSection(oc, SECTIONKIND_RWDATA, + (void*) (image + sections[i].offset), + (void*) (image + sections[i].offset + sections[i].size)); + + addProddableBlock(oc, (void*) (image + sections[i].offset), + sections[i].size); } // count external symbols defined here @@ -3313,13 +3539,30 @@ static int ocResolve_MachO(ObjectCode* oc) for(i=0;insects;i++) { - if(!relocateSection(image,symLC,nlist,sections,§ions[i])) + if(!relocateSection(oc,image,symLC,nlist,segLC->nsects,sections,§ions[i])) return 0; } /* Free the local symbol table; we won't need it again. */ freeHashTable(oc->lochash, NULL); oc->lochash = NULL; + + /* + Flush the data & instruction caches. + Because the PPC has split data/instruction caches, we have to + do that whenever we modify code at runtime. + */ + { + int n = (oc->fileSize + islandSize * oc->n_islands) / 4; + unsigned long *p = (unsigned long*)oc->image; + while(n--) + { + __asm__ volatile ("dcbf 0,%0\n\tsync\n\ticbi 0,%0" + : : "r" (p)); + p++; + } + __asm__ volatile ("sync\n\tisync"); + } return 1; }