+ // mach-o files advertise interposing by having a __DATA __interpose section
+ struct InterposeData { uintptr_t replacement; uintptr_t replacee; };
+ const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
+ const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
+ const struct load_command* cmd = cmds;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ switch (cmd->cmd) {
+ case LC_SEGMENT_COMMAND:
+ {
+ const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
+ const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
+ const struct macho_section* const sectionsEnd = §ionsStart[seg->nsects];
+ for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
+ if ( ((sect->flags & SECTION_TYPE) == S_INTERPOSING) || ((strcmp(sect->sectname, "__interpose") == 0) && (strcmp(seg->segname, "__DATA") == 0)) ) {
+ // <rdar://problem/23929217> Ensure section is within segment
+ if ( (sect->addr < seg->vmaddr) || (sect->addr+sect->size > seg->vmaddr+seg->vmsize) || (sect->addr+sect->size < sect->addr) )
+ dyld::throwf("interpose section has malformed address range for %s\n", this->getPath());
+ __block uintptr_t sectionStart = sect->addr + fSlide;
+ __block uintptr_t sectionEnd = sectionStart + sect->size;
+ const size_t count = sect->size / sizeof(InterposeData);
+ InterposeData interposeArray[count];
+ // Note, we memcpy here as rebases may have already been applied.
+ memcpy(&interposeArray[0], (void*)sectionStart, sect->size);
+ __block InterposeData *interposeArrayStart = &interposeArray[0];
+ eachBind(context, ^(const LinkContext& ctx, ImageLoaderMachOCompressed* image, uintptr_t addr, uint8_t type,
+ const char* symbolName, uint8_t symbolFlags, intptr_t addend, long libraryOrdinal,
+ ExtraBindData *extraBindData,
+ const char* msg, LastLookup* last, bool runResolver) {
+ if (addr >= sectionStart && addr < sectionEnd) {
+ if ( context.verboseInterposing ) {
+ dyld::log("dyld: interposing %s at 0x%lx in range 0x%lx..0x%lx\n",
+ symbolName, addr, sectionStart, sectionEnd);
+ }
+ const ImageLoader* targetImage;
+ uintptr_t symbolAddress;
+
+ // resolve symbol
+ if (type == BIND_TYPE_THREADED_REBASE) {
+ symbolAddress = 0;
+ targetImage = nullptr;
+ } else
+ symbolAddress = image->resolve(ctx, symbolName, symbolFlags, libraryOrdinal, &targetImage, last, runResolver);
+
+ uintptr_t newValue = symbolAddress+addend;
+ uintptr_t index = (addr - sectionStart) / sizeof(uintptr_t);
+ switch (type) {
+ case BIND_TYPE_POINTER:
+ ((uintptr_t*)interposeArrayStart)[index] = newValue;
+ break;
+ case BIND_TYPE_TEXT_ABSOLUTE32:
+ // unreachable!
+ abort();
+ case BIND_TYPE_TEXT_PCREL32:
+ // unreachable!
+ abort();
+ case BIND_TYPE_THREADED_BIND:
+ ((uintptr_t*)interposeArrayStart)[index] = newValue;
+ break;
+ case BIND_TYPE_THREADED_REBASE: {
+ // Regular pointer which needs to fit in 51-bits of value.
+ // C++ RTTI uses the top bit, so we'll allow the whole top-byte
+ // and the signed-extended bottom 43-bits to be fit in to 51-bits.
+ uint64_t top8Bits = (*(uint64_t*)addr) & 0x0007F80000000000ULL;
+ uint64_t bottom43Bits = (*(uint64_t*)addr) & 0x000007FFFFFFFFFFULL;
+ uint64_t targetValue = ( top8Bits << 13 ) | (((intptr_t)(bottom43Bits << 21) >> 21) & 0x00FFFFFFFFFFFFFF);
+ newValue = (uintptr_t)(targetValue + fSlide);
+ ((uintptr_t*)interposeArrayStart)[index] = newValue;
+ break;
+ }
+ default:
+ dyld::throwf("bad bind type %d", type);
+ }
+ }
+ return (uintptr_t)0;
+ });
+ for (size_t j=0; j < count; ++j) {
+ ImageLoader::InterposeTuple tuple;
+ tuple.replacement = interposeArray[j].replacement;
+ tuple.neverImage = this;
+ tuple.onlyImage = NULL;
+ tuple.replacee = interposeArray[j].replacee;
+ if ( context.verboseInterposing ) {
+ dyld::log("dyld: interposing index %d 0x%lx with 0x%lx\n",
+ (unsigned)j, interposeArray[j].replacee, interposeArray[j].replacement);
+ }
+ // <rdar://problem/25686570> ignore interposing on a weak function that does not exist
+ if ( tuple.replacee == 0 )
+ continue;
+ // <rdar://problem/7937695> verify that replacement is in this image
+ if ( this->containsAddress((void*)tuple.replacement) ) {
+ // chain to any existing interpositions
+ for (std::vector<InterposeTuple>::iterator it=fgInterposingTuples.begin(); it != fgInterposingTuples.end(); it++) {
+ if ( it->replacee == tuple.replacee ) {
+ tuple.replacee = it->replacement;
+ }
+ }
+ ImageLoader::fgInterposingTuples.push_back(tuple);
+ }
+ }
+ }
+ }
+ }
+ break;
+ }
+ cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+ }