]> git.saurik.com Git - apple/ld64.git/blobdiff - src/other/machochecker.cpp
ld64-409.12.tar.gz
[apple/ld64.git] / src / other / machochecker.cpp
index ef6ba486e1ae9b55164d8ece518d58a351972299..8e954580700b4d45565a91e07af86bbd7413bc3e 100644 (file)
@@ -134,6 +134,7 @@ private:
        uint8_t                                                                         loadCommandSizeMask();
        void                                                                            checkSymbolTable();
        void                                                                            checkInitTerms();
        uint8_t                                                                         loadCommandSizeMask();
        void                                                                            checkSymbolTable();
        void                                                                            checkInitTerms();
+       void                                                                            checkThreadedRebaseBind();
        void                                                                            checkIndirectSymbolTable();
        void                                                                            checkRelocations();
        void                                                                            checkExternalReloation(const macho_relocation_info<P>* reloc);
        void                                                                            checkIndirectSymbolTable();
        void                                                                            checkRelocations();
        void                                                                            checkExternalReloation(const macho_relocation_info<P>* reloc);
@@ -142,12 +143,13 @@ private:
        void                                                                            verifyInstallName();
        void                                                                            verifyNoRpaths();
        void                                                                            verifyNoFlatLookups();
        void                                                                            verifyInstallName();
        void                                                                            verifyNoRpaths();
        void                                                                            verifyNoFlatLookups();
+       void                                                                            verifyiOSMac();
 
        pint_t                                                                          relocBase();
        bool                                                                            addressInWritableSegment(pint_t address);
        bool                                                                            hasTextRelocInRange(pint_t start, pint_t end);
        pint_t                                                                          segStartAddress(uint8_t segIndex);
 
        pint_t                                                                          relocBase();
        bool                                                                            addressInWritableSegment(pint_t address);
        bool                                                                            hasTextRelocInRange(pint_t start, pint_t end);
        pint_t                                                                          segStartAddress(uint8_t segIndex);
-       bool                                                                            addressIsRebaseSite(pint_t addr);
+       bool                                                                            addressIsRebaseSite(pint_t addr, pint_t& pointeeAddr);
        bool                                                                            addressIsBindingSite(pint_t addr);
        pint_t                                                                          getInitialStackPointer(const macho_thread_command<P>*);
        pint_t                                                                          getEntryPoint(const macho_thread_command<P>*);
        bool                                                                            addressIsBindingSite(pint_t addr);
        pint_t                                                                          getInitialStackPointer(const macho_thread_command<P>*);
        pint_t                                                                          getEntryPoint(const macho_thread_command<P>*);
@@ -173,6 +175,8 @@ private:
        bool                                                                            fWriteableSegmentWithAddrOver4G;
        bool                                                                            fSlidableImage;
        bool                                                                            fHasLC_RPATH;
        bool                                                                            fWriteableSegmentWithAddrOver4G;
        bool                                                                            fSlidableImage;
        bool                                                                            fHasLC_RPATH;
+       bool                                                                            fIsDebugVariant;
+       uint64_t                                                                        fBaseAddress = 0;
        const macho_segment_command<P>*                         fFirstSegment;
        const macho_segment_command<P>*                         fFirstWritableSegment;
        const macho_segment_command<P>*                         fTEXTSegment;
        const macho_segment_command<P>*                         fFirstSegment;
        const macho_segment_command<P>*                         fFirstWritableSegment;
        const macho_segment_command<P>*                         fTEXTSegment;
@@ -356,7 +360,7 @@ template <typename A>
 MachOChecker<A>::MachOChecker(const uint8_t* fileContent, uint32_t fileLength, const char* path, const char* verifierDstRoot)
  : fHeader(NULL), fLength(fileLength), fInstallName(NULL), fStrings(NULL), fSymbols(NULL), fSymbolCount(0), fDynamicSymbolTable(NULL), fIndirectTableCount(0),
  fLocalRelocations(NULL),  fLocalRelocationsCount(0),  fExternalRelocations(NULL),  fExternalRelocationsCount(0),
 MachOChecker<A>::MachOChecker(const uint8_t* fileContent, uint32_t fileLength, const char* path, const char* verifierDstRoot)
  : fHeader(NULL), fLength(fileLength), fInstallName(NULL), fStrings(NULL), fSymbols(NULL), fSymbolCount(0), fDynamicSymbolTable(NULL), fIndirectTableCount(0),
  fLocalRelocations(NULL),  fLocalRelocationsCount(0),  fExternalRelocations(NULL),  fExternalRelocationsCount(0),
