X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=ghc%2Frts%2FLinker.c;h=cb685223fa68c181ed726d8886b484c809672636;hb=7bb0f34f7e8e75d19a730891de6fe76ce96860d5;hp=b0c3b564d5f0bcd060b848db31b4212657684601;hpb=9f627b3122604910e99641159f711efc5345eb9f;p=ghc-hetmet.git diff --git a/ghc/rts/Linker.c b/ghc/rts/Linker.c index b0c3b56..cb68522 100644 --- a/ghc/rts/Linker.c +++ b/ghc/rts/Linker.c @@ -78,12 +78,14 @@ # include # include #elif defined(darwin_HOST_OS) -# include # define OBJFORMAT_MACHO # include # include # include # include +#if defined(powerpc_HOST_ARCH) +# include +#endif #endif /* Hash table mapping symbol names to Symbol */ @@ -104,13 +106,16 @@ 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 ); +static int machoGetMisalignment( FILE * ); +#ifdef powerpc_HOST_ARCH +static int ocAllocateJumpIslands_MachO ( ObjectCode* oc ); static void machoInitSymbolsWithoutUnderscore( void ); #endif +#endif /* ----------------------------------------------------------------------------- * Built-in symbols from the RTS @@ -296,7 +301,8 @@ typedef struct _RtsSymbolVal { SymX(log) \ SymX(sqrt) \ SymX(memcpy) \ - SymX(stg_InstallConsoleEvent) \ + SymX(rts_InstallConsoleEvent) \ + SymX(rts_ConsoleHandlerDone) \ Sym(mktime) \ Sym(_imp___timezone) \ Sym(_imp___tzname) \ @@ -633,7 +639,7 @@ typedef struct _RtsSymbolVal { #define RTS_LIBGCC_SYMBOLS #endif -#ifdef darwin_HOST_OS +#if defined(darwin_HOST_OS) && defined(powerpc_HOST_ARCH) // Symbols that don't have a leading underscore // on Mac OS X. They have to receive special treatment, // see machoInitSymbolsWithoutUnderscore() @@ -681,6 +687,12 @@ static RtsSymbolVal rtsSyms[] = { RTS_MINGW_ONLY_SYMBOLS RTS_CYGWIN_ONLY_SYMBOLS RTS_LIBGCC_SYMBOLS +#if defined(darwin_HOST_OS) && defined(i386_HOST_ARCH) + // dyld stub code contains references to this, + // but it should never be called because we treat + // lazy pointers as nonlazy. + { "dyld_stub_binding_helper", (void*)0xDEADBEEF }, +#endif { 0, 0 } /* sentinel */ }; @@ -753,7 +765,7 @@ initLinker( void ) ghciInsertStrHashTable("(GHCi built-in symbols)", symhash, sym->lbl, sym->addr); } -# if defined(OBJFORMAT_MACHO) +# if defined(OBJFORMAT_MACHO) && defined(powerpc_HOST_ARCH) machoInitSymbolsWithoutUnderscore(); # endif @@ -1018,8 +1030,8 @@ loadObj( char *path ) void *map_addr = NULL; #else FILE *f; + int misalignment; #endif - initLinker(); /* debugBelch("loadObj %s\n", path ); */ @@ -1123,13 +1135,29 @@ loadObj( char *path ) #else /* !USE_MMAP */ - oc->image = stgMallocBytes(oc->fileSize, "loadObj(image)"); - /* load the image into memory */ f = fopen(path, "rb"); if (!f) barf("loadObj: can't read `%s'", path); +#ifdef darwin_HOST_OS + // In a Mach-O .o file, all sections can and will be misaligned + // if the total size of the headers is not a multiple of the + // desired alignment. This is fine for .o files that only serve + // as input for the static linker, but it's not fine for us, + // as SSE (used by gcc for floating point) and Altivec require + // 16-byte alignment. + // We calculate the correct alignment from the header before + // reading the file, and then we misalign oc->image on purpose so + // that the actual sections end up aligned again. + misalignment = machoGetMisalignment(f); +#else + misalignment = 0; +#endif + + oc->image = stgMallocBytes(oc->fileSize + misalignment, "loadObj(image)"); + oc->image += misalignment; + n = fread ( oc->image, 1, oc->fileSize, f ); if (n != oc->fileSize) barf("loadObj: error whilst reading `%s'", path); @@ -1138,7 +1166,7 @@ loadObj( char *path ) #endif /* USE_MMAP */ -# if defined(OBJFORMAT_MACHO) +# if defined(OBJFORMAT_MACHO) && defined(powerpc_HOST_ARCH) r = ocAllocateJumpIslands_MachO ( oc ); if (!r) { return r; } # elif defined(OBJFORMAT_ELF) && defined(powerpc_HOST_ARCH) @@ -1729,24 +1757,25 @@ ocVerifyImage_PEi386 ( ObjectCode* oc ) + hdr->NumberOfSymbols * sizeof_COFF_symbol; if (hdr->Machine != 0x14c) { - errorBelch("Not x86 PEi386"); + errorBelch("%s: Not x86 PEi386", oc->fileName); return 0; } if (hdr->SizeOfOptionalHeader != 0) { - errorBelch("PEi386 with nonempty optional header"); + errorBelch("%s: 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("Not a PEi386 object file"); + errorBelch("%s: Not a PEi386 object file", oc->fileName); return 0; } if ( (hdr->Characteristics & MYIMAGE_FILE_BYTES_REVERSED_HI) /* || !(hdr->Characteristics & MYIMAGE_FILE_32BIT_MACHINE) */ ) { - errorBelch("Invalid PEi386 word size or endiannness: %d", - (int)(hdr->Characteristics)); + errorBelch("%s: Invalid PEi386 word size or endiannness: %d", + oc->fileName, + (int)(hdr->Characteristics)); return 0; } /* If the string table size is way crazy, this might indicate that @@ -1962,6 +1991,7 @@ ocGetNames_PEi386 ( ObjectCode* oc ) # endif if (0==strcmp(".text",sectab_i->Name) || + 0==strcmp(".rdata",sectab_i->Name)|| 0==strcmp(".rodata",sectab_i->Name)) kind = SECTIONKIND_CODE_OR_RODATA; if (0==strcmp(".data",sectab_i->Name) || @@ -1980,8 +2010,10 @@ ocGetNames_PEi386 ( ObjectCode* oc ) information. */ && 0 != strcmp(".stab", sectab_i->Name) && 0 != strcmp(".stabstr", sectab_i->Name) + /* ignore constructor section for now */ + && 0 != strcmp(".ctors", sectab_i->Name) ) { - errorBelch("Unknown PEi386 section name `%s'", sectab_i->Name); + errorBelch("Unknown PEi386 section name `%s' (while processing: %s)", sectab_i->Name, oc->fileName); return 0; } @@ -2123,7 +2155,8 @@ ocResolve_PEi386 ( ObjectCode* oc ) /* Ignore sections called which contain stabs debugging information. */ if (0 == strcmp(".stab", sectab_i->Name) - || 0 == strcmp(".stabstr", sectab_i->Name)) + || 0 == strcmp(".stabstr", sectab_i->Name) + || 0 == strcmp(".ctors", sectab_i->Name)) continue; if ( sectab_i->Characteristics & MYIMAGE_SCN_LNK_NRELOC_OVFL ) { @@ -2220,9 +2253,22 @@ ocResolve_PEi386 ( ObjectCode* oc ) -- hence the constant 4. Also I don't know if A should be added, but so far it has always been zero. + + SOF 05/2005: 'A' (old contents of *pP) have been observed + to contain values other than zero (the 'wx' object file + that came with wxhaskell-0.9.4; dunno how it was compiled..). + So, add displacement to old value instead of asserting + A to be zero. Fixes wxhaskell-related crashes, and no other + ill effects have been observed. + + Update: the reason why we're seeing these more elaborate + relocations is due to a switch in how the NCG compiles SRTs + and offsets to them from info tables. SRTs live in .(ro)data, + while info tables live in .text, causing GAS to emit REL32/DISP32 + relocations with non-zero values. Adding the displacement is + the right thing to do. */ - ASSERT(A==0); - *pP = S - ((UInt32)pP) - 4; + *pP = S - ((UInt32)pP) - 4 + A; break; default: debugBelch("%s: unhandled PEi386 relocation type %d", @@ -3217,7 +3263,7 @@ ia64_extract_instruction(Elf64_Xword *target) { Elf64_Xword w1, w2; int slot = (Elf_Addr)target & 3; - (Elf_Addr)target &= ~3; + target = (Elf_Addr)target & ~3; w1 = *target; w2 = *(target+1); @@ -3239,7 +3285,7 @@ static void ia64_deposit_instruction(Elf64_Xword *target, Elf64_Xword value) { int slot = (Elf_Addr)target & 3; - (Elf_Addr)target &= ~3; + target = (Elf_Addr)target & ~3; switch (slot) { @@ -3342,7 +3388,7 @@ static int ocAllocateJumpIslands_ELF( ObjectCode *oc ) #if defined(OBJFORMAT_MACHO) /* - Support for MachO linking on Darwin/MacOS X on PowerPC chips + Support for MachO linking on Darwin/MacOS X by Wolfgang Thaller (wolfgang.thaller@gmx.net) I hereby formally apologize for the hackish nature of this code. @@ -3351,6 +3397,7 @@ static int ocAllocateJumpIslands_ELF( ObjectCode *oc ) *) add still more sanity checks. */ +#ifdef powerpc_HOST_ARCH static int ocAllocateJumpIslands_MachO(ObjectCode* oc) { struct mach_header *header = (struct mach_header *) oc->image; @@ -3395,6 +3442,7 @@ static int ocAllocateJumpIslands_MachO(ObjectCode* oc) } return ocAllocateJumpIslands(oc,0,0); } +#endif static int ocVerifyImage_MachO(ObjectCode* oc STG_UNUSED) { @@ -3473,6 +3521,10 @@ static int relocateSection( return 1; else if(!strcmp(sect->sectname,"__nl_symbol_ptr")) return 1; + else if(!strcmp(sect->sectname,"__la_sym_ptr2")) + return 1; + else if(!strcmp(sect->sectname,"__la_sym_ptr3")) + return 1; n = sect->nreloc; relocs = (struct relocation_info*) (image + sect->reloff); @@ -3492,6 +3544,15 @@ static int relocateSection( unsigned long* wordPtr = (unsigned long*) (image + sect->offset + scat->r_address); checkProddableBlock(oc,wordPtr); + // Note on relocation types: + // i386 uses the GENERIC_RELOC_* types, + // while ppc uses special PPC_RELOC_* types. + // *_RELOC_VANILLA and *_RELOC_PAIR have the same value + // in both cases, all others are different. + // Therefore, we use GENERIC_RELOC_VANILLA + // and GENERIC_RELOC_PAIR instead of the PPC variants, + // and use #ifdefs for the other types. + // Step 1: Figure out what the relocated value should be if(scat->r_type == GENERIC_RELOC_VANILLA) { @@ -3502,23 +3563,28 @@ static int relocateSection( scat->r_value) - scat->r_value; } +#ifdef powerpc_HOST_ARCH 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) +#else + else if(scat->r_type == GENERIC_RELOC_SECTDIFF) +#endif { struct scattered_relocation_info *pair = (struct scattered_relocation_info*) &relocs[i+1]; - if(!pair->r_scattered || pair->r_type != PPC_RELOC_PAIR) + if(!pair->r_scattered || pair->r_type != GENERIC_RELOC_PAIR) barf("Invalid Mach-O file: " - "PPC_RELOC_*_SECTDIFF not followed by PPC_RELOC_PAIR"); + "RELOC_*_SECTDIFF not followed by RELOC_PAIR"); word = (unsigned long) (relocateAddress(oc, nSections, sections, scat->r_value) - relocateAddress(oc, nSections, sections, pair->r_value)); i++; } +#ifdef powerpc_HOST_ARCH else if(scat->r_type == PPC_RELOC_HI16 || scat->r_type == PPC_RELOC_LO16 || scat->r_type == PPC_RELOC_HA16 @@ -3557,14 +3623,21 @@ static int relocateSection( i++; } + #endif else continue; // ignore the others +#ifdef powerpc_HOST_ARCH if(scat->r_type == GENERIC_RELOC_VANILLA || scat->r_type == PPC_RELOC_SECTDIFF) +#else + if(scat->r_type == GENERIC_RELOC_VANILLA + || scat->r_type == GENERIC_RELOC_SECTDIFF) +#endif { *wordPtr = word; } +#ifdef powerpc_HOST_ARCH else if(scat->r_type == PPC_RELOC_LO16_SECTDIFF || scat->r_type == PPC_RELOC_LO16) { ((unsigned short*) wordPtr)[1] = word & 0xFFFF; @@ -3578,6 +3651,7 @@ static int relocateSection( ((unsigned short*) wordPtr)[1] = ((word >> 16) & 0xFFFF) + ((word & (1<<15)) ? 1 : 0); } +#endif } } @@ -3592,10 +3666,12 @@ static int relocateSection( if(reloc->r_length == 2) { unsigned long word = 0; +#ifdef powerpc_HOST_ARCH unsigned long jumpIsland = 0; long offsetToJumpIsland = 0xBADBAD42; // initialise to bad value // to avoid warning and to catch // bugs. +#endif unsigned long* wordPtr = (unsigned long*) (image + sect->offset + reloc->r_address); checkProddableBlock(oc,wordPtr); @@ -3604,6 +3680,7 @@ static int relocateSection( { word = *wordPtr; } +#ifdef powerpc_HOST_ARCH else if(reloc->r_type == PPC_RELOC_LO16) { word = ((unsigned short*) wordPtr)[1]; @@ -3624,7 +3701,7 @@ static int relocateSection( word = *wordPtr; word = (word & 0x03FFFFFC) | ((word & 0x02000000) ? 0xFC000000 : 0); } - +#endif if(!reloc->r_extern) { @@ -3648,17 +3725,19 @@ static int relocateSection( if(reloc->r_pcrel) { +#ifdef powerpc_HOST_ARCH // In the .o file, this should be a relative jump to NULL - // and we'll change it to a jump to a relative jump to the symbol + // and we'll change it to a relative jump to the symbol ASSERT(-word == reloc->r_address); - word = (unsigned long) symbolAddress; - jumpIsland = makeJumpIsland(oc,reloc->r_symbolnum,word); - word -= ((long)image) + sect->offset + reloc->r_address; + jumpIsland = makeJumpIsland(oc,reloc->r_symbolnum,(unsigned long) symbolAddress); if(jumpIsland != 0) { - offsetToJumpIsland = jumpIsland - - (((long)image) + sect->offset + reloc->r_address); + offsetToJumpIsland = word + jumpIsland + - (((long)image) + sect->offset - sect->addr); } +#endif + word += (unsigned long) symbolAddress + - (((long)image) + sect->offset - sect->addr); } else { @@ -3671,6 +3750,7 @@ static int relocateSection( *wordPtr = word; continue; } +#ifdef powerpc_HOST_ARCH else if(reloc->r_type == PPC_RELOC_LO16) { ((unsigned short*) wordPtr)[1] = word & 0xFFFF; @@ -3707,7 +3787,8 @@ static int relocateSection( *wordPtr = (*wordPtr & 0xFC000003) | (word & 0x03FFFFFC); continue; } - } +#endif + } barf("\nunknown relocation %d",reloc->r_type); return 0; } @@ -3889,6 +3970,10 @@ static int ocResolve_MachO(ObjectCode* oc) la_ptrs = §ions[i]; else if(!strcmp(sections[i].sectname,"__nl_symbol_ptr")) nl_ptrs = §ions[i]; + else if(!strcmp(sections[i].sectname,"__la_sym_ptr2")) + la_ptrs = §ions[i]; + else if(!strcmp(sections[i].sectname,"__la_sym_ptr3")) + la_ptrs = §ions[i]; } if(dsymLC) @@ -3921,6 +4006,7 @@ static int ocResolve_MachO(ObjectCode* oc) return 1; } +#ifdef powerpc_HOST_ARCH /* * The Mach-O object format uses leading underscores. But not everywhere. * There is a small number of runtime support functions defined in @@ -3953,3 +4039,26 @@ static void machoInitSymbolsWithoutUnderscore() #undef Sym } #endif + +/* + * Figure out by how much to shift the entire Mach-O file in memory + * when loading so that its single segment ends up 16-byte-aligned + */ +static int machoGetMisalignment( FILE * f ) +{ + struct mach_header header; + int misalignment; + + fread(&header, sizeof(header), 1, f); + rewind(f); + + if(header.magic != MH_MAGIC) + return 0; + + misalignment = (header.sizeofcmds + sizeof(header)) + & 0xF; + + return misalignment ? (16 - misalignment) : 0; +} + +#endif