]> git.saurik.com Git - apple/ld64.git/blobdiff - src/other/dyldinfo.cpp
ld64-409.12.tar.gz
[apple/ld64.git] / src / other / dyldinfo.cpp
index e2719783b1efa0c7750c6feb791f00db5700b077..45fcb0f508bf6876323a5168fc397b28963a5f3f 100644 (file)
@@ -32,6 +32,7 @@
 #include <errno.h>
 
 #include <vector>
+#include <tuple>
 #include <set>
 #include <unordered_set>
 
@@ -615,6 +616,8 @@ const char* DyldInfoPrinter<A>::ordinalName(int libraryOrdinal)
                        return "main-executable";
                case BIND_SPECIAL_DYLIB_FLAT_LOOKUP:
                        return "flat-namespace";
+               case BIND_SPECIAL_DYLIB_WEAK_LOOKUP:
+                       return "weak";
        }
        if ( libraryOrdinal < BIND_SPECIAL_DYLIB_FLAT_LOOKUP )
                throw "unknown special ordinal";
@@ -644,12 +647,164 @@ const char* DyldInfoPrinter<A>::classicOrdinalName(int libraryOrdinal)
 template <typename A>
 void DyldInfoPrinter<A>::printRebaseInfo()
 {
+       bool seenThreadedRebase = false;
        if ( (fInfo == NULL) || (fInfo->rebase_off() == 0) ) {
-               printf("no compressed rebase info\n");
+               // 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 ( (fInfo->rebase_size() == 0) && (fInfo->bind_size() != 0) ) {
+                       const uint8_t* p = (uint8_t*)fHeader + fInfo->bind_off();
+                       const uint8_t* end = &p[fInfo->bind_size()];
+
+                       uint8_t type = 0;
+                       uint8_t flags = 0;
+                       uint8_t segIndex = 0;
+                       uint64_t segOffset = 0;
+                       const char* symbolName = NULL;
+                       const char* fromDylib = "??";
+                       int libraryOrdinal = 0;
+                       int64_t addend = 0;
+                       uint32_t count;
+                       uint32_t skip;
+                       pint_t segStartAddr = 0;
+                       const char* segName = "??";
+                       const char* typeName = "??";
+                       const char* weak_import = "";
+                       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;
+                                               fromDylib = ordinalName(libraryOrdinal);
+                                               break;
+                                       case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
+                                               libraryOrdinal = read_uleb128(p, end);
+                                               fromDylib = ordinalName(libraryOrdinal);
+                                               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;
+                                               }
+                                               fromDylib = ordinalName(libraryOrdinal);
+                                               break;
+                                       case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
+                                               symbolName = (char*)p;
+                                               while (*p != '\0')
+                                                       ++p;
+                                               ++p;
+                                               flags = immediate & BIND_SYMBOL_FLAGS_WEAK_IMPORT;
+                                               if ( flags != 0 )
+                                                       weak_import = " (weak import)";
+                                               else
+                                                       weak_import = "";
+                                               break;
+                                       case BIND_OPCODE_SET_TYPE_IMM:
+                                               type = immediate;
+                                               typeName = bindTypeName(type);
+                                               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);
+                                               segName = segmentName(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:
+                                                               printf("rebase information (from compressed dyld info):\n");
+                                                               printf("segment section          address     type         value\n");
+                                                               count = read_uleb128(p, end);
+                                                               seenThreadedRebase = true;
+                                                               break;
+                                                       case BIND_SUBOPCODE_THREADED_APPLY: {
+                                                               uint64_t delta = 0;
+                                                               do {
+                                                                       const uint8_t* pointerLocation = (uint8_t*)fHeader + fSegments[segIndex]->fileoff() + segOffset;
+                                                                       uint64_t value = P::getP(*(uint64_t*)pointerLocation);
+#if SUPPORT_ARCH_arm64e
+                                                                       uint16_t diversity = (uint16_t)(value >> 32);
+                                                                       bool hasAddressDiversity = (value & (1ULL << 48)) != 0;
+                                                                       ptrauth_key key = (ptrauth_key)((value >> 49) & 0x3);
+                                                                       bool isAuthenticated = (value & (1ULL << 63)) != 0;
+#endif
+                                                                       bool isRebase = (value & (1ULL << 62)) == 0;
+                                                                       if (isRebase) {
+
+#if SUPPORT_ARCH_arm64e
+                                                                               static const char* keyNames[] = {
+                                                                                       "IA", "IB", "DA", "DB"
+                                                                               };
+                                                                               if (isAuthenticated) {
+                                                                                       uint64_t targetValue = value & 0xFFFFFFFFULL;
+                                                                                       targetValue += fBaseAddress;
+                                                                                       printf("%-7s %-16s 0x%08llX  %s  0x%08llX (JOP: diversity %d, address %s, %s)\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, targetValue, diversity, hasAddressDiversity ? "true" : "false", keyNames[key]);
+                                                                               } 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);
+                                                                                       printf("%-7s %-16s 0x%08llX  %s  0x%08llX\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, targetValue);
+                                                                               }
+                                                                       }
+                                                                       // 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);
+                               }
+                       }
+               }
+
+               if (!seenThreadedRebase)
+                       printf("no compressed rebase info\n");
        }
        else {
                printf("rebase information (from compressed dyld info):\n");
-               printf("segment section          address     type\n");
+               printf("segment section          address     type         value\n");
 
                const uint8_t* p = (uint8_t*)fHeader + fInfo->rebase_off();
                const uint8_t* end = &p[fInfo->rebase_size()];
@@ -662,6 +817,8 @@ void DyldInfoPrinter<A>::printRebaseInfo()
                pint_t segStartAddr = 0;
                const char* segName = "??";
                const char* typeName = "??";
+               const uint8_t* pointerLocation = nullptr;
+               uint64_t value = 0;
                bool done = false;
                while ( !done && (p < end) ) {
                        uint8_t immediate = *p & REBASE_IMMEDIATE_MASK;
@@ -689,35 +846,42 @@ void DyldInfoPrinter<A>::printRebaseInfo()
                                        break;
                                case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
                                        for (int i=0; i < immediate; ++i) {
-                                               printf("%-7s %-16s 0x%08llX  %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
+                                               pointerLocation = (uint8_t*)fHeader + fSegments[segIndex]->fileoff() + segOffset;
+                                               value = P::getP(*(uint64_t*)pointerLocation);
+                                               printf("%-7s %-16s 0x%08llX  %s  0x%08llX\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, value);
                                                segOffset += sizeof(pint_t);
                                        }
                                        break;
                                case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
                                        count = read_uleb128(p, end);
                                        for (uint32_t i=0; i < count; ++i) {
-                                               printf("%-7s %-16s 0x%08llX  %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
+                                               pointerLocation = (uint8_t*)fHeader + fSegments[segIndex]->fileoff() + segOffset;
+                                               value = P::getP(*(uint64_t*)pointerLocation);
+                                               printf("%-7s %-16s 0x%08llX  %s  0x%08llX\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, value);
                                                segOffset += sizeof(pint_t);
                                        }
                                        break;
                                case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
-                                       printf("%-7s %-16s 0x%08llX  %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
+                                       pointerLocation = (uint8_t*)fHeader + fSegments[segIndex]->fileoff() + segOffset;
+                                       value = P::getP(*(uint64_t*)pointerLocation);
+                                       printf("%-7s %-16s 0x%08llX  %s  0x%08llX\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, value);
                                        segOffset += read_uleb128(p, end) + sizeof(pint_t);
                                        break;
                                case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
                                        count = read_uleb128(p, end);
                                        skip = read_uleb128(p, end);
                                        for (uint32_t i=0; i < count; ++i) {
-                                               printf("%-7s %-16s 0x%08llX  %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
+                                               pointerLocation = (uint8_t*)fHeader + fSegments[segIndex]->fileoff() + segOffset;
+                                               value = P::getP(*(uint64_t*)pointerLocation);
+                                               printf("%-7s %-16s 0x%08llX  %s  0x%08llX\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, value);
                                                segOffset += skip + sizeof(pint_t);
                                        }
                                        break;
                                default:
                                        throwf("bad rebase opcode %d", *p);
                        }
-               }       
+               }
        }
-
 }
 
 
@@ -791,11 +955,6 @@ void DyldInfoPrinter<A>::printRebaseInfoOpcodes()
 
 }
 
-
-
-
-
-
 template <typename A>
 void DyldInfoPrinter<A>::printBindingInfoOpcodes(bool weakbinding)
 {
@@ -901,6 +1060,20 @@ void DyldInfoPrinter<A>::printBindingInfoOpcodes(bool weakbinding)
                                        skip = read_uleb128(p, end);
                                        printf("0x%04X BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%d, 0x%08X)\n", opcodeOffset, count, skip);
                                        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);
+                                                       printf("0x%04X BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB(%d)\n", opcodeOffset, count);
+                                                       break;
+                                               case BIND_SUBOPCODE_THREADED_APPLY:
+                                                       printf("0x%04X BIND_SUBOPCODE_THREADED_APPLY\n", opcodeOffset);
+                                                       break;
+                                               default:
+                                                       throwf("unknown threaded bind subopcode %d", immediate);
+                                       }
+                                       break;
                                default:
                                        throwf("unknown bind opcode %d", *p);
                        }
@@ -909,7 +1082,20 @@ void DyldInfoPrinter<A>::printBindingInfoOpcodes(bool weakbinding)
 
 }
 
+struct ThreadedBindData {
+       ThreadedBindData(const char* symbolName, int64_t addend, int libraryOrdinal, uint8_t flags, uint8_t type)
+               : symbolName(symbolName), addend(addend), libraryOrdinal(libraryOrdinal), flags(flags), type(type) { }
 
+       std::tuple<const char*, int64_t, int, uint8_t, uint8_t> pack() const {
+               return std::make_tuple(symbolName, addend, libraryOrdinal, flags, type);
+       }
+
+       const char* symbolName  = nullptr;
+       int64_t addend                  = 0;
+       int libraryOrdinal              = 0;
+       uint8_t flags                   = 0;
+       uint8_t type                    = 0;
+};
 
 template <typename A>
 void DyldInfoPrinter<A>::printBindingInfo()
@@ -922,8 +1108,9 @@ void DyldInfoPrinter<A>::printBindingInfo()
                printf("segment section          address        type    addend dylib            symbol\n");
                const uint8_t* p = (uint8_t*)fHeader + fInfo->bind_off();
                const uint8_t* end = &p[fInfo->bind_size()];
-               
+
                uint8_t type = 0;
+               uint8_t flags = 0;
                uint8_t segIndex = 0;
                uint64_t segOffset = 0;
                const char* symbolName = NULL;
@@ -936,6 +1123,8 @@ void DyldInfoPrinter<A>::printBindingInfo()
                const char* segName = "??";
                const char* typeName = "??";
                const char* weak_import = "";
+               std::vector<ThreadedBindData> ordinalTable;
+               bool useThreadedRebaseBind = false;
                bool done = false;
                while ( !done && (p < end) ) {
                        uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
@@ -968,7 +1157,8 @@ void DyldInfoPrinter<A>::printBindingInfo()
                                        while (*p != '\0')
                                                ++p;
                                        ++p;
-                                       if ( (immediate & BIND_SYMBOL_FLAGS_WEAK_IMPORT) != 0 )
+                                       flags = immediate & BIND_SYMBOL_FLAGS_WEAK_IMPORT;
+                                       if ( flags != 0 )
                                                weak_import = " (weak import)";
                                        else
                                                weak_import = "";
@@ -990,8 +1180,12 @@ void DyldInfoPrinter<A>::printBindingInfo()
                                        segOffset += read_uleb128(p, end);
                                        break;
                                case BIND_OPCODE_DO_BIND:
-                                       printf("%-7s %-16s 0x%08llX %10s  %5lld %-16s %s%s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, fromDylib, symbolName, weak_import );
-                                       segOffset += sizeof(pint_t);
+                                       if (!useThreadedRebaseBind) {
+                                               printf("%-7s %-16s 0x%08llX %10s  %5lld %-16s %s%s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, fromDylib, symbolName, weak_import );
+                                               segOffset += sizeof(pint_t);
+                                       } else {
+                                               ordinalTable.push_back(ThreadedBindData(symbolName, addend, libraryOrdinal, flags, type));
+                                       }
                                        break;
                                case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
                                        printf("%-7s %-16s 0x%08llX %10s  %5lld %-16s %s%s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, fromDylib, symbolName, weak_import );
@@ -1009,6 +1203,68 @@ void DyldInfoPrinter<A>::printBindingInfo()
                                                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);
+                                                       ordinalTable.clear();
+                                                       ordinalTable.reserve(count);
+                                                       useThreadedRebaseBind = true;
+                                                       break;
+                                               case BIND_SUBOPCODE_THREADED_APPLY: {
+                                                       uint64_t delta = 0;
+                                                       do {
+                                                               const uint8_t* pointerLocation = (uint8_t*)fHeader + fSegments[segIndex]->fileoff() + segOffset;
+                                                               uint64_t value = P::getP(*(uint64_t*)pointerLocation);
+#if SUPPORT_ARCH_arm64e
+                                                               uint16_t diversity = (uint16_t)(value >> 32);
+                                                               bool hasAddressDiversity = (value & (1ULL << 48)) != 0;
+                                                               ptrauth_key key = (ptrauth_key)((value >> 49) & 0x3);
+                                                               bool isAuthenticated = (value & (1ULL << 63)) != 0;
+#endif
+                                                               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 >= ordinalTable.size()) {
+                                                                               fprintf(stderr, "bind ordinal is out of range\n");
+                                                                               break;
+                                                                       }
+                                                                       std::tie(symbolName, addend, libraryOrdinal, flags, type) = ordinalTable[ordinal].pack();
+                                                                       if ( (flags & BIND_SYMBOL_FLAGS_WEAK_IMPORT) != 0 )
+                                                                               weak_import = " (weak import)";
+                                                                       else
+                                                                               weak_import = "";
+                                                                       fromDylib = ordinalName(libraryOrdinal);
+#if SUPPORT_ARCH_arm64e
+                                                                       if (isAuthenticated) {
+                                                                               static const char* keyNames[] = {
+                                                                                       "IA", "IB", "DA", "DB"
+                                                                               };
+                                                                               printf("%-7s %-16s 0x%08llX %10s  %5lld %-16s %s%s with value 0x%016llX (JOP: diversity %d, address %s, %s)\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, fromDylib, symbolName, weak_import, value, diversity, hasAddressDiversity ? "true" : "false", keyNames[key]);
+                                                                       } else
+#endif
+                                                                       {
+                                                                               printf("%-7s %-16s 0x%08llX %10s  %5lld %-16s %s%s with value 0x%016llX\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, fromDylib, symbolName, weak_import, value );
+                                                                       }
+                                                               }
+
+                                                               // 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);
                        }
@@ -1734,6 +1990,8 @@ const char* DyldInfoPrinter<A>::sharedRegionKindName(uint8_t kind)
                        return "br22";
                case DYLD_CACHE_ADJ_V2_IMAGE_OFF_32:
                        return "off32";
+               case DYLD_CACHE_ADJ_V2_THREADED_POINTER_64:
+                       return "theaded-pointer64";
        }
 }
 
@@ -2009,6 +2267,93 @@ const char*      DyldInfoPrinter<arm64>::relocTypeName(uint8_t r_type)
 template <typename A>
 void DyldInfoPrinter<A>::printRelocRebaseInfo()
 {
+       // First check if we can find a magic section for threaded rebase
+       {
+               auto rebaseChain = [this](uintptr_t chainStartMappedAddress, uintptr_t chainStartVMAddress, uint64_t stepMultiplier, uintptr_t baseAddress) {
+                       uint64_t delta = 0;
+                       uintptr_t mappedAddress = chainStartMappedAddress;
+                       uintptr_t vmAddress = chainStartVMAddress;
+                       do {
+                               uint64_t value = *(uint64_t*)mappedAddress;
+
+                               uint8_t segIndex = segmentIndexForAddress(vmAddress);
+                               const char* segName = segmentName(segIndex);
+                               const char* sectName = sectionName(segIndex, vmAddress);
+
+#if SUPPORT_ARCH_arm64e
+                               uint16_t diversity = (uint16_t)(value >> 32);
+                               bool hasAddressDiversity = (value & (1ULL << 48)) != 0;
+                               ptrauth_key key = (ptrauth_key)((value >> 49) & 0x3);
+                               bool isAuthenticated = (value & (1ULL << 63)) != 0;
+#endif
+                               bool isRebase = (value & (1ULL << 62)) == 0;
+                               if (isRebase) {
+
+#if SUPPORT_ARCH_arm64e
+                                       if (isAuthenticated) {
+                                               uint64_t slide = 0;
+                                               static const char* keyNames[] = {
+                                                       "IA", "IB", "DA", "DB"
+                                               };
+                                               // The new value for a rebase is the low 32-bits of the threaded value plus the slide.
+                                               uint64_t newValue = (value & 0xFFFFFFFF) + slide;
+                                               // Add in the offset from the mach_header
+                                               newValue += baseAddress;
+                                               // We have bits to merge in to the discriminator
+                                               printf("%-7s %-16s 0x%08llX  %s  0x%08llX (JOP: diversity %d, address %s, %s)\n",
+                                                          segName, sectName, (uint64_t)vmAddress, "pointer", newValue,
+                                                          diversity, hasAddressDiversity ? "true" : "false", keyNames[key]);
+                                       } 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 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);
+                                               printf("%-7s %-16s 0x%08llX  %s  0x%08llX\n", segName, sectName, (uint64_t)vmAddress, "pointer", targetValue);
+                                       }
+                               }
+
+                               // 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;
+                               mappedAddress += delta * stepMultiplier;
+                               vmAddress += delta * stepMultiplier;
+                       } while ( delta != 0 );
+               };
+               for(const macho_segment_command<P>* segCmd : fSegments) {
+                       if (strcmp(segCmd->segname(), "__TEXT") != 0)
+                               continue;
+                       macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
+                       macho_section<P>* const sectionsEnd = &sectionsStart[segCmd->nsects()];
+                       for(macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
+                               if (strcmp(sect->sectname(), "__thread_starts") != 0)
+                                       continue;
+                               printf("rebase information (from __TEXT,__thread_starts):\n");
+                               printf("segment  section          address     type\n");
+                               const uint8_t* sectionContent = (uint8_t*)fHeader + segCmd->fileoff() + sect->offset();
+                               uint32_t *threadStarts = (uint32_t*)sectionContent;
+                               uint32_t *threadEnds = (uint32_t*)(sectionContent + sect->size());
+                               uint32_t threadStartsHeader = threadStarts[0];
+                               uint64_t stepMultiplier = (threadStartsHeader & 1) == 1 ? 8 : 4;
+                               for (uint32_t* threadOffset = threadStarts + 1; threadOffset != threadEnds; ++threadOffset) {
+                                       //printf("Thread start offset: 0x%016X\n", *threadOffset);
+                                       // If we get a 0xFFFFFFFF offset then ld64 overestimated the size required.  So skip the remainder
+                                       // of the entries.
+                                       if (*threadOffset == 0xFFFFFFFF)
+                                               break;
+                                       uint64_t chainStartVMAddr = fBaseAddress + *threadOffset;
+                                       uintptr_t chainStartMappedAddress = (uintptr_t)mappedAddressForVMAddress(chainStartVMAddr);
+                                       rebaseChain(chainStartMappedAddress, chainStartVMAddr, stepMultiplier, fBaseAddress);
+                               }
+                               return;
+                       }
+               }
+       }
+
        if ( fDynamicSymbolTable == NULL ) {
                printf("no classic dynamic symbol table");
        }
@@ -2412,14 +2757,6 @@ int main(int argc, const char* argv[])
                                                sPreferredArch = CPU_TYPE_POWERPC64;
                                        else if ( strcmp(arch, "ppc") == 0 )
                                                sPreferredArch = CPU_TYPE_POWERPC;
-                                       else if ( strcmp(arch, "i386") == 0 )
-                                               sPreferredArch = CPU_TYPE_I386;
-                                       else if ( strcmp(arch, "x86_64") == 0 )
-                                               sPreferredArch = CPU_TYPE_X86_64;
-#if SUPPORT_ARCH_arm64
-                                       else if ( strcmp(arch, "arm64") == 0 )
-                                               sPreferredArch = CPU_TYPE_ARM64;
-#endif
                                        else {
                                                if ( arch == NULL )
                                                        throw "-arch missing architecture name";