- fWriteableSegmentWithAddrOver4G(false), fSlidableImage(false), fHasLC_RPATH(false), fFirstSegment(NULL), fFirstWritableSegment(NULL),
+ fWriteableSegmentWithAddrOver4G(false), fSlidableImage(false), fHasLC_RPATH(false), fIsDebugVariant(false), fFirstSegment(NULL), fFirstWritableSegment(NULL),
  fTEXTSegment(NULL), fDyldInfo(NULL), fSectionCount(0)
 {
        // sanity check
  fTEXTSegment(NULL), fDyldInfo(NULL), fSectionCount(0)
 {
        // sanity check
@@ -381,6 +385,8 @@ MachOChecker<A>::MachOChecker(const uint8_t* fileContent, uint32_t fileLength, c
        
        checkInitTerms();
 
        
        checkInitTerms();
 
+       checkThreadedRebaseBind();
+
        if ( verifierDstRoot != NULL )
                verify();
 }
        if ( verifierDstRoot != NULL )
                verify();
 }
@@ -578,6 +584,8 @@ void MachOChecker<A>::checkLoadCommands()
                                if ( segCmd->vmaddr() > 0x100000000ULL )
                                        fWriteableSegmentWithAddrOver4G = true;
                        }
                                if ( segCmd->vmaddr() > 0x100000000ULL )
                                        fWriteableSegmentWithAddrOver4G = true;
                        }
+                       if ( (segCmd->fileoff() == 0) && (segCmd->filesize() != 0) )
+                               fBaseAddress = segCmd->vmaddr();
                                
                        // check section ranges
                        const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
                                
                        // check section ranges
                        const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
@@ -848,19 +856,35 @@ void MachOChecker<A>::checkSection(const macho_segment_command<P>* segCmd, const
        // more section tests here
 }
 
        // more section tests here
 }
 
+static bool endsWith(const char* str, const char* suffix)
+{
+       size_t suffixLen = strlen(suffix);
+       size_t strLen    = strlen(str);
+       if ( strLen > suffixLen ) {
+               return (strcmp(&str[strLen-suffixLen], suffix) == 0);
+       }
+       return false;
+}
 
 template <typename A>
 void MachOChecker<A>::verify()
 {
 
 template <typename A>
 void MachOChecker<A>::verify()
 {
-       bool sharedCacheCandidate = false;
-       if ( fInstallName != NULL ) {
-               if ( (strncmp(fInstallName, "/usr/lib/", 9) == 0) || (strncmp(fInstallName, "/System/Library/", 16) == 0) ) {
-                       sharedCacheCandidate = true;
-                       verifyInstallName();
-                       verifyNoRpaths();
+       if ( endsWith(fPath, "_asan.dylib") || endsWith(fPath, "_asan") || endsWith(fPath, "_debug.dylib") || endsWith(fPath, "_debug") )
+               fIsDebugVariant = true;
+
+       if ( (fDstRoot != NULL) && (strlen(fDstRoot) < strlen(fPath)) ) {
+               const char* installLocationInDstRoot = &fPath[strlen(fDstRoot)];
+               if ( installLocationInDstRoot[0] != '/' )
+                       --installLocationInDstRoot;
+               if ( (strncmp(installLocationInDstRoot, "/usr/lib/", 9) == 0) || (strncmp(installLocationInDstRoot, "/System/Library/", 16) == 0) ) {
+                       if ( !fIsDebugVariant && (strstr(fPath, ".app/") == NULL) ) {
+                               verifyInstallName();
+                               verifyNoRpaths();
+                       }
                }
        }
        verifyNoFlatLookups();
                }
        }
        verifyNoFlatLookups();
+       verifyiOSMac();
 }
 
 
 }
 
 
@@ -929,6 +953,41 @@ void MachOChecker<A>::verifyNoFlatLookups()
        }
 }
 
        }
 }
 
+template <typename A>
+void MachOChecker<A>::verifyiOSMac()
+{
+       const char* fileLocationWithinDstRoot = &fPath[strlen(fDstRoot)];
+       if ( strncmp(fileLocationWithinDstRoot, "/System/iOSSupport/", 19) == 0 ) {
+               // everything in /System/iOSSupport/ should be iOSMac only
+               bool bad = false;
+               const uint32_t cmd_count = fHeader->ncmds();
+               const macho_load_command<P>* cmd = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
+               for (uint32_t i = 0; i < cmd_count; ++i) {
+                       const macho_build_version_command<P>* buildVersCmd;
+                       switch ( cmd->cmd() ) {
+                               case LC_VERSION_MIN_MACOSX:
+                               case LC_VERSION_MIN_IPHONEOS:
+                               case LC_VERSION_MIN_TVOS:
+                               case LC_VERSION_MIN_WATCHOS:
+                                       bad = true;
+                                       break;
+                               case LC_BUILD_VERSION:
+                                       buildVersCmd = (macho_build_version_command<P>*)cmd;
+                                       if ( buildVersCmd->platform() != PLATFORM_IOSMAC )
+                                               bad = true;
+                                       break;
+                       }
+                       cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+               }
+               if ( bad )
+                       printf("macos_in_ios_support\twarn\tnon-iOSMac in /System/iOSSupport/ in arch %s\n", archName());
+       }
+       else {
+               // maybe someday warn about iOSMac only stuff not in /System/iOSSupport/
+       }
+}
+
+
 template <typename A>
 void MachOChecker<A>::checkIndirectSymbolTable()
 {
 template <typename A>
 void MachOChecker<A>::checkIndirectSymbolTable()
 {
@@ -1084,23 +1143,28 @@ void MachOChecker<A>::checkInitTerms()
                                                        throwf("%s section size is not an even multiple of element size", sect->sectname());
                                                if ( (sect->addr() % sizeof(pint_t)) != 0 )
                                                        throwf("%s section size is not pointer size aligned", sect->sectname());
                                                        throwf("%s section size is not an even multiple of element size", sect->sectname());
                                                if ( (sect->addr() % sizeof(pint_t)) != 0 )
                                                        throwf("%s section size is not pointer size aligned", sect->sectname());
-                                               // check each pointer in array points within TEXT
                                                arrayStart = (pint_t*)((char*)fHeader + sect->offset());
                                                arrayEnd = (pint_t*)((char*)fHeader + sect->offset() + sect->size());
                                                arrayStart = (pint_t*)((char*)fHeader + sect->offset());
                                                arrayEnd = (pint_t*)((char*)fHeader + sect->offset() + sect->size());
-                                               for (pint_t* p=arrayStart; p < arrayEnd; ++p) {
-                                                       pint_t pointer = P::getP(*p);
-                                                       if ( (pointer < fTEXTSegment->vmaddr()) ||  (pointer >= (fTEXTSegment->vmaddr()+fTEXTSegment->vmsize())) ) 
-                                                               throwf("%s 0x%08llX points outside __TEXT segment", kind, (long long)pointer);
-                                               }
                                                // check each pointer in array will be rebased and not bound
                                                if ( fSlidableImage ) {
                                                        pint_t sectionBeginAddr = sect->addr();
                                                        pint_t sectionEndddr = sect->addr() + sect->size();
                                                // check each pointer in array will be rebased and not bound
                                                if ( fSlidableImage ) {
                                                        pint_t sectionBeginAddr = sect->addr();
                                                        pint_t sectionEndddr = sect->addr() + sect->size();
-                                                       for(pint_t addr = sectionBeginAddr; addr < sectionEndddr; addr += sizeof(pint_t)) {
+                                                       for(pint_t addr = sectionBeginAddr, *p = arrayStart; addr < sectionEndddr; addr += sizeof(pint_t), ++p) {
                                                                if ( addressIsBindingSite(addr) )
                                                                        throwf("%s at 0x%0llX has binding to external symbol", kind, (long long)addr);
                                                                if ( addressIsBindingSite(addr) )
                                                                        throwf("%s at 0x%0llX has binding to external symbol", kind, (long long)addr);
-                                                               if ( ! addressIsRebaseSite(addr) )
+                                                               pint_t pointer = P::getP(*p);
+                                                               if ( ! addressIsRebaseSite(addr, pointer) )
                                                                        throwf("%s at 0x%0llX is not rebased", kind, (long long)addr);
                                                                        throwf("%s at 0x%0llX is not rebased", kind, (long long)addr);
+                                                               // check each pointer in array points within TEXT
+                                                               if ( (pointer < fTEXTSegment->vmaddr()) ||  (pointer >= (fTEXTSegment->vmaddr()+fTEXTSegment->vmsize())) )
+                                                                       throwf("%s 0x%08llX points outside __TEXT segment", kind, (long long)pointer);
+                                                       }
+                                               } else {
+                                                       // check each pointer in array points within TEXT
+                                                       for (pint_t* p=arrayStart; p < arrayEnd; ++p) {
+                                                               pint_t pointer = P::getP(*p);
+                                                               if ( (pointer < fTEXTSegment->vmaddr()) ||  (pointer >= (fTEXTSegment->vmaddr()+fTEXTSegment->vmsize())) )
+                                                                       throwf("%s 0x%08llX 3 points outside __TEXT segment", kind, (long long)pointer);
                                                        }
                                                }
                                                break;
                                                        }
                                                }
                                                break;
@@ -1112,6 +1176,131 @@ void MachOChecker<A>::checkInitTerms()
 
 }
 
 
 }
 
+template <typename A>
+void MachOChecker<A>::checkThreadedRebaseBind()
+{
+       // look bind info
+       if ( fDyldInfo != NULL ) {
+               const uint8_t* p = (uint8_t*)fHeader + fDyldInfo->bind_off();
+               const uint8_t* end = &p[fDyldInfo->bind_size()];
+
+               uint8_t type = 0;
+               uint64_t segOffset = 0;
+               uint32_t count;
+               uint32_t skip;
+               const char* symbolName = NULL;
+               int libraryOrdinal = 0;
+               int segIndex;
+               int64_t addend = 0;
+               pint_t segStartAddr = 0;
+               uint64_t ordinalTableSize = 0;
+               bool useThreadedRebaseBind = false;
+               bool done = false;
+               while ( !done && (p < end) ) {
+                       uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
+                       uint8_t opcode = *p & BIND_OPCODE_MASK;
+                       ++p;
+                       switch (opcode) {
+                               case BIND_OPCODE_DONE:
+                                       done = true;
+                                       break;
+                               case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
+                                       libraryOrdinal = immediate;
+                                       break;
+                               case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
+                                       libraryOrdinal = read_uleb128(p, end);
+                                       break;
+                               case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
+                                       // the special ordinals are negative numbers
+                                       if ( immediate == 0 )
+                                               libraryOrdinal = 0;
+                                       else {
+                                               int8_t signExtended = BIND_OPCODE_MASK | immediate;
+                                               libraryOrdinal = signExtended;
+                                       }
+                                       break;
+                               case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
+                                       symbolName = (char*)p;
+                                       while (*p != '\0')
+                                               ++p;
+                                       ++p;
+                                       break;
+                               case BIND_OPCODE_SET_TYPE_IMM:
+                                       type = immediate;
+                                       break;
+                               case BIND_OPCODE_SET_ADDEND_SLEB:
+                                       addend = read_sleb128(p, end);
+                                       break;
+                               case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
+                                       segIndex = immediate;
+                                       segStartAddr = segStartAddress(segIndex);
+                                       segOffset = read_uleb128(p, end);
+                                       break;
+                               case BIND_OPCODE_ADD_ADDR_ULEB:
+                                       segOffset += read_uleb128(p, end);
+                                       break;
+                               case BIND_OPCODE_DO_BIND:
+                                       segOffset += sizeof(pint_t);
+                                       break;
+                               case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
+                                       segOffset += read_uleb128(p, end) + sizeof(pint_t);
+                                       break;
+                               case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
+                                       segOffset += immediate*sizeof(pint_t) + sizeof(pint_t);
+                                       break;
+                               case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
+                                       count = read_uleb128(p, end);
+                                       skip = read_uleb128(p, end);
+                                       for (uint32_t i=0; i < count; ++i) {
+                                               segOffset += skip + sizeof(pint_t);
+                                       }
+                                       break;
+                               case BIND_OPCODE_THREADED:
+                                       // Note the immediate is a sub opcode
+                                       switch (immediate) {
+                                               case BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB:
+                                                       ordinalTableSize = read_uleb128(p, end);
+                                                       useThreadedRebaseBind = true;
+                                                       break;
+                                               case BIND_SUBOPCODE_THREADED_APPLY: {
+                                                       if ( !useThreadedRebaseBind ) {
+                                                               throwf("BIND_SUBOPCODE_THREADED_APPLY without ordinal table");
+                                                       }
+                                                       uint64_t delta = 0;
+                                                       do {
+                                                               const uint8_t* pointerLocation = (uint8_t*)fHeader + fSegments[segIndex]->fileoff() + segOffset;
+                                                               uint64_t value = P::getP(*(uint64_t*)pointerLocation);
+                                                               bool isRebase = (value & (1ULL << 62)) == 0;
+
+                                                               if (isRebase) {
+                                                                       //printf("(rebase): %-7s %-16s 0x%08llX  %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
+                                                               } else {
+                                                                       // the ordinal is bits [0..15]
+                                                                       uint16_t ordinal = value & 0xFFFF;
+                                                                       if (ordinal >= ordinalTableSize) {
+                                                                               throwf("bind ordinal is out of range");
+                                                                       }
+                                                               }
+
+                                                               // The delta is bits [51..61]
+                                                               // And bit 62 is to tell us if we are a rebase (0) or bind (1)
+                                                               value &= ~(1ULL << 62);
+                                                               delta = ( value & 0x3FF8000000000000 ) >> 51;
+                                                               segOffset += delta * sizeof(pint_t);
+                                                       } while ( delta != 0);
+                                                       break;
+                                               }
+                                               default:
+                                                       throwf("unknown threaded bind subopcode %d", immediate);
+                                       }
+                                       break;
+                               default:
+                                       throwf("bad bind opcode %d", *p);
+                       }
+               }
+       }
+}
+
 
 
 template <>
 
 
 template <>
