Loading...
--- dyld/dyld-46.16/src/ImageLoaderMachO.cpp
+++ dyld/dyld-45.1/src/ImageLoaderMachO.cpp
@@ -34,12 +34,8 @@
#include <mach-o/reloc.h>
#include <mach-o/nlist.h>
#include <sys/sysctl.h>
-#include <libkern/OSAtomic.h>
#if __ppc__ || __ppc64__
#include <mach-o/ppc/reloc.h>
-#endif
-#if __x86_64__
- #include <mach-o/x86_64/reloc.h>
#endif
#ifndef S_ATTR_SELF_MODIFYING_CODE
@@ -80,11 +76,7 @@
struct macho_routines_command : public routines_command {};
#endif
-#if __x86_64__
- #define POINTER_RELOC X86_64_RELOC_UNSIGNED
-#else
#define POINTER_RELOC GENERIC_RELOC_VANILLA
-#endif
uint32_t ImageLoaderMachO::fgHintedBinaryTreeSearchs = 0;
uint32_t ImageLoaderMachO::fgUnhintedBinaryTreeSearchs = 0;
@@ -1128,9 +1120,6 @@
#elif __i386__
const i386_thread_state_t* registers = (i386_thread_state_t*)(((char*)cmd) + 16);
return (void*)registers->eip;
- #elif __x86_64__
- const x86_thread_state64_t* registers = (x86_thread_state64_t*)(((char*)cmd) + 16);
- return (void*)registers->rip;
#else
#warning need processor specific code
#endif
@@ -1219,10 +1208,6 @@
uintptr_t ImageLoaderMachO::getRelocBase()
{
-#if __x86_64__
- // r_address is offset from first writable segment
- return getFirstWritableSegmentAddress();
-#endif
#if __ppc__ || __i386__
if ( fIsSplitSeg ) {
// in split segment libraries r_address is offset from first writable segment
@@ -1261,52 +1246,19 @@
}
#endif
-#if __ppc__ || __i386__
-void ImageLoaderMachO::resetPreboundLazyPointers(const LinkContext& context, uintptr_t relocBase)
-{
- // loop through all local (internal) relocation records looking for pre-bound-lazy-pointer values
- register const uintptr_t slide = this->fSlide;
- const relocation_info* const relocsStart = (struct relocation_info*)(&fLinkEditBase[fDynamicInfo->locreloff]);
- const relocation_info* const relocsEnd = &relocsStart[fDynamicInfo->nlocrel];
- for (const relocation_info* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
- if ( (reloc->r_address & R_SCATTERED) != 0 ) {
- const struct scattered_relocation_info* sreloc = (struct scattered_relocation_info*)reloc;
- if (sreloc->r_length == RELOC_SIZE) {
- uintptr_t* locationToFix = (uintptr_t*)(sreloc->r_address + relocBase);
- switch(sreloc->r_type) {
- #if __ppc__
- case PPC_RELOC_PB_LA_PTR:
- *locationToFix = sreloc->r_value + slide;
- break;
- #endif
- #if __i386__
- case GENERIC_RELOC_PB_LA_PTR:
- *locationToFix = sreloc->r_value + slide;
- break;
- #endif
- }
- }
- }
- }
-}
-#endif
-
void ImageLoaderMachO::doRebase(const LinkContext& context)
{
// if prebound and loaded at prebound address, then no need to rebase
- if ( this->usablePrebinding(context) ) {
+ // Note: you might think that the check for allDependentLibrariesAsWhenPreBound() is not needed
+ // but it is. If a dependent library changed, this image's lazy pointers into that library
+ // need to be updated (reset back to lazy binding handler). That work is done most easily
+ // here because there is a PPC_RELOC_PB_LA_PTR reloc record for each lazy pointer.
+ if ( this->usablePrebinding(context) && this->usesTwoLevelNameSpace() ) {
// skip rebasing cause prebound and prebinding not disabled
++fgImagesWithUsedPrebinding; // bump totals for statistics
return;
}
-
- // <rdar://problem/5146059> update_prebinding fails if a prebound dylib depends on a non-prebound dylib
- // In the unusual case that we find a prebound dylib dependent on un-prebound dylib and we are running
- // update_prebinding, we want the link of the prebound dylib to fail so that it will be excluded from
- // the list of dylibs to be re-written.
- if ( context.prebinding && !this->isPrebindable() )
- throwf("dylib not prebound: %s", this->getPath());
-
+
// print why prebinding was not used
if ( context.verbosePrebinding ) {
if ( !this->isPrebindable() ) {
@@ -1326,40 +1278,18 @@
}
}
- // cache values that are used in the following loop
- const uintptr_t relocBase = this->getRelocBase();
- register const uintptr_t slide = this->fSlide;
-
-#if __ppc__ || __i386__
- // if prebound and we got here, then prebinding is not valid, so reset all lazy pointers
- if ( this->isPrebindable() )
- this->resetPreboundLazyPointers(context, relocBase);
-#endif
-
- // if loaded at preferred address, no rebasing necessary
- if ( slide == 0 )
- return;
-
// if there are __TEXT fixups, temporarily make __TEXT writable
if ( fTextSegmentWithFixups != NULL )
fTextSegmentWithFixups->tempWritable();
+ // cache this value that is used in the following loop
+ register const uintptr_t slide = this->fSlide;
+
// loop through all local (internal) relocation records
+ const uintptr_t relocBase = this->getRelocBase();
const relocation_info* const relocsStart = (struct relocation_info*)(&fLinkEditBase[fDynamicInfo->locreloff]);
const relocation_info* const relocsEnd = &relocsStart[fDynamicInfo->nlocrel];
for (const relocation_info* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
- #if __x86_64__
- // only one kind of local relocation supported for x86_64
- if ( reloc->r_length != 3 )
- throw "bad local relocation length";
- if ( reloc->r_type != X86_64_RELOC_UNSIGNED )
- throw "unknown local relocation type";
- if ( reloc->r_pcrel != 0 )
- throw "bad local relocation pc_rel";
- if ( reloc->r_extern != 0 )
- throw "extern relocation found with local relocations";
- *((uintptr_t*)(reloc->r_address + relocBase)) += slide;
- #endif
#if __ppc__ || __ppc64__ || __i386__
if ( (reloc->r_address & R_SCATTERED) == 0 ) {
if ( reloc->r_symbolnum == R_ABS ) {
@@ -1395,6 +1325,12 @@
case GENERIC_RELOC_VANILLA:
*locationToFix += slide;
break;
+ #if __ppc__ || __ppc64__
+ case PPC_RELOC_PB_LA_PTR:
+ // should only see these in prebound images, and we got here so prebinding is being ignored
+ *locationToFix = sreloc->r_value + slide;
+ break;
+ #endif
#if __ppc__
case PPC_RELOC_HI16:
case PPC_RELOC_LO16:
@@ -1404,18 +1340,10 @@
otherRelocsPPC(locationToFix, sreloc->r_type, reloc->r_address, slide);
break;
#endif
- #if __ppc__
- case PPC_RELOC_PB_LA_PTR:
- // do nothing
- break;
- #elif __ppc64__
- case PPC_RELOC_PB_LA_PTR:
- // these should never exist in ppc64, but the first ld64 had a bug and created them
+ #if __i386__
+ case GENERIC_RELOC_PB_LA_PTR:
+ // should only see these in prebound images, and we got here so prebinding is being ignored
*locationToFix = sreloc->r_value + slide;
- break;
- #elif __i386__
- case GENERIC_RELOC_PB_LA_PTR:
- // do nothing
break;
#endif
default:
@@ -1426,7 +1354,7 @@
throw "bad local scattered relocation length";
}
}
- #endif
+ #endif
}
// if there were __TEXT fixups, restore write protection
@@ -1763,12 +1691,6 @@
if ( context.bindFlat || !twoLevel ) {
// flat lookup
- if ( ((undefinedSymbol->n_type & N_PEXT) != 0) && ((undefinedSymbol->n_type & N_TYPE) == N_SECT) ) {
- // is a multi-module private_extern internal reference that the linker did not optimize away
- uintptr_t addr = undefinedSymbol->n_value + this->fSlide;
- *foundIn = this;
- return addr;
- }
const Symbol* sym;
if ( context.flatExportFinder(symbolName, &sym, foundIn) )
return (*foundIn)->getExportedSymbolAddress(sym);
@@ -1779,6 +1701,13 @@
if ( sym != NULL )
return (*foundIn)->getExportedSymbolAddress(sym);
}
+ if ( ((undefinedSymbol->n_type & N_PEXT) != 0) || ((undefinedSymbol->n_type & N_TYPE) == N_SECT) ) {
+ // could be a multi-module private_extern internal reference
+ // the static linker squirrels away the target address in n_value
+ uintptr_t addr = undefinedSymbol->n_value + this->fSlide;
+ *foundIn = this;
+ return addr;
+ }
if ( (undefinedSymbol->n_desc & N_WEAK_REF) != 0 ) {
// definition can't be found anywhere
// if reference is weak_import, then it is ok, just return 0
@@ -1788,7 +1717,7 @@
}
else {
// symbol requires searching images with coalesced symbols
- if ( !context.prebinding && this->needsCoalescing() && symbolRequiresCoalescing(undefinedSymbol) ) {
+ if ( this->needsCoalescing() && symbolRequiresCoalescing(undefinedSymbol) ) {
const Symbol* sym;
if ( context.coalescedExportFinder(symbolName, &sym, foundIn) )
return (*foundIn)->getExportedSymbolAddress(sym);
@@ -1834,7 +1763,7 @@
}
if ( target == NULL ) {
- //fprintf(stderr, "resolveUndefined(%s) in %s\n", symbolName, this->getPath());
+ fprintf(stderr, "resolveUndefined(%s) in %s\n", symbolName, this->getPath());
throw "symbol not found";
}
@@ -2044,35 +1973,14 @@
#if __i386__
// i386 has special self-modifying stubs that change from "CALL rel32" to "JMP rel32"
if ( ((sect->flags & SECTION_TYPE) == S_SYMBOL_STUBS) && ((sect->flags & S_ATTR_SELF_MODIFYING_CODE) != 0) && (sect->reserved2 == 5) ) {
+ uint8_t* const jmpTableEntryToPatch = (uint8_t*)ptrToBind;
uint32_t rel32 = targetAddr - (((uint32_t)ptrToBind)+5);
- // re-write instruction in a thread-safe manner
- // use 8-byte compare-and-swap to alter 5-byte jump table entries
- // loop is required in case the extra three bytes that cover the next entry are altered by another thread
- bool done = false;
- while ( !done ) {
- volatile int64_t* jumpPtr = (int64_t*)ptrToBind;
- int pad = 0;
- // By default the three extra bytes swapped follow the 5-byte JMP.
- // But, if the 5-byte jump is up against the end of the __IMPORT segment
- // We don't want to access bytes off the end of the segment, so we shift
- // the extra bytes to precede the 5-byte JMP.
- if ( (((uint32_t)ptrToBind + 8) & 0x00000FFC) == 0x00000000 ) {
- jumpPtr = (int64_t*)((uint32_t)ptrToBind - 3);
- pad = 3;
- }
- int64_t oldEntry = *jumpPtr;
- union {
- int64_t int64;
- uint8_t bytes[8];
- } newEntry;
- newEntry.int64 = oldEntry;
- newEntry.bytes[pad+0] = 0xE9; // JMP rel32
- newEntry.bytes[pad+1] = rel32 & 0xFF;
- newEntry.bytes[pad+2] = (rel32 >> 8) & 0xFF;
- newEntry.bytes[pad+3] = (rel32 >> 16) & 0xFF;
- newEntry.bytes[pad+4] = (rel32 >> 24) & 0xFF;
- done = OSAtomicCompareAndSwap64Barrier(oldEntry, newEntry.int64, (int64_t*)jumpPtr);
- }
+ //fprintf(stderr, "rewriting stub at %p\n", jmpTableEntryToPatch);
+ jmpTableEntryToPatch[0] = 0xE9; // JMP rel32
+ jmpTableEntryToPatch[1] = rel32 & 0xFF;
+ jmpTableEntryToPatch[2] = (rel32 >> 8) & 0xFF;
+ jmpTableEntryToPatch[3] = (rel32 >> 16) & 0xFF;
+ jmpTableEntryToPatch[4] = (rel32 >> 24) & 0xFF;
}
else
#endif
@@ -2312,49 +2220,16 @@
const uint8_t type = sect->flags & SECTION_TYPE;
if ( (type == S_SYMBOL_STUBS) && (sect->flags & S_ATTR_SELF_MODIFYING_CODE) && (sect->reserved2 == 5) ) {
// reset each jmp entry in this section
- const uint32_t indirectTableOffset = sect->reserved1;
- const uint32_t* const indirectTable = (uint32_t*)&fLinkEditBase[fDynamicInfo->indirectsymoff];
uint8_t* start = (uint8_t*)(sect->addr + this->fSlide);
uint8_t* end = start + sect->size;
uintptr_t dyldHandler = (uintptr_t)&fast_stub_binding_helper_interface;
- uint32_t entryIndex = 0;
- for (uint8_t* entry = start; entry < end; entry += 5, ++entryIndex) {
- bool installLazyHandler = true;
- // jump table entries that cross a (64-byte) cache line boundary have the potential to cause crashes
- // if the instruction is updated by one thread while being executed by another
- if ( ((uint32_t)entry & 0xFFFFFFC0) != ((uint32_t)entry+4 & 0xFFFFFFC0) ) {
- // need to bind this now to avoid a potential problem if bound lazily
- uint32_t symbolIndex = indirectTable[indirectTableOffset + entryIndex];
- // the latest linker marks 64-byte crossing stubs with INDIRECT_SYMBOL_ABS so they are not used
- if ( symbolIndex != INDIRECT_SYMBOL_ABS ) {
- const char* symbolName = &fStrings[fSymbolTable[symbolIndex].n_un.n_strx];
- ImageLoader* image = NULL;
- try {
- uintptr_t symbolAddr = this->resolveUndefined(context, &fSymbolTable[symbolIndex], this->usesTwoLevelNameSpace(), &image);
- symbolAddr = this->bindIndirectSymbol((uintptr_t*)entry, sect, symbolName, symbolAddr, image, context);
- ++fgTotalBindFixups;
- uint32_t rel32 = symbolAddr - (((uint32_t)entry)+5);
- entry[0] = 0xE9; // JMP rel32
- entry[1] = rel32 & 0xFF;
- entry[2] = (rel32 >> 8) & 0xFF;
- entry[3] = (rel32 >> 16) & 0xFF;
- entry[4] = (rel32 >> 24) & 0xFF;
- installLazyHandler = false;
- }
- catch (const char* msg) {
- // ignore errors when binding symbols early
- // maybe the function is never called, and therefore erroring out now would be a regression
- }
- }
- }
- if ( installLazyHandler ) {
- uint32_t rel32 = dyldHandler - (((uint32_t)entry)+5);
- entry[0] = 0xE8; // CALL rel32
- entry[1] = rel32 & 0xFF;
- entry[2] = (rel32 >> 8) & 0xFF;
- entry[3] = (rel32 >> 16) & 0xFF;
- entry[4] = (rel32 >> 24) & 0xFF;
- }
+ for (uint8_t* entry = start; entry < end; entry += 5) {
+ uint32_t rel32 = dyldHandler - (((uint32_t)entry)+5);
+ entry[0] = 0xE8; // CALL rel32
+ entry[1] = rel32 & 0xFF;
+ entry[2] = (rel32 >> 8) & 0xFF;
+ entry[3] = (rel32 >> 16) & 0xFF;
+ entry[4] = (rel32 >> 24) & 0xFF;
}
}
}
@@ -2369,10 +2244,7 @@
bool ImageLoaderMachO::usablePrebinding(const LinkContext& context) const
{
// if prebound and loaded at prebound address, and all libraries are same as when this was prebound, then no need to bind
- if ( this->isPrebindable()
- && (this->getSlide() == 0)
- && (this->usesTwoLevelNameSpace() || context.prebinding)
- && this->allDependentLibrariesAsWhenPreBound() ) {
+ if ( this->isPrebindable() && this->allDependentLibrariesAsWhenPreBound() && (this->getSlide() == 0) ) {
// allow environment variables to disable prebinding
if ( context.bindFlat )
return false;
@@ -2551,22 +2423,16 @@
for (const DependentLibrary* dl=fLibraries; dl < &fLibraries[fLibrariesCount]; dl++) {
if (strcmp(dl->name, name) == 0 ) {
// found matching DependentLibrary for this load command
- if ( dl->image == NULL ) {
- // missing weak linked dylib
- dylib->dylib.timestamp = 0;
+ ImageLoaderMachO* targetImage = (ImageLoaderMachO*)(dl->image); // !!! assume only mach-o images are prebound
+ if ( ! targetImage->isPrebindable() )
+ throw "dependent dylib is not prebound";
+ // if the target is currently being re-prebound then its timestamp will be the same as this one
+ if ( ! targetImage->usablePrebinding(context) ) {
+ dylib->dylib.timestamp = timestamp;
}
else {
- ImageLoaderMachO* targetImage = (ImageLoaderMachO*)(dl->image); // !!! assume only mach-o images are prebound
- if ( ! targetImage->isPrebindable() )
- throw "dependent dylib is not prebound";
- // if the target is currently being re-prebound then its timestamp will be the same as this one
- if ( ! targetImage->usablePrebinding(context) ) {
- dylib->dylib.timestamp = timestamp;
- }
- else {
- // otherwise dependent library is already correctly prebound, so use its checksum
- dylib->dylib.timestamp = targetImage->doGetLibraryInfo().checksum;
- }
+ // otherwise dependent library is already correctly prebound, so use its checksum
+ dylib->dylib.timestamp = targetImage->doGetLibraryInfo().checksum;
}
break;
}
@@ -2664,7 +2530,7 @@
switch(sreloc->r_type) {
#if __ppc__ || __ppc64__
case PPC_RELOC_PB_LA_PTR:
- #elif __i386__ || __x86_64__
+ #elif __i386__
case GENERIC_RELOC_PB_LA_PTR:
#else
#error unknown architecture