/* -----------------------------------------------------------------------------
- * $Id: Linker.c,v 1.137 2003/10/08 10:37:25 wolfgang Exp $
+ * $Id: Linker.c,v 1.138 2003/10/29 16:12:00 wolfgang Exp $
*
* (c) The GHC Team, 2000-2003
*
#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:
- *) handle uninitialized data sections ("__common").
- Normal common definitions work, but beware if you pass -fno-common to gcc.
*) implement ocVerifyImage_MachO
*) add still more sanity checks.
*/
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;
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);
- checkProddableBlock(oc,word);
- *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);
+ }
}
}
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;
for(i=0;i<segLC->nsects;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));
addSection(oc, SECTIONKIND_RWDATA,
(void*) (image + sections[i].offset),
(void*) (image + sections[i].offset + sections[i].size));
-
- if(sections[i].size > 0) // size 0 segments do exist
- addProddableBlock(oc, (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
for(i=0;i<segLC->nsects;i++)
{
- if(!relocateSection(oc,image,symLC,nlist,sections,§ions[i]))
+ if(!relocateSection(oc,image,symLC,nlist,segLC->nsects,sections,§ions[i]))
return 0;
}