Loading...
--- dyld/dyld-1284.13/common/MachOFile.cpp
+++ dyld/dyld-1330/common/MachOFile.cpp
@@ -69,6 +69,7 @@
#include "MachOFile.h"
#include "Platform.h"
#include "SupportedArchs.h"
+#include "Universal.h"
#include "CodeSigningTypes.h"
#include "ObjC.h"
@@ -81,8 +82,11 @@
#include "ObjCVisitor.h"
#endif
+using mach_o::GradedArchitectures;
using mach_o::Header;
using mach_o::Platform;
+using mach_o::Universal;
+using mach_o::Version32;
namespace dyld3 {
@@ -270,227 +274,6 @@
return strBuf;
}
-bool FatFile::isFatFileWithSlice(Diagnostics& diag, uint64_t fileLen, const GradedArchs& archs, bool isOSBinary,
- uint64_t& sliceOffset, uint64_t& sliceLen, bool& missingSlice) const
-{
- missingSlice = false;
- if ( (this->magic != OSSwapBigToHostInt32(FAT_MAGIC)) && (this->magic != OSSwapBigToHostInt32(FAT_MAGIC_64)) )
- return false;
-
- __block int bestGrade = 0;
- forEachSlice(diag, fileLen, ^(uint32_t sliceCpuType, uint32_t sliceCpuSubType, const void* sliceStart, uint64_t sliceSize, bool& stop) {
- if (int sliceGrade = archs.grade(sliceCpuType, sliceCpuSubType, isOSBinary)) {
- if ( sliceGrade > bestGrade ) {
- sliceOffset = (char*)sliceStart - (char*)this;
- sliceLen = sliceSize;
- bestGrade = sliceGrade;
- }
- }
- });
- if ( diag.hasError() )
- return false;
-
- if ( bestGrade == 0 )
- missingSlice = true;
-
- return (bestGrade != 0);
-}
-
-
-//////////////////////////// GradedArchs ////////////////////////////////////////
-
-
-#define GRADE_i386 CPU_TYPE_I386, CPU_SUBTYPE_I386_ALL, false
-#define GRADE_x86_64 CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL, false
-#define GRADE_x86_64h CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_H, false
-#define GRADE_armv7 CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7, false
-#define GRADE_armv7s CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7S, false
-#define GRADE_armv7k CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7K, false
-#define GRADE_armv6m CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6M, false
-#define GRADE_armv7m CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7M, false
-#define GRADE_armv7em CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7EM, false
-#define GRADE_armv8m CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V8M, false
-#define GRADE_arm64 CPU_TYPE_ARM64, CPU_SUBTYPE_ARM64_ALL, false
-#define GRADE_arm64e CPU_TYPE_ARM64, CPU_SUBTYPE_ARM64E, false
-#define GRADE_arm64e_pb CPU_TYPE_ARM64, CPU_SUBTYPE_ARM64E, true
-#define GRADE_arm64_32 CPU_TYPE_ARM64_32, CPU_SUBTYPE_ARM64_32_V8, false
-const GradedArchs GradedArchs::i386 = GradedArchs({GRADE_i386, 1});
-const GradedArchs GradedArchs::x86_64 = GradedArchs({GRADE_x86_64, 1});
-const GradedArchs GradedArchs::x86_64h = GradedArchs({GRADE_x86_64h, 2}, {GRADE_x86_64, 1});
-const GradedArchs GradedArchs::arm64 = GradedArchs({GRADE_arm64, 1});
-#if SUPPORT_ARCH_arm64e
-const GradedArchs GradedArchs::arm64e_keysoff = GradedArchs({GRADE_arm64e, 2}, {GRADE_arm64, 1});
-const GradedArchs GradedArchs::arm64e_keysoff_pb = GradedArchs({GRADE_arm64e_pb, 2}, {GRADE_arm64, 1});
-const GradedArchs GradedArchs::arm64e = GradedArchs({GRADE_arm64e, 1});
-const GradedArchs GradedArchs::arm64e_pb = GradedArchs({GRADE_arm64e_pb, 1});
-#endif
-const GradedArchs GradedArchs::armv7 = GradedArchs({GRADE_armv7, 1});
-const GradedArchs GradedArchs::armv7s = GradedArchs({GRADE_armv7s, 2}, {GRADE_armv7, 1});
-const GradedArchs GradedArchs::armv7k = GradedArchs({GRADE_armv7k, 1});
-const GradedArchs GradedArchs::armv7m = GradedArchs({GRADE_armv7m, 1});
-const GradedArchs GradedArchs::armv7em = GradedArchs({GRADE_armv7em, 1});
-
-
-#if SUPPORT_ARCH_arm64_32
-const GradedArchs GradedArchs::arm64_32 = GradedArchs({GRADE_arm64_32, 1});
-#endif
-
-#if BUILDING_LIBDYLD || BUILDING_UNIT_TESTS
-const GradedArchs GradedArchs::launch_AS = GradedArchs({GRADE_arm64e, 3}, {GRADE_arm64, 2}, {GRADE_x86_64, 1});
-const GradedArchs GradedArchs::launch_AS_Sim = GradedArchs({GRADE_arm64, 2}, {GRADE_x86_64, 1});
-const GradedArchs GradedArchs::launch_Intel_h = GradedArchs({GRADE_x86_64h, 3}, {GRADE_x86_64, 2}, {GRADE_i386, 1});
-const GradedArchs GradedArchs::launch_Intel = GradedArchs({GRADE_x86_64, 2}, {GRADE_i386, 1});
-const GradedArchs GradedArchs::launch_Intel_Sim = GradedArchs({GRADE_x86_64, 2}, {GRADE_i386, 1});
-#endif
-
-int GradedArchs::grade(uint32_t cputype, uint32_t cpusubtype, bool isOSBinary) const
-{
- for (const auto& p : _orderedCpuTypes) {
- if (p.type == 0) { break; }
- if ( (p.type == cputype) && (p.subtype == (cpusubtype & ~CPU_SUBTYPE_MASK)) ) {
- if ( p.osBinary ) {
- if ( isOSBinary )
- return p.grade;
- }
- else {
- return p.grade;
- }
- }
- }
- return 0;
-}
-
-const char* GradedArchs::name() const
-{
- mach_o::Architecture arch = mach_o::Architecture(_orderedCpuTypes[0].type, _orderedCpuTypes[0].subtype);
- // FIXME: Existing clients of this function don't expect the various arm64e names,
- // such as arm64e.old.
- if ( arch.usesArm64AuthPointers() )
- return "arm64e";
- return arch.name();
-}
-
-void GradedArchs::forEachArch(bool platformBinariesOnly, void (^handler)(const char*)) const
-{
- for (const auto& p : _orderedCpuTypes) {
- if (p.type == 0)
- break;
- if ( p.osBinary && !platformBinariesOnly )
- continue;
- // Note: mach_o::Architecture uses high bits to distiguish arm64e variant
- // passing the base cpu type/subtype will result in "arm64.old"
- if ( (p.type == CPU_TYPE_ARM64) && (p.subtype == CPU_SUBTYPE_ARM64E) )
- handler("arm64e");
- else
- handler(mach_o::Architecture(p.type, p.subtype).name());
- }
-}
-
-bool GradedArchs::checksOSBinary() const
-{
- for (const auto& p : _orderedCpuTypes) {
- if (p.type == 0) { return false; }
- if ( p.osBinary ) { return true; }
- }
- __builtin_unreachable();
-}
-
-bool GradedArchs::supports64() const
-{
- return (_orderedCpuTypes.front().type & CPU_ARCH_ABI64) != 0;
-}
-
-#if !TARGET_OS_SIMULATOR && __x86_64__
-static bool isHaswell()
-{
- // FIXME: figure out a commpage way to check this
- struct host_basic_info info;
- mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT;
- mach_port_t hostPort = mach_host_self();
- kern_return_t result = host_info(hostPort, HOST_BASIC_INFO, (host_info_t)&info, &count);
- mach_port_deallocate(mach_task_self(), hostPort);
- return (result == KERN_SUCCESS) && (info.cpu_subtype == CPU_SUBTYPE_X86_64_H);
-}
-#endif
-
-const GradedArchs& GradedArchs::forCurrentOS(bool keysOff, bool osBinariesOnly)
-{
-#if __arm64e__
- if ( osBinariesOnly )
- return (keysOff ? arm64e_keysoff_pb : arm64e_pb);
- else
- return (keysOff ? arm64e_keysoff : arm64e);
-#elif __ARM64_ARCH_8_32__
- return arm64_32;
-#elif __arm64__
- return arm64;
-#elif __x86_64__
- #if TARGET_OS_SIMULATOR
- return x86_64;
- #else
- return isHaswell() ? x86_64h : x86_64;
- #endif
-#else
- #error unknown platform
-#endif
-}
-
-#if BUILDING_LIBDYLD || BUILDING_UNIT_TESTS
-const GradedArchs& GradedArchs::launchCurrentOS(const char* simArches)
-{
-#if TARGET_OS_SIMULATOR
- // on Apple Silicon, there is both an arm64 and an x86_64 (under rosetta) simulators
- // You cannot tell if you are running under rosetta, so CoreSimulator sets SIMULATOR_ARCHS
- if ( strcmp(simArches, "arm64 x86_64") == 0 )
- return launch_AS_Sim;
- else
- return x86_64;
-#elif TARGET_OS_OSX
- #if __arm64__
- return launch_AS;
- #else
- return isHaswell() ? launch_Intel_h : launch_Intel;
- #endif
-#else
- // all other platforms use same grading for executables as dylibs
- return forCurrentOS(true, false);
-#endif
-}
-#endif // BUILDING_LIBDYLD
-
-const GradedArchs& GradedArchs::forName(const char* archName, bool keysOff)
-{
- if (strcmp(archName, "x86_64h") == 0 )
- return x86_64h;
- else if (strcmp(archName, "x86_64") == 0 )
- return x86_64;
-#if SUPPORT_ARCH_arm64e
- else if (strcmp(archName, "arm64e") == 0 )
- return keysOff ? arm64e_keysoff : arm64e;
-#endif
- else if (strcmp(archName, "arm64") == 0 )
- return arm64;
- else if (strcmp(archName, "armv7k") == 0 )
- return armv7k;
- else if (strcmp(archName, "armv7s") == 0 )
- return armv7s;
- else if (strcmp(archName, "armv7") == 0 )
- return armv7;
- else if (strcmp(archName, "armv7m") == 0 )
- return armv7m;
- else if (strcmp(archName, "armv7em") == 0 )
- return armv7em;
-#if SUPPORT_ARCH_arm64_32
- else if (strcmp(archName, "arm64_32") == 0 )
- return arm64_32;
-#endif
- else if (strcmp(archName, "i386") == 0 )
- return i386;
- assert(0 && "unknown arch name");
-}
-
-
-
//////////////////////////// MachOFile ////////////////////////////////////////
bool MachOFile::is64() const
@@ -792,6 +575,9 @@
void MachOFile::forEachDependentDylib(void (^callback)(const char* loadPath, bool isWeak, bool isReExport, bool isUpward, uint32_t compatVersion, uint32_t curVersion, bool& stop)) const
{
+ if ( this->isDyld() )
+ return;
+
Diagnostics diag;
__block unsigned count = 0;
__block bool stopped = false;
@@ -993,7 +779,7 @@
case DYLD_CHAINED_PTR_ARM64E:
case DYLD_CHAINED_PTR_ARM64E_USERLAND:
if ( fixupLoc->arm64e.bind.bind ) {
- uint64_t ordinal = fixupLoc->arm64e.bind.ordinal;
+ uint32_t ordinal = fixupLoc->arm64e.bind.ordinal;
uint64_t addend = (ordinal < targetAddends.size()) ? targetAddends[ordinal] : 0;
if ( fixupLoc->arm64e.bind.auth ) {
if ( addend >= tooLargeAuthAddend ) {
@@ -1011,7 +797,7 @@
break;
case DYLD_CHAINED_PTR_ARM64E_USERLAND24:
if ( fixupLoc->arm64e.bind24.bind ) {
- uint64_t ordinal = fixupLoc->arm64e.bind24.ordinal;
+ uint32_t ordinal = fixupLoc->arm64e.bind24.ordinal;
uint64_t addend = (ordinal < targetAddends.size()) ? targetAddends[ordinal] : 0;
if ( fixupLoc->arm64e.bind24.auth ) {
if ( addend >= tooLargeAuthAddend ) {
@@ -1030,7 +816,7 @@
case DYLD_CHAINED_PTR_64:
case DYLD_CHAINED_PTR_64_OFFSET: {
if ( fixupLoc->generic64.rebase.bind ) {
- uint64_t ordinal = fixupLoc->generic64.bind.ordinal;
+ uint32_t ordinal = fixupLoc->generic64.bind.ordinal;
uint64_t addend = (ordinal < targetAddends.size()) ? targetAddends[ordinal] : 0;
addend += fixupLoc->generic64.bind.addend;
if ( addend >= tooLargeRegularAddend ) {
@@ -1042,7 +828,7 @@
}
case DYLD_CHAINED_PTR_32:
if ( fixupLoc->generic32.bind.bind ) {
- uint64_t ordinal = fixupLoc->generic32.bind.ordinal;
+ uint32_t ordinal = fixupLoc->generic32.bind.ordinal;
uint64_t addend = (ordinal < targetAddends.size()) ? targetAddends[ordinal] : 0;
addend += fixupLoc->generic32.bind.addend;
if ( addend >= tooLargeRegularAddend ) {
@@ -1337,8 +1123,41 @@
if ( !passedLinkeditChecks )
return false;
+#if BUILDING_CACHE_BUILDER || BUILDING_CACHE_BUILDER_UNIT_TESTS
+
+ // Make sure we don't have cheaper roots patching (binds in the __objc_classlist) with bind opcodes
+ if ( checkObjC && hasOpcodeFixups() && hasSection("__DATA_CONST", "__objc_classlist") ) {
+ this->withFileLayout(diag, ^(const mach_o::Layout& layout) {
+ mach_o::Fixups fixups(layout);
+
+ __block uint64_t classListStartOffset = 0;
+ __block uint64_t classListEndOffset = 0;
+ this->forEachSection(^(const Header::SectionInfo& sectInfo, bool& stop) {
+ if ( sectInfo.segmentName != "__DATA_CONST" )
+ return;
+ if ( sectInfo.sectionName != "__objc_classlist" )
+ return;
+
+ classListStartOffset = sectInfo.address - layout.textUnslidVMAddr();
+ classListEndOffset = classListStartOffset + sectInfo.size;
+ stop = true;
+ });
+
+ fixups.forEachBindLocation_Opcodes(diag, ^(uint64_t runtimeOffset, uint32_t segmentIndex, unsigned int targetIndex, bool &stop) {
+ if ( (runtimeOffset < classListStartOffset) || (runtimeOffset > classListEndOffset) )
+ return;
+ passedLinkeditChecks = false;
+ failureReason("has opcode fixups and objc cheaper roots. Likely has unaligned fixups");
+ stop = true;
+ }, ^(uint64_t runtimeOffset, uint32_t segmentIndex, unsigned int overrideBindTargetIndex, bool &stop) {
+ });
+ });
+
+ if ( !passedLinkeditChecks )
+ return false;
+ }
+
// Check there are no pointer based objc method lists in CONST segments
-#if BUILDING_CACHE_BUILDER || BUILDING_CACHE_BUILDER_UNIT_TESTS
if ( checkObjC ) {
typedef std::pair<VMAddress, VMAddress> Range;
__block std::vector<Range> constRanges;
@@ -1939,63 +1758,65 @@
return result;
}
-static void getArchNames(const GradedArchs& archs, bool isOSBinary, char buffer[256])
+static void getArchNames(const GradedArchitectures& archs, bool isOSBinary, char buffer[256])
{
buffer[0] = '\0';
- archs.forEachArch(isOSBinary, ^(const char* archName) {
+ archs.forEachArch(isOSBinary, ^(mach_o::Architecture arch) {
if ( buffer[0] != '\0' )
strlcat(buffer, "' or '", 256);
- strlcat(buffer, archName, 256);
+ strlcat(buffer, arch.name(), 256);
});
}
-
-const MachOFile* MachOFile::compatibleSlice(Diagnostics& diag, uint64_t& sliceOffsetOut, uint64_t& sliceLenOut, const void* fileContent, size_t contentSize, const char* path, Platform platform, bool isOSBinary, const GradedArchs& archs, bool internalInstall)
-{
- const Header* mh = nullptr;
- if ( const dyld3::FatFile* ff = dyld3::FatFile::isFatFile(fileContent) ) {
- uint64_t sliceOffset;
- uint64_t sliceLen;
- bool missingSlice;
- if ( ff->isFatFileWithSlice(diag, contentSize, archs, isOSBinary, sliceOffset, sliceLen, missingSlice) ) {
- mh = (const Header*)((long)fileContent + sliceOffset);
- sliceLenOut = sliceLen;
- sliceOffsetOut = sliceOffset;
+
+const MachOFile* MachOFile::compatibleSlice(Diagnostics& diag, uint64_t& sliceOffsetOut, uint64_t& sliceLenOut, const void* fileContent, size_t contentSize, const char* path, Platform platform, bool isOSBinary, const GradedArchitectures& archs, bool internalInstall)
+{
+ const Header* hdr = nullptr;
+ std::span<const uint8_t> content = { (const uint8_t*)fileContent, contentSize };
+ if ( const Universal* uni = Universal::isUniversal(content) ) {
+ if ( mach_o::Error err = uni->valid(content.size()) ) {
+ diag.error("%s", err.message());
+ return nullptr;
+ }
+ Universal::Slice slice;
+ if ( uni->bestSlice(archs, isOSBinary, slice) ) {
+ hdr = (const Header*)slice.buffer.data();
+ sliceLenOut = slice.buffer.size();
+ sliceOffsetOut = slice.buffer.data() - content.data();
}
else {
- BLOCK_ACCCESSIBLE_ARRAY(char, gradedArchsBuf, 256);
+ char strBuf[256];
+ char gradedArchsBuf[256];
getArchNames(archs, isOSBinary, gradedArchsBuf);
-
- char strBuf[256];
- diag.error("fat file, but missing compatible architecture (have '%s', need '%s')", ff->archNames(strBuf, contentSize), gradedArchsBuf);
+ diag.error("fat file, but missing compatible architecture (have '%s', need '%s')", uni->archNames(strBuf), gradedArchsBuf);
return nullptr;
}
}
else {
- mh = (const Header*)fileContent;
+ hdr = (const Header*)fileContent;
sliceLenOut = contentSize;
sliceOffsetOut = 0;
}
- std::span<const uint8_t> contents{(uint8_t*)mh, (size_t)sliceLenOut};
+ std::span<const uint8_t> contents{(uint8_t*)hdr, (size_t)sliceLenOut};
if ( !Header::isMachO(contents) ) {
diag.error("slice is not valid mach-o file");
return nullptr;
}
- if ( archs.grade(mh->arch().cpuType(), mh->arch().cpuSubtype(), isOSBinary) == 0 ) {
- BLOCK_ACCCESSIBLE_ARRAY(char, gradedArchsBuf, 256);
+ if ( !archs.isCompatible(hdr->arch(), isOSBinary) ) {
+ char gradedArchsBuf[256];
getArchNames(archs, isOSBinary, gradedArchsBuf);
- diag.error("mach-o file, but is an incompatible architecture (have '%s', need '%s')", mh->archName(), gradedArchsBuf);
+ diag.error("mach-o file, but is an incompatible architecture (have '%s', need '%s')", hdr->archName(), gradedArchsBuf);
return nullptr;
}
- if ( !mh->loadableIntoProcess(platform, path, internalInstall) ) {
- Platform havePlatform = mh->platformAndVersions().platform;
+ if ( !hdr->loadableIntoProcess(platform, path, internalInstall) ) {
+ Platform havePlatform = hdr->platformAndVersions().platform;
diag.error("mach-o file (%s), but incompatible platform (have '%s', need '%s')", path, havePlatform.name().c_str(), platform.name().c_str());
return nullptr;
}
- return (const MachOFile*)mh;
+ return (const MachOFile*)hdr;
}
const uint8_t* MachOFile::trieWalk(Diagnostics& diag, const uint8_t* start, const uint8_t* end, const char* symbol)
@@ -2484,6 +2305,7 @@
this->authenticated = 0;
this->key = 0;
this->usesAddrDiversity = 0;
+ this->padding = 0;
}
MachOFile::PointerMetaData::PointerMetaData(const ChainedFixupPointerOnDisk* fixupLoc, uint16_t pointer_format)
@@ -2493,6 +2315,7 @@
this->authenticated = 0;
this->key = 0;
this->usesAddrDiversity = 0;
+ this->padding = 0;
switch ( pointer_format ) {
case DYLD_CHAINED_PTR_ARM64E:
case DYLD_CHAINED_PTR_ARM64E_KERNEL: