# include <windows.h>
# include <math.h>
#elif defined(darwin_HOST_OS)
-# include <mach-o/ppc/reloc.h>
# define OBJFORMAT_MACHO
# include <mach-o/loader.h>
# include <mach-o/nlist.h>
# include <mach-o/reloc.h>
# include <mach-o/dyld.h>
+#if defined(powerpc_HOST_ARCH)
+# include <mach-o/ppc/reloc.h>
+#endif
#endif
/* Hash table mapping symbol names to Symbol */
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
#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()
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 */
};
ghciInsertStrHashTable("(GHCi built-in symbols)",
symhash, sym->lbl, sym->addr);
}
-# if defined(OBJFORMAT_MACHO)
+# if defined(OBJFORMAT_MACHO) && defined(powerpc_HOST_ARCH)
machoInitSymbolsWithoutUnderscore();
# endif
void *map_addr = NULL;
#else
FILE *f;
+ int misalignment;
#endif
-
initLinker();
/* debugBelch("loadObj %s\n", 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);
#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)
+ 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
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' (while processing: %s)", sectab_i->Name, oc->fileName);
return 0;
/* 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 ) {
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.
*/
*pP = S - ((UInt32)pP) - 4 + A;
break;
{
Elf64_Xword w1, w2;
int slot = (Elf_Addr)target & 3;
- (Elf_Addr)target &= ~3;
+ target = (Elf_Addr)target & ~3;
w1 = *target;
w2 = *(target+1);
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)
{
#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.
*) add still more sanity checks.
*/
+#ifdef powerpc_HOST_ARCH
static int ocAllocateJumpIslands_MachO(ObjectCode* oc)
{
struct mach_header *header = (struct mach_header *) oc->image;
}
return ocAllocateJumpIslands(oc,0,0);
}
+#endif
static int ocVerifyImage_MachO(ObjectCode* oc STG_UNUSED)
{
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);
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)
{
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
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;
((unsigned short*) wordPtr)[1] = ((word >> 16) & 0xFFFF)
+ ((word & (1<<15)) ? 1 : 0);
}
+#endif
}
}
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);
{
word = *wordPtr;
}
+#ifdef powerpc_HOST_ARCH
else if(reloc->r_type == PPC_RELOC_LO16)
{
word = ((unsigned short*) wordPtr)[1];
word = *wordPtr;
word = (word & 0x03FFFFFC) | ((word & 0x02000000) ? 0xFC000000 : 0);
}
-
+#endif
if(!reloc->r_extern)
{
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
{
*wordPtr = word;
continue;
}
+#ifdef powerpc_HOST_ARCH
else if(reloc->r_type == PPC_RELOC_LO16)
{
((unsigned short*) wordPtr)[1] = word & 0xFFFF;
*wordPtr = (*wordPtr & 0xFC000003) | (word & 0x03FFFFFC);
continue;
}
- }
+#endif
+ }
barf("\nunknown relocation %d",reloc->r_type);
return 0;
}
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)
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
#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