X-Git-Url: https://git.saurik.com/apple/ld64.git/blobdiff_plain/f410558f5d60087e4c310119a1751b437121c3b9..HEAD:/src/other/machochecker.cpp diff --git a/src/other/machochecker.cpp b/src/other/machochecker.cpp index ef6ba48..8e95458 100644 --- a/src/other/machochecker.cpp +++ b/src/other/machochecker.cpp @@ -134,6 +134,7 @@ private: uint8_t loadCommandSizeMask(); void checkSymbolTable(); void checkInitTerms(); + void checkThreadedRebaseBind(); void checkIndirectSymbolTable(); void checkRelocations(); void checkExternalReloation(const macho_relocation_info
* reloc); @@ -142,12 +143,13 @@ private: 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); - 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
*); pint_t getEntryPoint(const macho_thread_command
*); @@ -173,6 +175,8 @@ private: bool fWriteableSegmentWithAddrOver4G; bool fSlidableImage; bool fHasLC_RPATH; + bool fIsDebugVariant; + uint64_t fBaseAddress = 0; const macho_segment_command
* fFirstSegment; const macho_segment_command
* fFirstWritableSegment; const macho_segment_command
* fTEXTSegment;
@@ -356,7 +360,7 @@ template * const sectionsStart = (macho_section *)((char*)segCmd + sizeof(macho_segment_command ));
@@ -848,19 +856,35 @@ void MachOChecker::checkSection(const macho_segment_command * segCmd, const
// 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 * cmd = (macho_load_command *)((uint8_t*)fHeader + sizeof(macho_header ));
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ const macho_build_version_command * 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 *)cmd;
+ if ( buildVersCmd->platform() != PLATFORM_IOSMAC )
+ bad = true;
+ break;
+ }
+ cmd = (const macho_load_command *)(((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 * const localRelocsEnd = &fLocalRelocations[fLocalRelocationsCount];
@@ -1521,12 +1710,125 @@ bool MachOChecker::addressIsRebaseSite(pint_t targetAddr)
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;
}
-
template