@@ -1437,7 +1626,7 @@ bool MachOChecker<A>::hasTextRelocInRange(pint_t rangeStart, pint_t rangeEnd)
 }
 
 template <typename A>
 }
 
 template <typename A>
-bool MachOChecker<A>::addressIsRebaseSite(pint_t targetAddr)
+bool MachOChecker<A>::addressIsRebaseSite(pint_t targetAddr, pint_t& pointeeAddr)
 {
        // look at local relocs
        const macho_relocation_info<P>* const localRelocsEnd = &fLocalRelocations[fLocalRelocationsCount];
 {
        // look at local relocs
        const macho_relocation_info<P>* const localRelocsEnd = &fLocalRelocations[fLocalRelocationsCount];
@@ -1521,12 +1710,125 @@ bool MachOChecker<A>::addressIsRebaseSite(pint_t targetAddr)
                                default:
                                        throwf("bad rebase opcode %d", *p);
                        }
                                default:
                                        throwf("bad rebase opcode %d", *p);
                        }
-               }       
+               }
+               
+               // If we have no rebase opcodes, then we may be using the threaded rebase/bind combined
+               // format and need to parse the bind opcodes instead.
+               if ( (fDyldInfo->rebase_size() == 0) && (fDyldInfo->bind_size() != 0) ) {
+                       const uint8_t* p = (uint8_t*)fHeader + fDyldInfo->bind_off();
+                       const uint8_t* end = &p[fDyldInfo->bind_size()];
+
+                       uint8_t segIndex = 0;
+                       uint64_t segOffset = 0;
+                       uint32_t count;
+                       uint32_t skip;
+                       pint_t segStartAddr = 0;
+                       bool done = false;
+                       while ( !done && (p < end) ) {
+                               uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
+                               uint8_t opcode = *p & BIND_OPCODE_MASK;
+                               ++p;
+                               switch (opcode) {
+                                       case BIND_OPCODE_DONE:
+                                               done = true;
+                                               break;
+                                       case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
+                                               break;
+                                       case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
+                                               read_uleb128(p, end);
+                                               break;
+                                       case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
+                                               break;
+                                       case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
+                                               while (*p != '\0')
+                                                       ++p;
+                                               ++p;
+                                               break;
+                                       case BIND_OPCODE_SET_TYPE_IMM:
+                                               break;
+                                       case BIND_OPCODE_SET_ADDEND_SLEB:
+                                               read_sleb128(p, end);
+                                               break;
+                                       case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
+                                               segIndex = immediate;
+                                               segStartAddr = segStartAddress(segIndex);
+                                               segOffset = read_uleb128(p, end);
+                                               break;
+                                       case BIND_OPCODE_ADD_ADDR_ULEB:
+                                               segOffset += read_uleb128(p, end);
+                                               break;
+                                       case BIND_OPCODE_DO_BIND:
+                                               break;
+                                       case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
+                                               segOffset += read_uleb128(p, end) + sizeof(pint_t);
+                                               break;
+                                       case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
+                                               segOffset += immediate*sizeof(pint_t) + sizeof(pint_t);
+                                               break;
+                                       case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
+                                               count = read_uleb128(p, end);
+                                               skip = read_uleb128(p, end);
+                                               for (uint32_t i=0; i < count; ++i) {
+                                                       segOffset += skip + sizeof(pint_t);
+                                               }
+                                               break;
+                                       case BIND_OPCODE_THREADED:
+                                               // Note the immediate is a sub opcode
+                                               switch (immediate) {
+                                                       case BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB:
+                                                               count = read_uleb128(p, end);
+                                                               break;
+                                                       case BIND_SUBOPCODE_THREADED_APPLY: {
+                                                               uint64_t delta = 0;
+                                                               do {
+                                                                       uint8_t* pointerLocation = (uint8_t*)fHeader + fSegments[segIndex]->fileoff() + segOffset;
+                                                                       uint64_t value = P::getP(*(uint64_t*)pointerLocation);
+#if SUPPORT_ARCH_arm64e
+                                                                       bool isAuthenticated = (value & (1ULL << 63)) != 0;
+#endif
+                                                                       bool isRebase = (value & (1ULL << 62)) == 0;
+                                                                       if ( isRebase && ( (segStartAddr+segOffset) == targetAddr ) ) {
+
+#if SUPPORT_ARCH_arm64e
+                                                                               if (isAuthenticated) {
+                                                                                       uint64_t targetValue = value & 0xFFFFFFFFULL;
+                                                                                       targetValue += fBaseAddress;
+                                                                                       pointeeAddr = (pint_t)targetValue;
+                                                                               } else
+#endif
+                                                                               {
+                                                                                       // 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 = value & 0x0007F80000000000ULL;
+                                                                                       uint64_t bottom43Bits = value & 0x000007FFFFFFFFFFULL;
+                                                                                       uint64_t targetValue = ( top8Bits << 13 ) | (((intptr_t)(bottom43Bits << 21) >> 21) & 0x00FFFFFFFFFFFFFF);
+                                                                                       pointeeAddr = (pint_t)targetValue;
+                                                                               }
+                                                                               return true;
+                                                                       }
+
+                                                                       // The delta is bits [51..61]
+                                                                       // And bit 62 is to tell us if we are a rebase (0) or bind (1)
+                                                                       value &= ~(1ULL << 62);
+                                                                       delta = ( value & 0x3FF8000000000000 ) >> 51;
+                                                                       segOffset += delta * sizeof(pint_t);
+                                                               } while ( delta != 0 );
+                                                               break;
+                                                       }
+                                                       default:
+                                                               throwf("unknown threaded bind subopcode %d", immediate);
+                                               }
+                                               break;
+                                       default:
+                                               throwf("bad bind opcode %d", *p);
+                               }
+                       }
+               }
        }
        return false;
 }
 
        }
        return false;
 }
 
