summaryrefslogtreecommitdiff
path: root/rts/Linker.c
diff options
context:
space:
mode:
authorBen Gamari <bgamari.foss@gmail.com>2016-11-02 15:02:25 -0400
committerBen Gamari <ben@smart-cactus.org>2016-11-02 15:42:00 -0400
commitf6c47df34acee1b906146a6e54665192d02d15b6 (patch)
tree0c2ad983616d206047420d16896b3da0b77e9ff4 /rts/Linker.c
parent6ea0b4f1a6a0478eeeacb0a7be62e426d4aa58e5 (diff)
downloadhaskell-f6c47df34acee1b906146a6e54665192d02d15b6.tar.gz
linker: Split MachO implementation into new source file
Test Plan: Validate Reviewers: erikd, austin, simonmar Reviewed By: simonmar Subscribers: thomie Differential Revision: https://phabricator.haskell.org/D2649
Diffstat (limited to 'rts/Linker.c')
-rw-r--r--rts/Linker.c1227
1 files changed, 1 insertions, 1226 deletions
diff --git a/rts/Linker.c b/rts/Linker.c
index 3a10bb39b9..7b4753e0ea 100644
--- a/rts/Linker.c
+++ b/rts/Linker.c
@@ -67,18 +67,10 @@
# include <windows.h>
#elif defined(darwin_HOST_OS)
# define OBJFORMAT_MACHO
+# include "linker/MachO.h"
# include <regex.h>
# include <mach/machine.h>
# include <mach-o/fat.h>
-# include <mach-o/loader.h>
-# include <mach-o/nlist.h>
-# include <mach-o/reloc.h>
-#if defined(powerpc_HOST_ARCH)
-# include <mach-o/ppc/reloc.h>
-#endif
-#if defined(x86_64_HOST_ARCH)
-# include <mach-o/x86_64/reloc.h>
-#endif
#endif
#if defined(x86_64_HOST_ARCH) && defined(darwin_HOST_OS)
@@ -204,19 +196,6 @@ static int ocRunInit_ELF ( ObjectCode* oc );
#if NEED_SYMBOL_EXTRAS
static int ocAllocateSymbolExtras_ELF ( ObjectCode* oc );
#endif
-
-#elif defined(OBJFORMAT_MACHO)
-static int ocVerifyImage_MachO ( ObjectCode* oc );
-static int ocGetNames_MachO ( ObjectCode* oc );
-static int ocResolve_MachO ( ObjectCode* oc );
-static int ocRunInit_MachO ( ObjectCode* oc );
-static int machoGetMisalignment( FILE * );
-#if NEED_SYMBOL_EXTRAS
-static int ocAllocateSymbolExtras_MachO ( ObjectCode* oc );
-#endif
-#ifdef powerpc_HOST_ARCH
-static void machoInitSymbolsWithoutUnderscore( void );
-#endif
#endif
/* on x86_64 we have a problem with relocating symbol references in
@@ -3986,1207 +3965,3 @@ static int ocAllocateSymbolExtras_ELF( ObjectCode *oc )
* Mach-O specifics
* ------------------------------------------------------------------------*/
-#if defined(OBJFORMAT_MACHO)
-
-/*
- 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.
- Things that need to be done:
- *) implement ocVerifyImage_MachO
- *) add still more sanity checks.
-*/
-
-#if x86_64_HOST_ARCH || powerpc64_HOST_ARCH
-#define mach_header mach_header_64
-#define segment_command segment_command_64
-#define section section_64
-#define nlist nlist_64
-#endif
-
-#ifdef powerpc_HOST_ARCH
-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;
-
- 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/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; i < symLC->nsyms; i++) {
-
- if (nlist[i].n_type & N_STAB) {
- ;
- } 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) {
- min = i;
- }
-
- if (i > max) {
- max = i;
- }
- }
- }
- }
-
- 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)
-{
- struct mach_header *header = (struct mach_header *) oc->image;
- struct load_command *lc = (struct load_command *) (header + 1);
- unsigned i;
-
- 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)
-{
- 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("Could not load image %s: bad magic!\n"
- " Expected %08x (64bit), got %08x%s\n",
- oc->fileName, MH_MAGIC_64, header->magic,
- header->magic == MH_MAGIC ? " (32bit)." : ".");
- return 0;
- }
-#else
- if(header->magic != MH_MAGIC) {
- errorBelch("Could not load image %s: bad magic!\n"
- " Expected %08x (32bit), got %08x%s\n",
- oc->fileName, MH_MAGIC, header->magic,
- header->magic == MH_MAGIC_64 ? " (64bit)." : ".");
- return 0;
- }
-#endif
-
- // FIXME: do some more verifying here
- IF_DEBUG(linker, debugBelch("ocVerifyImage_MachO: done\n"));
- return 1;
-}
-
-static int
-resolveImports(
- ObjectCode* oc,
- char *image,
- struct symtab_command *symLC,
- struct section *sect, // ptr to lazy or non-lazy symbol pointer section
- unsigned long *indirectSyms,
- struct nlist *nlist)
-{
- unsigned i;
- size_t itemSize = 4;
-
- IF_DEBUG(linker, debugBelch("resolveImports: start\n"));
-
-#if i386_HOST_ARCH
- int isJumpTable = 0;
-
- if (strcmp(sect->sectname,"__jump_table") == 0) {
- isJumpTable = 1;
- itemSize = 5;
- ASSERT(sect->reserved2 == itemSize);
- }
-
-#endif
-
- 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]];
- SymbolName* nm = image + symLC->stroff + symbol->n_un.n_strx;
- SymbolAddr* 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 = (SymbolAddr*) (symbol->n_value);
- IF_DEBUG(linker, debugBelch("resolveImports: undefined external %s has value %p\n", nm, addr));
- } else {
- addr = lookupSymbol_(nm);
- IF_DEBUG(linker, debugBelch("resolveImports: looking up %s, %p\n", nm, addr));
- }
-
- if (addr == NULL)
- {
- errorBelch("\nlookupSymbol failed in resolveImports\n"
- "%s: unknown symbol `%s'", oc->fileName, nm);
- return 0;
- }
- ASSERT(addr);
-
-#if i386_HOST_ARCH
- if (isJumpTable) {
- checkProddableBlock(oc,image + sect->offset + i*itemSize, 5);
-
- *(image + sect->offset + i * itemSize) = 0xe9; // jmp opcode
- *(unsigned*)(image + sect->offset + i*itemSize + 1)
- = (SymbolAddr*)addr - (image + sect->offset + i*itemSize + 5);
- }
- else
-#endif
- {
- checkProddableBlock(oc,
- ((void**)(image + sect->offset)) + i,
- sizeof(void *));
- ((void**)(image + sect->offset))[i] = addr;
- }
- }
-
- IF_DEBUG(linker, debugBelch("resolveImports: done\n"));
- return 1;
-}
-
-static unsigned long
-relocateAddress(
- ObjectCode* oc,
- int nSections,
- struct section* sections,
- unsigned long address)
-{
- int i;
- IF_DEBUG(linker, debugBelch("relocateAddress: start\n"));
- for (i = 0; i < nSections; i++)
- {
- IF_DEBUG(linker, debugBelch(" relocating address in section %d\n", i));
- if (sections[i].addr <= address
- && address < sections[i].addr + sections[i].size)
- {
- return (unsigned long)oc->image
- + sections[i].offset + address - sections[i].addr;
- }
- }
- barf("Invalid Mach-O file:"
- "Address out of bounds while relocating object file");
- return 0;
-}
-
-static int
-relocateSection(
- ObjectCode* oc,
- char *image,
- struct symtab_command *symLC, struct nlist *nlist,
- int nSections, struct section* sections, struct section *sect)
-{
- struct relocation_info *relocs;
- int i, n;
-
- IF_DEBUG(linker, debugBelch("relocateSection: start\n"));
-
- if(!strcmp(sect->sectname,"__la_symbol_ptr"))
- 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;
- IF_DEBUG(linker, debugBelch("relocateSection: number of relocations: %d\n", n));
-
- relocs = (struct relocation_info*) (image + sect->reloff);
-
- for(i = 0; i < n; i++)
- {
-#ifdef x86_64_HOST_ARCH
- struct relocation_info *reloc = &relocs[i];
-
- char *thingPtr = image + sect->offset + reloc->r_address;
- uint64_t thing;
- /* We shouldn't need to initialise this, but gcc on OS X 64 bit
- complains that it may be used uninitialized if we don't */
- uint64_t value = 0;
- 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));
-
- switch(reloc->r_length)
- {
- case 0:
- checkProddableBlock(oc,thingPtr,1);
- thing = *(uint8_t*)thingPtr;
- baseValue = (uint64_t)thingPtr + 1;
- break;
- case 1:
- checkProddableBlock(oc,thingPtr,2);
- thing = *(uint16_t*)thingPtr;
- baseValue = (uint64_t)thingPtr + 2;
- break;
- case 2:
- checkProddableBlock(oc,thingPtr,4);
- thing = *(uint32_t*)thingPtr;
- baseValue = (uint64_t)thingPtr + 4;
- break;
- case 3:
- checkProddableBlock(oc,thingPtr,8);
- thing = *(uint64_t*)thingPtr;
- baseValue = (uint64_t)thingPtr + 8;
- break;
- default:
- barf("Unknown size.");
- }
-
- IF_DEBUG(linker,
- 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)
- {
- struct nlist *symbol = &nlist[reloc->r_symbolnum];
- SymbolName* nm = image + symLC->stroff + symbol->n_un.n_strx;
- SymbolAddr* 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);
- 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)
- {
- struct nlist *symbol = &nlist[reloc->r_symbolnum];
- SymbolName* nm = image + symLC->stroff + symbol->n_un.n_strx;
- SymbolAddr* 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 {
- 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));
- }
- }
- else
- {
- // 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));
-
- if (type == X86_64_RELOC_BRANCH)
- {
- if((int32_t)(value - baseValue) != (int64_t)(value - baseValue))
- {
- ASSERT(reloc->r_extern);
- value = (uint64_t) &makeSymbolExtra(oc, reloc->r_symbolnum, value)
- -> jumpIsland;
- }
- ASSERT((int32_t)(value - baseValue) == (int64_t)(value - baseValue));
- type = X86_64_RELOC_SIGNED;
- }
-
- switch(type)
- {
- case X86_64_RELOC_UNSIGNED:
- ASSERT(!reloc->r_pcrel);
- thing += value;
- break;
- case X86_64_RELOC_SIGNED:
- case X86_64_RELOC_SIGNED_1:
- case X86_64_RELOC_SIGNED_2:
- case X86_64_RELOC_SIGNED_4:
- ASSERT(reloc->r_pcrel);
- thing += value - baseValue;
- break;
- case X86_64_RELOC_SUBTRACTOR:
- ASSERT(!reloc->r_pcrel);
- thing -= value;
- break;
- default:
- barf("unkown relocation");
- }
-
- switch(reloc->r_length)
- {
- case 0:
- *(uint8_t*)thingPtr = thing;
- break;
- case 1:
- *(uint16_t*)thingPtr = thing;
- break;
- case 2:
- *(uint32_t*)thingPtr = thing;
- break;
- case 3:
- *(uint64_t*)thingPtr = thing;
- break;
- }
-#else
- if(relocs[i].r_address & R_SCATTERED)
- {
- struct scattered_relocation_info *scat =
- (struct scattered_relocation_info*) &relocs[i];
-
- if(!scat->r_pcrel)
- {
- if(scat->r_length == 2)
- {
- unsigned long word = 0;
- unsigned long* wordPtr = (unsigned long*) (image + sect->offset + scat->r_address);
-
- /* In this check we assume that sizeof(unsigned long) = 2 * sizeof(unsigned short)
- on powerpc_HOST_ARCH */
- checkProddableBlock(oc,wordPtr,sizeof(unsigned long));
-
- // 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) {
- word = *wordPtr
- + (unsigned long) relocateAddress(oc,
- nSections,
- sections,
- 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
- || scat->r_type == PPC_RELOC_LOCAL_SECTDIFF)
-#else
- else if(scat->r_type == GENERIC_RELOC_SECTDIFF
- || scat->r_type == GENERIC_RELOC_LOCAL_SECTDIFF)
-#endif
- {
- struct scattered_relocation_info *pair =
- (struct scattered_relocation_info*) &relocs[i+1];
-
- if (!pair->r_scattered || pair->r_type != GENERIC_RELOC_PAIR) {
- barf("Invalid Mach-O file: "
- "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
- || scat->r_type == PPC_RELOC_LO14)
- { // these are generated by label+offset things
- struct relocation_info *pair = &relocs[i+1];
-
- if ((pair->r_address & R_SCATTERED) || pair->r_type != PPC_RELOC_PAIR) {
- barf("Invalid Mach-O file: "
- "PPC_RELOC_* not followed by PPC_RELOC_PAIR");
- }
-
- if(scat->r_type == PPC_RELOC_LO16)
- {
- word = ((unsigned short*) wordPtr)[1];
- word |= ((unsigned long) relocs[i+1].r_address & 0xFFFF) << 16;
- }
- else if(scat->r_type == PPC_RELOC_LO14)
- {
- barf("Unsupported Relocation: PPC_RELOC_LO14");
- word = ((unsigned short*) wordPtr)[1] & 0xFFFC;
- word |= ((unsigned long) relocs[i+1].r_address & 0xFFFF) << 16;
- }
- else if(scat->r_type == PPC_RELOC_HI16)
- {
- word = ((unsigned short*) wordPtr)[1] << 16;
- word |= ((unsigned long) relocs[i+1].r_address & 0xFFFF);
- }
- else if(scat->r_type == PPC_RELOC_HA16)
- {
- word = ((unsigned short*) wordPtr)[1] << 16;
- word += ((short)relocs[i+1].r_address & (short)0xFFFF);
- }
-
-
- word += (unsigned long) relocateAddress(oc, nSections, sections, scat->r_value)
- - scat->r_value;
-
- i++;
- }
- #endif
- else {
- barf ("Don't know how to handle this Mach-O "
- "scattered relocation entry: "
- "object file %s; entry type %ld; "
- "address %#lx\n",
- OC_INFORMATIVE_FILENAME(oc),
- scat->r_type,
- scat->r_address);
- return 0;
- }
-
-#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
- || scat->r_type == GENERIC_RELOC_LOCAL_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;
- }
- else if (scat->r_type == PPC_RELOC_HI16_SECTDIFF
- || scat->r_type == PPC_RELOC_HI16)
- {
- ((unsigned short*) wordPtr)[1] = (word >> 16) & 0xFFFF;
- }
- else if (scat->r_type == PPC_RELOC_HA16_SECTDIFF
- || scat->r_type == PPC_RELOC_HA16)
- {
- ((unsigned short*) wordPtr)[1] = ((word >> 16) & 0xFFFF)
- + ((word & (1<<15)) ? 1 : 0);
- }
-#endif
- }
- else
- {
- barf("Can't handle Mach-O scattered relocation entry "
- "with this r_length tag: "
- "object file %s; entry type %ld; "
- "r_length tag %ld; address %#lx\n",
- OC_INFORMATIVE_FILENAME(oc),
- scat->r_type,
- scat->r_length,
- scat->r_address);
- return 0;
- }
- }
- else /* scat->r_pcrel */
- {
- barf("Don't know how to handle *PC-relative* Mach-O "
- "scattered relocation entry: "
- "object file %s; entry type %ld; address %#lx\n",
- OC_INFORMATIVE_FILENAME(oc),
- scat->r_type,
- scat->r_address);
- return 0;
- }
-
- }
- else /* !(relocs[i].r_address & R_SCATTERED) */
- {
- struct relocation_info *reloc = &relocs[i];
- if (reloc->r_pcrel && !reloc->r_extern) {
- IF_DEBUG(linker, debugBelch("relocateSection: pc relative but not external, skipping\n"));
- continue;
- }
-
- 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);
-
- /* In this check we assume that sizeof(unsigned long) = 2 * sizeof(unsigned short)
- on powerpc_HOST_ARCH */
- checkProddableBlock(oc,wordPtr, sizeof(unsigned long));
-
- if (reloc->r_type == GENERIC_RELOC_VANILLA) {
- word = *wordPtr;
- }
-#ifdef powerpc_HOST_ARCH
- else if (reloc->r_type == PPC_RELOC_LO16) {
- word = ((unsigned short*) wordPtr)[1];
- word |= ((unsigned long) relocs[i+1].r_address & 0xFFFF) << 16;
- }
- else if (reloc->r_type == PPC_RELOC_HI16) {
- word = ((unsigned short*) wordPtr)[1] << 16;
- word |= ((unsigned long) relocs[i+1].r_address & 0xFFFF);
- }
- else if (reloc->r_type == PPC_RELOC_HA16) {
- word = ((unsigned short*) wordPtr)[1] << 16;
- word += ((short)relocs[i+1].r_address & (short)0xFFFF);
- }
- else if (reloc->r_type == PPC_RELOC_BR24) {
- word = *wordPtr;
- word = (word & 0x03FFFFFC) | ((word & 0x02000000) ? 0xFC000000 : 0);
- }
-#endif
- else {
- barf("Can't handle this Mach-O relocation entry "
- "(not scattered): "
- "object file %s; entry type %ld; address %#lx\n",
- OC_INFORMATIVE_FILENAME(oc),
- reloc->r_type,
- reloc->r_address);
- return 0;
- }
-
- if (!reloc->r_extern) {
- long delta = sections[reloc->r_symbolnum-1].offset
- - sections[reloc->r_symbolnum-1].addr
- + ((long) image);
-
- word += delta;
- }
- else {
- struct nlist *symbol = &nlist[reloc->r_symbolnum];
- char *nm = image + symLC->stroff + symbol->n_un.n_strx;
- void *symbolAddress = lookupSymbol_(nm);
-
- if (!symbolAddress) {
- errorBelch("\nunknown symbol `%s'", nm);
- return 0;
- }
-
- 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 relative jump to the symbol
- ASSERT(word + reloc->r_address == 0);
- jumpIsland = (unsigned long)
- &makeSymbolExtra(oc,
- reloc->r_symbolnum,
- (unsigned long) symbolAddress)
- -> jumpIsland;
- if (jumpIsland != 0) {
- offsetToJumpIsland = word + jumpIsland
- - (((long)image) + sect->offset - sect->addr);
- }
-#endif
- word += (unsigned long) symbolAddress
- - (((long)image) + sect->offset - sect->addr);
- }
- else {
- word += (unsigned long) symbolAddress;
- }
- }
-
- if (reloc->r_type == GENERIC_RELOC_VANILLA) {
- *wordPtr = word;
- continue;
- }
-#ifdef powerpc_HOST_ARCH
- else if(reloc->r_type == PPC_RELOC_LO16)
- {
- ((unsigned short*) wordPtr)[1] = word & 0xFFFF;
- i++;
- continue;
- }
- else if(reloc->r_type == PPC_RELOC_HI16)
- {
- ((unsigned short*) wordPtr)[1] = (word >> 16) & 0xFFFF;
- i++;
- continue;
- }
- else if(reloc->r_type == PPC_RELOC_HA16)
- {
- ((unsigned short*) wordPtr)[1] = ((word >> 16) & 0xFFFF)
- + ((word & (1<<15)) ? 1 : 0);
- i++;
- continue;
- }
- else if(reloc->r_type == PPC_RELOC_BR24)
- {
- if ((word & 0x03) != 0) {
- barf("%s: unconditional relative branch with a displacement "
- "which isn't a multiple of 4 bytes: %#lx",
- OC_INFORMATIVE_FILENAME(oc),
- word);
- }
-
- if((word & 0xFE000000) != 0xFE000000 &&
- (word & 0xFE000000) != 0x00000000) {
- // The branch offset is too large.
- // Therefore, we try to use a jump island.
- if (jumpIsland == 0) {
- barf("%s: unconditional relative branch out of range: "
- "no jump island available: %#lx",
- OC_INFORMATIVE_FILENAME(oc),
- word);
- }
-
- word = offsetToJumpIsland;
-
- if((word & 0xFE000000) != 0xFE000000 &&
- (word & 0xFE000000) != 0x00000000) {
- barf("%s: unconditional relative branch out of range: "
- "jump island out of range: %#lx",
- OC_INFORMATIVE_FILENAME(oc),
- word);
- }
- }
- *wordPtr = (*wordPtr & 0xFC000003) | (word & 0x03FFFFFC);
- continue;
- }
-#endif
- }
- else
- {
- barf("Can't handle Mach-O relocation entry (not scattered) "
- "with this r_length tag: "
- "object file %s; entry type %ld; "
- "r_length tag %ld; address %#lx\n",
- OC_INFORMATIVE_FILENAME(oc),
- reloc->r_type,
- reloc->r_length,
- reloc->r_address);
- return 0;
- }
- }
-#endif
- }
-
- IF_DEBUG(linker, debugBelch("relocateSection: done\n"));
- return 1;
-}
-
-static int
-ocGetNames_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,curSymbol = 0;
- struct segment_command *segLC = NULL;
- struct section *sections;
- struct symtab_command *symLC = NULL;
- struct nlist *nlist;
- unsigned long commonSize = 0;
- SymbolAddr* commonStorage = NULL;
- unsigned long commonCounter;
-
- IF_DEBUG(linker,debugBelch("ocGetNames_MachO: start\n"));
-
- for(i=0;i<header->ncmds;i++)
- {
- if (lc->cmd == LC_SEGMENT || lc->cmd == LC_SEGMENT_64) {
- segLC = (struct segment_command*) lc;
- }
- else if (lc->cmd == LC_SYMTAB) {
- symLC = (struct symtab_command*) lc;
- }
-
- lc = (struct load_command *) ( ((char*)lc) + lc->cmdsize );
- }
-
- sections = (struct section*) (segLC+1);
- nlist = symLC ? (struct nlist*) (image + symLC->symoff)
- : NULL;
-
- if (!segLC) {
- barf("ocGetNames_MachO: no segment load command");
- }
-
- Section *secArray;
- secArray = (Section*)stgCallocBytes(
- sizeof(Section),
- segLC->nsects,
- "ocGetNames_MachO(sections)");
- oc->sections = secArray;
- oc->n_sections = segLC->nsects;
-
- IF_DEBUG(linker, debugBelch("ocGetNames_MachO: will load %d sections\n", segLC->nsects));
- for(i=0;i<segLC->nsects;i++)
- {
- IF_DEBUG(linker, debugBelch("ocGetNames_MachO: section %d\n", i));
-
- if (sections[i].size == 0) {
- IF_DEBUG(linker, debugBelch("ocGetNames_MachO: found a zero length section, skipping\n"));
- continue;
- }
-
- if((sections[i].flags & SECTION_TYPE) == S_ZEROFILL) {
- char * zeroFillArea;
- if (RTS_LINKER_USE_MMAP) {
- zeroFillArea = mmapForLinker(sections[i].size, MAP_ANONYMOUS,
- -1, 0);
- if (zeroFillArea == NULL) return 0;
- memset(zeroFillArea, 0, sections[i].size);
- }
- else {
- zeroFillArea = stgCallocBytes(1,sections[i].size,
- "ocGetNames_MachO(common symbols)");
- }
- sections[i].offset = zeroFillArea - image;
- }
-
- SectionKind kind = SECTIONKIND_OTHER;
-
- if (0==strcmp(sections[i].sectname,"__text")) {
- kind = SECTIONKIND_CODE_OR_RODATA;
- }
- else if (0==strcmp(sections[i].sectname,"__const") ||
- 0==strcmp(sections[i].sectname,"__data") ||
- 0==strcmp(sections[i].sectname,"__bss") ||
- 0==strcmp(sections[i].sectname,"__common") ||
- 0==strcmp(sections[i].sectname,"__mod_init_func")) {
- kind = SECTIONKIND_RWDATA;
- }
-
- addSection(&secArray[i], kind, SECTION_NOMEM,
- (void *)(image + sections[i].offset),
- sections[i].size,
- 0, 0, 0);
-
- addProddableBlock(oc,
- (void *) (image + sections[i].offset),
- sections[i].size);
- }
-
- // count external symbols defined here
- oc->n_symbols = 0;
- if (symLC) {
- for (i = 0; i < symLC->nsyms; i++) {
- if (nlist[i].n_type & N_STAB) {
- ;
- }
- else if(nlist[i].n_type & N_EXT)
- {
- if((nlist[i].n_type & N_TYPE) == N_UNDF
- && (nlist[i].n_value != 0))
- {
- commonSize += nlist[i].n_value;
- oc->n_symbols++;
- }
- else if((nlist[i].n_type & N_TYPE) == N_SECT)
- oc->n_symbols++;
- }
- }
- }
- IF_DEBUG(linker, debugBelch("ocGetNames_MachO: %d external symbols\n", oc->n_symbols));
- oc->symbols = stgMallocBytes(oc->n_symbols * sizeof(SymbolName*),
- "ocGetNames_MachO(oc->symbols)");
-
- if(symLC)
- {
- for(i=0;i<symLC->nsyms;i++)
- {
- if(nlist[i].n_type & N_STAB)
- ;
- else if((nlist[i].n_type & N_TYPE) == N_SECT)
- {
- if(nlist[i].n_type & N_EXT)
- {
- SymbolName* nm = image + symLC->stroff + nlist[i].n_un.n_strx;
- if ((nlist[i].n_desc & N_WEAK_DEF) && lookupSymbol_(nm)) {
- // weak definition, and we already have a definition
- IF_DEBUG(linker, debugBelch(" weak: %s\n", nm));
- }
- else
- {
- IF_DEBUG(linker, debugBelch("ocGetNames_MachO: inserting %s\n", nm));
- SymbolAddr* addr = image
- + sections[nlist[i].n_sect - 1].offset
- - sections[nlist[i].n_sect - 1].addr
- + nlist[i].n_value;
-
- ghciInsertSymbolTable( oc->fileName
- , symhash
- , nm
- , addr
- , HS_BOOL_FALSE
- , oc);
-
- oc->symbols[curSymbol] = nm;
- curSymbol++;
- }
- }
- else
- {
- IF_DEBUG(linker, debugBelch("ocGetNames_MachO: \t...not external, skipping\n"));
- }
- }
- else
- {
- IF_DEBUG(linker, debugBelch("ocGetNames_MachO: \t...not defined in this section, skipping\n"));
- }
- }
- }
-
- commonStorage = stgCallocBytes(1,commonSize,"ocGetNames_MachO(common symbols)");
- commonCounter = (unsigned long)commonStorage;
-
- if (symLC) {
- for (i = 0; i < symLC->nsyms; i++) {
- if((nlist[i].n_type & N_TYPE) == N_UNDF
- && (nlist[i].n_type & N_EXT)
- && (nlist[i].n_value != 0)) {
-
- SymbolName* nm = image + symLC->stroff + nlist[i].n_un.n_strx;
- unsigned long sz = nlist[i].n_value;
-
- nlist[i].n_value = commonCounter;
-
- IF_DEBUG(linker, debugBelch("ocGetNames_MachO: inserting common symbol: %s\n", nm));
- ghciInsertSymbolTable(oc->fileName, symhash, nm,
- (void*)commonCounter, HS_BOOL_FALSE, oc);
- oc->symbols[curSymbol] = nm;
- curSymbol++;
-
- commonCounter += sz;
- }
- }
- }
-
- IF_DEBUG(linker, debugBelch("ocGetNames_MachO: done\n"));
- return 1;
-}
-
-static int
-ocResolve_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;
- struct segment_command *segLC = NULL;
- struct section *sections;
- struct symtab_command *symLC = NULL;
- struct dysymtab_command *dsymLC = NULL;
- struct nlist *nlist;
-
- IF_DEBUG(linker, debugBelch("ocResolve_MachO: start\n"));
- for (i = 0; i < header->ncmds; i++)
- {
- if (lc->cmd == LC_SEGMENT || lc->cmd == LC_SEGMENT_64) {
- segLC = (struct segment_command*) lc;
- IF_DEBUG(linker, debugBelch("ocResolve_MachO: found a 32 or 64 bit segment load command\n"));
- }
- else if (lc->cmd == LC_SYMTAB) {
- symLC = (struct symtab_command*) lc;
- IF_DEBUG(linker, debugBelch("ocResolve_MachO: found a symbol table load command\n"));
- }
- else if (lc->cmd == LC_DYSYMTAB) {
- dsymLC = (struct dysymtab_command*) lc;
- IF_DEBUG(linker, debugBelch("ocResolve_MachO: found a dynamic symbol table load command\n"));
- }
-
- lc = (struct load_command *) ( ((char*)lc) + lc->cmdsize );
- }
-
- sections = (struct section*) (segLC+1);
- nlist = symLC ? (struct nlist*) (image + symLC->symoff)
- : NULL;
-
- if(dsymLC)
- {
- unsigned long *indirectSyms
- = (unsigned long*) (image + dsymLC->indirectsymoff);
-
- IF_DEBUG(linker, debugBelch("ocResolve_MachO: resolving dsymLC\n"));
- for (i = 0; i < segLC->nsects; i++)
- {
- if( !strcmp(sections[i].sectname,"__la_symbol_ptr")
- || !strcmp(sections[i].sectname,"__la_sym_ptr2")
- || !strcmp(sections[i].sectname,"__la_sym_ptr3"))
- {
- if(!resolveImports(oc,image,symLC,&sections[i],indirectSyms,nlist))
- return 0;
- }
- else if(!strcmp(sections[i].sectname,"__nl_symbol_ptr")
- || !strcmp(sections[i].sectname,"__pointers"))
- {
- if(!resolveImports(oc,image,symLC,&sections[i],indirectSyms,nlist))
- return 0;
- }
- else if(!strcmp(sections[i].sectname,"__jump_table"))
- {
- if(!resolveImports(oc,image,symLC,&sections[i],indirectSyms,nlist))
- return 0;
- }
- else
- {
- IF_DEBUG(linker, debugBelch("ocResolve_MachO: unknown section\n"));
- }
- }
- }
-
- for(i=0;i<segLC->nsects;i++)
- {
- IF_DEBUG(linker, debugBelch("ocResolve_MachO: relocating section %d\n", i));
-
- if (!relocateSection(oc,image,symLC,nlist,segLC->nsects,sections,&sections[i]))
- return 0;
- }
-
-#if defined (powerpc_HOST_ARCH)
- ocFlushInstructionCache( oc );
-#endif
-
- return 1;
-}
-
-static int ocRunInit_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));
- struct segment_command *segLC = NULL;
- struct section *sections;
- uint32_t i;
-
- for (i = 0; i < header->ncmds; i++) {
- if (lc->cmd == LC_SEGMENT || lc->cmd == LC_SEGMENT_64) {
- segLC = (struct segment_command*) lc;
- }
- lc = (struct load_command *) ( ((char*)lc) + lc->cmdsize );
- }
- if (!segLC) {
- barf("ocRunInit_MachO: no segment load command");
- }
- sections = (struct section*) (segLC+1);
-
- int argc, envc;
- char **argv, **envv;
-
- getProgArgv(&argc, &argv);
- getProgEnvv(&envc, &envv);
-
- for (i = 0; i < segLC->nsects; i++) {
- // ToDo: replace this with a proper check for the S_MOD_INIT_FUNC_POINTERS
- // flag. We should do this elsewhere in the Mach-O linker code
- // too. Note that the system linker will *refuse* to honor
- // sections which don't have this flag, so this could cause
- // weird behavior divergence (albeit reproduceable).
- if (0 == strcmp(sections[i].sectname,"__mod_init_func")) {
- char *init_startC = image + sections[i].offset;
- init_t *init = (init_t*)init_startC;
- init_t *init_end = (init_t*)(init_startC + sections[i].size);
- for (; init < init_end; init++) {
- (*init)(argc, argv, envv);
- }
- }
- }
-
- freeProgEnvv(envc, envv);
- 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
- * libcc_dynamic.a whose name does not have a leading underscore.
- * As a consequence, we can't get their address from C code.
- * We have to use inline assembler just to take the address of a function.
- * Yuck.
- */
-
-extern void* symbolsWithoutUnderscore[];
-
-static void
-machoInitSymbolsWithoutUnderscore(void)
-{
- void **p = symbolsWithoutUnderscore;
- __asm__ volatile(".globl _symbolsWithoutUnderscore\n.data\n_symbolsWithoutUnderscore:");
-
-#undef SymI_NeedsProto
-#undef SymI_NeedsDataProto
-
-#define SymI_NeedsProto(x) \
- __asm__ volatile(".long " # x);
-
-#define SymI_NeedsDataProto(x) \
- SymI_NeedsProto(x)
-
- RTS_MACHO_NOUNDERLINE_SYMBOLS
-
- __asm__ volatile(".text");
-
-#undef SymI_NeedsProto
-#undef SymI_NeedsDataProto
-
-#define SymI_NeedsProto(x) \
- ghciInsertSymbolTable("(GHCi built-in symbols)", symhash, #x, *p++, HS_BOOL_FALSE, NULL);
-
-#define SymI_NeedsDataProto(x) \
- SymI_NeedsProto(x)
-
- RTS_MACHO_NOUNDERLINE_SYMBOLS
-
-#undef SymI_NeedsProto
-#undef SymI_NeedsDataProto
-}
-#endif
-
-#if defined(OBJFORMAT_MACHO)
-/*
- * 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;
-
- {
- int n = fread(&header, sizeof(header), 1, f);
- if (n != 1) {
- barf("machoGetMisalignment: can't read the Mach-O header");
- }
- }
- fseek(f, -sizeof(header), SEEK_CUR);
-
-#if x86_64_HOST_ARCH || powerpc64_HOST_ARCH
- if(header.magic != MH_MAGIC_64) {
- barf("Bad magic. Expected: %08x, got: %08x.",
- MH_MAGIC_64, header.magic);
- }
-#else
- if(header.magic != MH_MAGIC) {
- barf("Bad magic. Expected: %08x, got: %08x.",
- MH_MAGIC, header.magic);
- }
-#endif
-
- misalignment = (header.sizeofcmds + sizeof(header))
- & 0xF;
-
- return misalignment ? (16 - misalignment) : 0;
-}
-#endif
-
-#endif