diff options
-rw-r--r-- | rts/Linker.c | 10 | ||||
-rw-r--r-- | rts/linker/MachO.c | 329 | ||||
-rw-r--r-- | rts/linker/MachO.h | 17 | ||||
-rw-r--r-- | rts/linker/SymbolExtras.c | 1 | ||||
-rw-r--r-- | testsuite/tests/rts/linker/Makefile | 8 | ||||
-rw-r--r-- | testsuite/tests/rts/linker/all.T | 9 | ||||
-rwxr-xr-x | testsuite/tests/rts/linker/runner | bin | 0 -> 1528176 bytes | |||
-rw-r--r-- | testsuite/tests/rts/linker/runner.c | 65 | ||||
-rw-r--r-- | testsuite/tests/rts/linker/unsigned_reloc_macho_64.s | 11 | ||||
-rw-r--r-- | testsuite/tests/rts/linker/unsigned_reloc_macho_64.stdout | 2 |
10 files changed, 329 insertions, 123 deletions
diff --git a/rts/Linker.c b/rts/Linker.c index b293b6a839..ba78efe7b6 100644 --- a/rts/Linker.c +++ b/rts/Linker.c @@ -1419,6 +1419,8 @@ preloadObjectFile (pathchar *path) #endif /* RTS_LINKER_USE_MMAP */ + IF_DEBUG(linker, debugBelch("loadObj: preloaded image at %p\n", (void *) image)); + oc = mkOc(path, image, fileSize, true, NULL, misalignment); #if defined(OBJFORMAT_MACHO) @@ -1440,7 +1442,7 @@ preloadObjectFile (pathchar *path) static HsInt loadObj_ (pathchar *path) { ObjectCode* oc; - IF_DEBUG(linker, debugBelch("loadObj %" PATH_FMT "\n", path)); + IF_DEBUG(linker, debugBelch("loadObj: %" PATH_FMT "\n", path)); /* debugBelch("loadObj %s\n", path ); */ @@ -1611,6 +1613,8 @@ int ocTryLoad (ObjectCode* oc) { // run init/init_array/ctors/mod_init_func + IF_DEBUG(linker, debugBelch("ocTryLoad: ocRunInit start\n")); + loading_obj = oc; // tells foreignExportStablePtr what to do #if defined(OBJFORMAT_ELF) r = ocRunInit_ELF ( oc ); @@ -1814,8 +1818,8 @@ void freeProddableBlocks (ObjectCode *oc) */ void addSection (Section *s, SectionKind kind, SectionAlloc alloc, - void* start, StgWord size, StgWord mapped_offset, - void* mapped_start, StgWord mapped_size) + void* start, StgWord size, + StgWord mapped_offset, void* mapped_start, StgWord mapped_size) { s->start = start; /* actual start of section in memory */ s->size = size; /* actual size of section in memory */ diff --git a/rts/linker/MachO.c b/rts/linker/MachO.c index adcfcc7c40..7ec3cabef7 100644 --- a/rts/linker/MachO.c +++ b/rts/linker/MachO.c @@ -2,13 +2,12 @@ #if defined(darwin_HOST_OS) || defined(ios_HOST_OS) -#if defined(ios_HOST_OS) -#if !RTS_LINKER_USE_MMAP +#if defined(ios_HOST_OS) && !RTS_LINKER_USE_MMAP #error "ios must use mmap and mprotect!" #endif + /* for roundUpToPage */ #include "sm/OSMem.h" -#endif #include "RtsUtils.h" #include "GetEnv.h" @@ -680,77 +679,44 @@ relocateSectionAarch64(ObjectCode * oc, Section * section) } return 1; } -#else /* non aarch64_HOST_ARCH branch -- aarch64 doesn't use relocateAddress */ - -/* - * Try to find the final loaded address for some addres. - * Look through all sections, locating the section that - * contains the address and compute the absolue address. - */ -static unsigned long -relocateAddress( - ObjectCode* oc, - int nSections, - MachOSection* 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; -} - #endif /* aarch64_HOST_ARCH */ #if defined(x86_64_HOST_ARCH) static int -relocateSection( - ObjectCode* oc, - char *image, - MachOSymtabCommand *symLC, MachONList *nlist, - int nSections, MachOSection* sections, MachOSection *sect) +relocateSection(ObjectCode* oc, int curSection) { - MachORelocationInfo *relocs; - int i, n; + Section * sect = &oc->sections[curSection]; + MachOSection * msect = sect->info->macho_section; // for convenience access + MachORelocationInfo * relocs = sect->info->relocation_info; + MachOSymbol * symbols = oc->info->macho_symbols; - IF_DEBUG(linker, debugBelch("relocateSection: start\n")); + IF_DEBUG(linker, debugBelch("relocateSection %d (%s, %s): start\n", + curSection, msect->segname, msect->sectname)); - if(!strcmp(sect->sectname,"__la_symbol_ptr")) + if(!strcmp(msect->sectname,"__la_symbol_ptr")) return 1; - else if(!strcmp(sect->sectname,"__nl_symbol_ptr")) + else if(!strcmp(msect->sectname,"__nl_symbol_ptr")) return 1; - else if(!strcmp(sect->sectname,"__la_sym_ptr2")) + else if(!strcmp(msect->sectname,"__la_sym_ptr2")) return 1; - else if(!strcmp(sect->sectname,"__la_sym_ptr3")) + else if(!strcmp(msect->sectname,"__la_sym_ptr3")) return 1; - n = sect->nreloc; - IF_DEBUG(linker, debugBelch("relocateSection: number of relocations: %d\n", n)); + IF_DEBUG(linker, debugBelch("relocateSection: number of relocations: %d\n", msect->nreloc)); - relocs = (MachORelocationInfo*) (image + sect->reloff); - - for(i = 0; i < n; i++) + for(uint32_t i = 0; i < msect->nreloc; i++) { MachORelocationInfo *reloc = &relocs[i]; - char *thingPtr = image + sect->offset + reloc->r_address; + char *thingPtr = (char *) sect->start + 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; + int relocLenBytes; + int nextInstrAdj = 0; IF_DEBUG(linker, debugBelch("relocateSection: relocation %d\n", i)); IF_DEBUG(linker, debugBelch(" : type = %d\n", reloc->r_type)); @@ -766,27 +732,47 @@ relocateSection( case 0: checkProddableBlock(oc,thingPtr,1); thing = *(uint8_t*)thingPtr; - baseValue = (uint64_t)thingPtr + 1; + relocLenBytes = 1; break; case 1: checkProddableBlock(oc,thingPtr,2); thing = *(uint16_t*)thingPtr; - baseValue = (uint64_t)thingPtr + 2; + relocLenBytes = 2; break; case 2: checkProddableBlock(oc,thingPtr,4); thing = *(uint32_t*)thingPtr; - baseValue = (uint64_t)thingPtr + 4; + relocLenBytes = 4; break; case 3: checkProddableBlock(oc,thingPtr,8); thing = *(uint64_t*)thingPtr; - baseValue = (uint64_t)thingPtr + 8; + relocLenBytes = 8; break; default: barf("Unknown size."); } + /* + * With SIGNED_N the relocation is not at the + * end of instruction and baseValue needs to be + * adjusted accordingly. + */ + switch (type) { + case X86_64_RELOC_SIGNED_1: + nextInstrAdj = 1; + break; + case X86_64_RELOC_SIGNED_2: + nextInstrAdj = 2; + break; + case X86_64_RELOC_SIGNED_4: + nextInstrAdj = 4; + break; + } + baseValue = (uint64_t)thingPtr + relocLenBytes + nextInstrAdj; + + + IF_DEBUG(linker, debugBelch("relocateSection: length = %d, thing = %" PRId64 ", baseValue = %p\n", reloc->r_length, thing, (char *)baseValue)); @@ -794,18 +780,19 @@ relocateSection( if (type == X86_64_RELOC_GOT || type == X86_64_RELOC_GOT_LOAD) { - MachONList *symbol = &nlist[reloc->r_symbolnum]; - SymbolName* nm = image + symLC->stroff + symbol->n_un.n_strx; + MachOSymbol *symbol = &symbols[reloc->r_symbolnum]; + SymbolName* nm = symbol->name; SymbolAddr* addr = NULL; - IF_DEBUG(linker, debugBelch("relocateSection: making jump island for %s, extern = %d, X86_64_RELOC_GOT\n", nm, reloc->r_extern)); + 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); + ASSERT(reloc->r_extern); // fixme: redundant? if (reloc->r_extern == 0) { errorBelch("\nrelocateSection: global offset table relocation for symbol with r_extern == 0\n"); } - if (symbol->n_type & N_EXT) { + if (symbol->nlist->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 @@ -829,38 +816,41 @@ relocateSection( // 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)); + if ((symbol->nlist->n_type & N_TYPE) == N_SECT) { + ASSERT(symbol->addr != NULL); + addr = symbol->addr; + IF_DEBUG(linker, debugBelch("relocateSection: calculated relocation of " + "non-external X86_64_RELOC_GOT or X86_64_RELOC_GOT_LOAD\n")); + 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); + errorBelch("\nrelocateSection: %s is not exported," + " and should be defined in a section, but isn't!\n", nm); } } + // creates a jump island for every relocation entry for a symbol + // fixme: use got_addr to store the loc. of a jump island for a symbol value = (uint64_t) &makeSymbolExtra(oc, reloc->r_symbolnum, (unsigned long)addr)->addr; type = X86_64_RELOC_SIGNED; } else if (reloc->r_extern) { - MachONList *symbol = &nlist[reloc->r_symbolnum]; - SymbolName* nm = image + symLC->stroff + symbol->n_un.n_strx; + MachOSymbol *symbol = &symbols[reloc->r_symbolnum]; + SymbolName* nm = symbol->name; 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)); + IF_DEBUG(linker, debugBelch(" : type = %d\n", symbol->nlist->n_type)); + IF_DEBUG(linker, debugBelch(" : sect = %d\n", symbol->nlist->n_sect)); + IF_DEBUG(linker, debugBelch(" : desc = %d\n", symbol->nlist->n_desc)); + IF_DEBUG(linker, debugBelch(" : value = %p\n", (void *)symbol->nlist->n_value)); + + if ((symbol->nlist->n_type & N_TYPE) == N_SECT) { + ASSERT(symbol->addr != NULL); + value = (uint64_t) symbol->addr; + IF_DEBUG(linker, debugBelch("relocateSection, defined external symbol %s, relocated address %p\n", + nm, (void *)value)); } else { addr = lookupSymbol_(nm); @@ -877,15 +867,83 @@ relocateSection( } 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). + /* Since the relocation is internal, r_symbolnum contains a section + * number relative to which the relocation is. Depending on whether + * the relocation is unsigned or signed, the given displacement is + * relative to the image or the section respectively. + * + * For instance, in a signed case: + * thing = <displ. to to section r_symbolnum *in the image*> (1) + * + <offset within r_symbolnum section> + * (1) needs to be updated due to different section layout in memory. + */ - value = baseValue; + CHECKM(reloc->r_symbolnum > 0, + "relocateSection: unsupported r_symbolnum = %" PRIu32 " < 1 for internal relocation", + reloc->r_symbolnum); + + int targetSecNum = reloc->r_symbolnum - 1; // sec numbers start with 1 + Section * targetSec = &oc->sections[targetSecNum]; + MachOSection * targetMacho = targetSec->info->macho_section; + + IF_DEBUG(linker, + debugBelch("relocateSection: internal relocation relative to section %d (%s, %s)\n", + targetSecNum, targetMacho->segname, targetMacho->sectname)); + + switch (type) { + case X86_64_RELOC_UNSIGNED: { + CHECKM(thing >= targetMacho->addr, + "relocateSection: unsigned displacement %" PRIx64 "before target section start address %" PRIx64 "\n", + thing, (uint64_t) targetMacho->addr); + + uint64_t thingRelativeOffset = thing - targetMacho->addr; + IF_DEBUG(linker, debugBelch(" " + "unsigned displacement %" PRIx64 " with section relative offset %" PRIx64 "\n", + thing, thingRelativeOffset)); + + thing = (uint64_t) targetSec->start + thingRelativeOffset; + IF_DEBUG(linker, debugBelch(" " + "relocated address is %p\n", (void *) thing)); + + /* Compared to external relocation we don't need to adjust value + * any further since thing already has absolute address. + */ + value = 0; + break; + } + case X86_64_RELOC_SIGNED: + case X86_64_RELOC_SIGNED_1: + case X86_64_RELOC_SIGNED_2: + case X86_64_RELOC_SIGNED_4: { + uint32_t baseValueOffset = reloc->r_address + relocLenBytes + nextInstrAdj; + uint64_t imThingLoc = msect->addr + baseValueOffset + (int64_t) thing; + + CHECKM(imThingLoc >= targetMacho->addr, + "relocateSection: target location %p in image before target section start address %p\n", + (void *) imThingLoc, (void *) targetMacho->addr); + + int64_t thingRelativeOffset = imThingLoc - targetMacho->addr; + IF_DEBUG(linker, + debugBelch(" " + "original displacement %" PRId64 " to %p with section relative offset %" PRIu64 "\n", + thing, (void *) imThingLoc, thingRelativeOffset)); + + thing = (int64_t) ((uint64_t) targetSec->start + thingRelativeOffset) + - ((uint64_t) sect->start + baseValueOffset); + value = baseValue; // so that it further cancels out with baseValue + IF_DEBUG(linker, + debugBelch(" " + "relocated displacement %" PRId64 " to %p\n", + (int64_t) thing, (void *) (baseValue + thing))); + break; + } + default: + barf("relocateSection: unexpected internal relocation type %d\n", type); + return 0; + } } - IF_DEBUG(linker, debugBelch("relocateSection: value = %p\n", (void *)value)); + IF_DEBUG(linker, debugBelch("relocateSection: value = %p\n", (void *) value)); if (type == X86_64_RELOC_BRANCH) { @@ -920,6 +978,8 @@ relocateSection( barf("unknown relocation"); } + IF_DEBUG(linker, debugBelch("relocateSection: thing = %p\n", (void *) thing)); + switch(reloc->r_length) { case 0: @@ -961,6 +1021,20 @@ relocateSection( * addressability for relative or absolute access. */ +size_t ocGetRequiredSpace_MachO(ObjectCode* oc) +{ + size_t bytesNeeded = 0; + size_t sectionSize; + + for(int i = 0; i < oc->n_sections; i++) + { + sectionSize = oc->info->macho_sections[i].size; + bytesNeeded += roundUpToPage(sectionSize); + } + + return bytesNeeded; +} + int ocGetNames_MachO(ObjectCode* oc) { @@ -982,6 +1056,19 @@ ocGetNames_MachO(ObjectCode* oc) IF_DEBUG(linker, debugBelch("ocGetNames_MachO: will load %d sections\n", oc->n_sections)); + +#if defined(darwin_HOST_OS) + size_t requiredSize = ocGetRequiredSpace_MachO(oc); + IF_DEBUG(linker, debugBelch("ocGetNames_MachO: required mmaped space is %zu\n", + requiredSize)); + + void* memStart = mmapForLinker(requiredSize, MAP_ANONYMOUS, -1, 0); + if (memStart == NULL) { + barf("ocGetNames_MachO: failed to mmap"); + } + void* memCur = memStart; +#endif // darwin_HOST_OS + for(int i=0; i < oc->n_sections; i++) { MachOSection * section = &oc->info->macho_sections[i]; @@ -1105,9 +1192,10 @@ ocGetNames_MachO(ObjectCode* oc) zeroFillArea = stgCallocBytes(1,section->size, "ocGetNames_MachO(common symbols)"); } - section->offset = zeroFillArea - oc->image; + section->offset = zeroFillArea - oc->image; // fixme: fails down the road + // when zFA < oc->image since offset is unsigned - addSection(&secArray[i], kind, SECTION_NOMEM, + addSection(&secArray[i], kind, SECTION_NOMEM, // fixme: why NOMEM? (void *)(oc->image + section->offset), section->size, 0, 0, 0); @@ -1124,18 +1212,23 @@ ocGetNames_MachO(ObjectCode* oc) secArray[i].info->macho_section = section; secArray[i].info->relocation_info = (MachORelocationInfo*)(oc->image + section->reloff); - FALLTHROUGH; + break; } default: { - // just set the pointer to the loaded image. - addSection(&secArray[i], kind, SECTION_NOMEM, - (void *)(oc->image + section->offset), - section->size, - 0, 0, 0); + size_t sectionRoundedSize = roundUpToPage(section->size); - addProddableBlock(oc, - (void *) (oc->image + section->offset), - section->size); + IF_DEBUG(linker, debugBelch("ocGetNames_MachO: copying from %p to %p a block of %" PRIu64 " bytes\n", + (void *) (oc->image + section->offset), memCur, section->size)); + memcpy(memCur, oc->image + section->offset, section->size); + IF_DEBUG(linker, debugBelch("ocGetNames_MachO: copied %" PRIu64 " bytes\n", + section->size)); + + addSection(&secArray[i], kind, SECTION_MMAP, + memCur, section->size, + 0, memCur, sectionRoundedSize); + addProddableBlock(oc, memCur, section->size); + + memCur = (char*) memCur + sectionRoundedSize; secArray[i].info->nstubs = 0; secArray[i].info->stub_offset = NULL; @@ -1156,17 +1249,25 @@ ocGetNames_MachO(ObjectCode* oc) for(size_t i=0; i < oc->info->n_macho_symbols; i++) { MachOSymbol * s = &oc->info->macho_symbols[i]; if( N_SECT == (s->nlist->n_type & N_TYPE) ) { - /* section is given */ + if( NO_SECT == s->nlist->n_sect ) + barf("Symbol with N_SECT type, but no section."); + + /* section is given, and n_sect is >0 */ uint8_t n = s->nlist->n_sect - 1; if(0 == oc->info->macho_sections[n].size) { continue; } - if(s->nlist->n_sect == NO_SECT) - barf("Symbol with N_SECT type, but no section."); - /* addr <- offset in memory where this section resides - * - address rel. to the image where this section is stored - * + symbol offset in the image + /* addr <- address in memory where the relocated section resides | (a) + * - section's address in the image | (b) + * + symbol's address in the image | (c) + * (c) - (b) gives symbol's offset relative to section start + * (a) - (b) + (c) gives symbol's address for the relocated section + * + * (c) and (b) are not _real_ addresses and not equal + * to file offsets in the image. + * Rather they are (virtual) aligned addresses within + * a single segment of MH_OBJECT object file. */ s->addr = (uint8_t*)oc->sections[n].start - oc->info->macho_sections[n].addr @@ -1209,13 +1310,13 @@ ocGetNames_MachO(ObjectCode* oc) if (oc->info->symCmd) { for (size_t i = 0; i < oc->info->n_macho_symbols; i++) { SymbolName* nm = oc->info->macho_symbols[i].name; - if(oc->info->nlist[i].n_type & N_STAB) + if (oc->info->nlist[i].n_type & N_STAB) { IF_DEBUG(linker, debugBelch("ocGetNames_MachO: Skip STAB: %s\n", nm)); } - else if((oc->info->nlist[i].n_type & N_TYPE) == N_SECT) + else if ((oc->info->nlist[i].n_type & N_TYPE) == N_SECT) { - if(oc->info->nlist[i].n_type & N_EXT) + if (oc->info->nlist[i].n_type & N_EXT) { if ( (oc->info->nlist[i].n_desc & N_WEAK_DEF) && lookupSymbol_(nm)) { @@ -1405,9 +1506,7 @@ ocResolve_MachO(ObjectCode* oc) if (!relocateSectionAarch64(oc, &oc->sections[i])) return 0; #else - if (!relocateSection(oc,oc->image,oc->info->symCmd,oc->info->nlist, - oc->info->segCmd->nsects,oc->info->macho_sections, - &oc->info->macho_sections[i])) + if (!relocateSection(oc, i)) return 0; #endif } @@ -1433,19 +1532,24 @@ ocRunInit_MachO ( ObjectCode *oc ) getProgEnvv(&envc, &envv); for (int i = 0; i < oc->n_sections; i++) { + IF_DEBUG(linker, debugBelch("ocRunInit_MachO: checking section %d\n", 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 reproducible). - if (0 == strcmp(oc->info->macho_sections[i].sectname, - "__mod_init_func")) { + if (0 == strcmp(oc->info->macho_sections[i].sectname, "__mod_init_func")) { + IF_DEBUG(linker, debugBelch("ocRunInit_MachO: running mod init functions\n")); void *init_startC = oc->sections[i].start; init_t *init = (init_t*)init_startC; init_t *init_end = (init_t*)((uint8_t*)init_startC + oc->sections[i].info->macho_section->size); - for (; init < init_end; init++) { + + for (int pn = 0; init < init_end; init++, pn++) { + IF_DEBUG(linker, debugBelch("ocRunInit_MachO: function pointer %d at %p to %p\n", + pn, (void *) init, (void *) *init)); (*init)(argc, argv, envv); } } @@ -1481,6 +1585,7 @@ machoGetMisalignment( FILE * f ) misalignment = (header.sizeofcmds + sizeof(header)) & 0xF; + IF_DEBUG(linker, debugBelch("mach-o misalignment %d\n", misalignment)); return misalignment ? (16 - misalignment) : 0; } diff --git a/rts/linker/MachO.h b/rts/linker/MachO.h index 5e00e2a8d2..20cb2d061a 100644 --- a/rts/linker/MachO.h +++ b/rts/linker/MachO.h @@ -6,13 +6,14 @@ #include "MachOTypes.h" -void ocInit_MachO ( ObjectCode* oc ); -void ocDeinit_MachO ( ObjectCode* oc ); -int ocVerifyImage_MachO ( ObjectCode* oc ); -int ocGetNames_MachO ( ObjectCode* oc ); -int ocResolve_MachO ( ObjectCode* oc ); -int ocRunInit_MachO ( ObjectCode* oc ); -int machoGetMisalignment( FILE * ); -int ocAllocateExtras_MachO ( ObjectCode* oc ); +void ocInit_MachO ( ObjectCode* oc ); +void ocDeinit_MachO ( ObjectCode* oc ); +int ocVerifyImage_MachO ( ObjectCode* oc ); +size_t ocGetRequiredSpace_MachO ( ObjectCode* oc); +int ocGetNames_MachO ( ObjectCode* oc ); +int ocResolve_MachO ( ObjectCode* oc ); +int ocRunInit_MachO ( ObjectCode* oc ); +int machoGetMisalignment ( FILE * ); +int ocAllocateExtras_MachO ( ObjectCode* oc ); #include "EndPrivate.h" diff --git a/rts/linker/SymbolExtras.c b/rts/linker/SymbolExtras.c index a9e4c37967..4149522ba0 100644 --- a/rts/linker/SymbolExtras.c +++ b/rts/linker/SymbolExtras.c @@ -149,6 +149,7 @@ SymbolExtra* makeSymbolExtra( ObjectCode const* oc, #endif /* powerpc_HOST_ARCH */ #if defined(x86_64_HOST_ARCH) // jmp *-14(%rip) + // 0xFF 25 is opcode + ModRM of near absolute indirect jump static uint8_t jmp[] = { 0xFF, 0x25, 0xF2, 0xFF, 0xFF, 0xFF }; extra->addr = target; memcpy(extra->jumpIsland, jmp, 6); diff --git a/testsuite/tests/rts/linker/Makefile b/testsuite/tests/rts/linker/Makefile new file mode 100644 index 0000000000..c5d80faa3f --- /dev/null +++ b/testsuite/tests/rts/linker/Makefile @@ -0,0 +1,8 @@ +TOP=../../.. +include $(TOP)/mk/boilerplate.mk +include $(TOP)/mk/test.mk + +unsigned_reloc_macho_64: + as -o unsigned_reloc_macho_64.o unsigned_reloc_macho_64.s + '$(TEST_HC)' $(TEST_HC_OPTS_NO_RTSOPTS) -v0 --make -no-rtsopts-suggestions -no-hs-main -o runner -debug runner.c + ./runner unsigned_reloc_macho_64.o getAnswer diff --git a/testsuite/tests/rts/linker/all.T b/testsuite/tests/rts/linker/all.T new file mode 100644 index 0000000000..d1b3c22b27 --- /dev/null +++ b/testsuite/tests/rts/linker/all.T @@ -0,0 +1,9 @@ +# -*-: mode: python -*- + +test('unsigned_reloc_macho_64', + [ + extra_files(['runner.c', 'unsigned_reloc_macho_64.s']), + unless(opsys('darwin'), skip), + unless(arch('x86_64'), skip) + ], + run_command, ['$MAKE -s --no-print-directory unsigned_reloc_macho_64']) diff --git a/testsuite/tests/rts/linker/runner b/testsuite/tests/rts/linker/runner Binary files differnew file mode 100755 index 0000000000..7771d4ab57 --- /dev/null +++ b/testsuite/tests/rts/linker/runner diff --git a/testsuite/tests/rts/linker/runner.c b/testsuite/tests/rts/linker/runner.c new file mode 100644 index 0000000000..7c34ac284a --- /dev/null +++ b/testsuite/tests/rts/linker/runner.c @@ -0,0 +1,65 @@ +#include <Rts.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> + +#define MAX_SYMNAME 256 + +typedef long (*fun_t)(void); + +int main(int argc, char *argv[]) +{ + fun_t f; + int ok; + char * objpath; + + hs_init(&argc, &argv); + + initLinker(); + + if (argc < 3) { + errorBelch("usage: runner <objpath> <symname>"); + exit(1); + } + objpath = argv[1]; + +#ifdef darwin_HOST_OS + char symname[MAX_SYMNAME + 1]; + symname[0] = '_'; + strncpy(&symname[1], argv[2], MAX_SYMNAME); +#else + char * symname = argv[2]; +#endif + + printf("Linking: path = %s, symname = %s\n", objpath, symname); + + ok = loadObj(objpath); + if (!ok) { + errorBelch("loadObj(%s) failed", objpath); + exit(1); + } + + ok = resolveObjs(); + if (!ok) { + errorBelch("resolveObjs failed"); + exit(1); + } + + f = lookupSymbol(symname); + if (!f) { + errorBelch("lookupSymbol failed"); + exit(1); + } + + printf("%ld\n", f()); + + ok = unloadObj(objpath); + if (!ok) { + errorBelch("unloadObj(%s) failed", objpath); + exit(1); + } + + return 0; +} + diff --git a/testsuite/tests/rts/linker/unsigned_reloc_macho_64.s b/testsuite/tests/rts/linker/unsigned_reloc_macho_64.s new file mode 100644 index 0000000000..733c9863bd --- /dev/null +++ b/testsuite/tests/rts/linker/unsigned_reloc_macho_64.s @@ -0,0 +1,11 @@ + .text + .globl _getAnswer + +_getAnswer: + mov L2(%rip), %rdx + movq (%rdx), %rax + ret + + .data +L1: .quad 42 +L2: .quad L1 diff --git a/testsuite/tests/rts/linker/unsigned_reloc_macho_64.stdout b/testsuite/tests/rts/linker/unsigned_reloc_macho_64.stdout new file mode 100644 index 0000000000..8251451f5f --- /dev/null +++ b/testsuite/tests/rts/linker/unsigned_reloc_macho_64.stdout @@ -0,0 +1,2 @@ +Linking: path = unsigned_reloc_macho_64.o, symname = _getAnswer +42
\ No newline at end of file |