-
 template <typename A>
 bool MachOChecker<A>::addressIsBindingSite(pint_t targetAddr)
 {
 template <typename A>
 bool MachOChecker<A>::addressIsBindingSite(pint_t targetAddr)
 {
@@ -1619,6 +1921,35 @@ bool MachOChecker<A>::addressIsBindingSite(pint_t targetAddr)
                                                segOffset += skip + sizeof(pint_t);
                                        }
                                        break;
                                                segOffset += skip + sizeof(pint_t);
                                        }
                                        break;
+                               case BIND_OPCODE_THREADED:
+                                       // Note the immediate is a sub opcode
+                                       switch (immediate) {
+                                               case BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB:
+                                                       count = read_uleb128(p, end);
+                                                       break;
+                                               case BIND_SUBOPCODE_THREADED_APPLY: {
+                                                       uint64_t delta = 0;
+                                                       do {
+                                                               uint8_t* pointerLocation = (uint8_t*)fHeader + fSegments[segIndex]->fileoff() + segOffset;
+                                                               uint64_t value = P::getP(*(uint64_t*)pointerLocation);
+                                                               bool isRebase = (value & (1ULL << 62)) == 0;
+                                                               if (!isRebase) {
+                                                                       if ( (segStartAddr+segOffset) == targetAddr )
+                                                                               return true;
+                                                               }
+
+                                                               // The delta is bits [51..61]
+                                                               // And bit 62 is to tell us if we are a rebase (0) or bind (1)
+                                                               value &= ~(1ULL << 62);
+                                                               delta = ( value & 0x3FF8000000000000 ) >> 51;
+                                                               segOffset += delta * sizeof(pint_t);
+                                                       } while ( delta != 0 );
+                                                       break;
+                                               }
+                                               default:
+                                                       throwf("unknown threaded bind subopcode %d", immediate);
+                                       }
+                                       break;
                                default:
                                        throwf("bad bind opcode %d", *p);
                        }
                                default:
                                        throwf("bad bind opcode %d", *p);
                        }
@@ -1729,10 +2060,11 @@ int main(int argc, const char* argv[])
                        else if ( strcmp(arg, "-verifier_error_list") == 0 ) {
                                printf("os_dylib_rpath_install_name\tOS dylibs (those in /usr/lib/ or /System/Library/) must be built with -install_name that is an absolute path - not an @rpath\n");
                                printf("os_dylib_bad_install_name\tOS dylibs (those in /usr/lib/ or /System/Library/) must be built with -install_name matching their file system location\n");
                        else if ( strcmp(arg, "-verifier_error_list") == 0 ) {
                                printf("os_dylib_rpath_install_name\tOS dylibs (those in /usr/lib/ or /System/Library/) must be built with -install_name that is an absolute path - not an @rpath\n");
                                printf("os_dylib_bad_install_name\tOS dylibs (those in /usr/lib/ or /System/Library/) must be built with -install_name matching their file system location\n");
-                               printf("os_dylib_rpath\tOS dylibs should not contain LC_RPATH load commands (from -rpath linker option)\n");
+                               printf("os_dylib_rpath\tOS dylibs should not contain LC_RPATH load commands (from -rpath linker option)(remove LD_RUNPATH_SEARCH_PATHS Xcode build setting)\n");
                                printf("os_dylib_flat_namespace\tOS dylibs should not be built with -flat_namespace\n");
                                printf("os_dylib_undefined_dynamic_lookup\tOS dylibs should not be built with -undefined dynamic_lookup\n");
                                printf("os_dylib_flat_namespace\tOS dylibs should not be built with -flat_namespace\n");
                                printf("os_dylib_undefined_dynamic_lookup\tOS dylibs should not be built with -undefined dynamic_lookup\n");
-                               printf("os_dylib_malformed\the mach-o is malformed\n");
+                               printf("os_dylib_malformed\tthe mach-o file is malformed\n");
+                               printf("macos_in_ios_support\t/System/iOSSupport/ should only contain mach-o files that support iosmac\n");
                                return 0;
                        }
                        else {
                                return 0;
                        }
                        else {