/* -----------------------------------------------------------------------------
- * $Id: Linker.c,v 1.136 2003/10/08 09:42:34 wolfgang Exp $
+ * $Id: Linker.c,v 1.140 2003/11/12 15:45:49 sof Exp $
*
* (c) The GHC Team, 2000-2003
*
initLinker();
-#if !defined(openbsd_TARGET_OS)
hdl= dlopen(dll_name, RTLD_NOW | RTLD_GLOBAL);
-#else
- hdl= dlopen(dll_name, RTLD_LAZY);
-#endif
+
if (hdl == NULL) {
/* dlopen failed; return a ptr to the error msg. */
errmsg = dlerror();
* 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;
#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.
*/
if(nundefsym > 0)
{
#ifdef USE_MMAP
- #error ocAllocateJumpIslands_MachO doesn't want USE_MMAP to be defined
+ #error ocAllocateJumpIslands_MachO doesnt want USE_MMAP to be defined
#else
oc->image = stgReallocBytes(
image, oc->fileSize + islandSize * nundefsym,
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;
}
/* 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;
}