Loading...
--- dyld/dyld-1340/common/MachOFile.cpp
+++ dyld/dyld-1285.19/common/MachOFile.cpp
@@ -69,7 +69,6 @@
#include "MachOFile.h"
#include "Platform.h"
#include "SupportedArchs.h"
-#include "Universal.h"
#include "CodeSigningTypes.h"
#include "ObjC.h"
@@ -82,11 +81,8 @@
#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 {
@@ -274,6 +270,227 @@
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
@@ -575,9 +792,6 @@
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;
@@ -779,7 +993,7 @@
case DYLD_CHAINED_PTR_ARM64E:
case DYLD_CHAINED_PTR_ARM64E_USERLAND:
if ( fixupLoc->arm64e.bind.bind ) {
- uint32_t ordinal = fixupLoc->arm64e.bind.ordinal;
+ uint64_t ordinal = fixupLoc->arm64e.bind.ordinal;
uint64_t addend = (ordinal < targetAddends.size()) ? targetAddends[ordinal] : 0;
if ( fixupLoc->arm64e.bind.auth ) {
if ( addend >= tooLargeAuthAddend ) {
@@ -797,7 +1011,7 @@
break;
case DYLD_CHAINED_PTR_ARM64E_USERLAND24:
if ( fixupLoc->arm64e.bind24.bind ) {
- uint32_t ordinal = fixupLoc->arm64e.bind24.ordinal;
+ uint64_t ordinal = fixupLoc->arm64e.bind24.ordinal;
uint64_t addend = (ordinal < targetAddends.size()) ? targetAddends[ordinal] : 0;
if ( fixupLoc->arm64e.bind24.auth ) {
if ( addend >= tooLargeAuthAddend ) {
@@ -816,7 +1030,7 @@
case DYLD_CHAINED_PTR_64:
case DYLD_CHAINED_PTR_64_OFFSET: {
if ( fixupLoc->generic64.rebase.bind ) {
- uint32_t ordinal = fixupLoc->generic64.bind.ordinal;
+ uint64_t ordinal = fixupLoc->generic64.bind.ordinal;
uint64_t addend = (ordinal < targetAddends.size()) ? targetAddends[ordinal] : 0;
addend += fixupLoc->generic64.bind.addend;
if ( addend >= tooLargeRegularAddend ) {
@@ -828,7 +1042,7 @@
}
case DYLD_CHAINED_PTR_32:
if ( fixupLoc->generic32.bind.bind ) {
- uint32_t ordinal = fixupLoc->generic32.bind.ordinal;
+ uint64_t ordinal = fixupLoc->generic32.bind.ordinal;
uint64_t addend = (ordinal < targetAddends.size()) ? targetAddends[ordinal] : 0;
addend += fixupLoc->generic32.bind.addend;
if ( addend >= tooLargeRegularAddend ) {
@@ -1123,41 +1337,8 @@
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
-
- // 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 ( checkObjC ) {
typedef std::pair<VMAddress, VMAddress> Range;
__block std::vector<Range> constRanges;
@@ -1758,65 +1939,63 @@
return result;
}
-static void getArchNames(const GradedArchitectures& archs, bool isOSBinary, char buffer[256])
+static void getArchNames(const GradedArchs& archs, bool isOSBinary, char buffer[256])
{
buffer[0] = '\0';
- archs.forEachArch(isOSBinary, ^(mach_o::Architecture arch) {
+ archs.forEachArch(isOSBinary, ^(const char* archName) {
if ( buffer[0] != '\0' )
strlcat(buffer, "' or '", 256);
- strlcat(buffer, arch.name(), 256);
+ strlcat(buffer, archName, 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 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());
+
+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;
+ }
+ else {
+ BLOCK_ACCCESSIBLE_ARRAY(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);
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 {
- char strBuf[256];
- char gradedArchsBuf[256];
- getArchNames(archs, isOSBinary, gradedArchsBuf);
- diag.error("fat file, but missing compatible architecture (have '%s', need '%s')", uni->archNames(strBuf), gradedArchsBuf);
- return nullptr;
- }
}
else {
- hdr = (const Header*)fileContent;
+ mh = (const Header*)fileContent;
sliceLenOut = contentSize;
sliceOffsetOut = 0;
}
- std::span<const uint8_t> contents{(uint8_t*)hdr, (size_t)sliceLenOut};
+ std::span<const uint8_t> contents{(uint8_t*)mh, (size_t)sliceLenOut};
if ( !Header::isMachO(contents) ) {
diag.error("slice is not valid mach-o file");
return nullptr;
}
- if ( !archs.isCompatible(hdr->arch(), isOSBinary) ) {
- char gradedArchsBuf[256];
+ if ( archs.grade(mh->arch().cpuType(), mh->arch().cpuSubtype(), isOSBinary) == 0 ) {
+ BLOCK_ACCCESSIBLE_ARRAY(char, gradedArchsBuf, 256);
getArchNames(archs, isOSBinary, gradedArchsBuf);
- diag.error("mach-o file, but is an incompatible architecture (have '%s', need '%s')", hdr->archName(), gradedArchsBuf);
+ diag.error("mach-o file, but is an incompatible architecture (have '%s', need '%s')", mh->archName(), gradedArchsBuf);
return nullptr;
}
- if ( !hdr->loadableIntoProcess(platform, path, internalInstall) ) {
- Platform havePlatform = hdr->platformAndVersions().platform;
+ if ( !mh->loadableIntoProcess(platform, path, internalInstall) ) {
+ Platform havePlatform = mh->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*)hdr;
+ return (const MachOFile*)mh;
}
const uint8_t* MachOFile::trieWalk(Diagnostics& diag, const uint8_t* start, const uint8_t* end, const char* symbol)
@@ -2305,7 +2484,6 @@
this->authenticated = 0;
this->key = 0;
this->usesAddrDiversity = 0;
- this->padding = 0;
}
MachOFile::PointerMetaData::PointerMetaData(const ChainedFixupPointerOnDisk* fixupLoc, uint16_t pointer_format)
@@ -2315,7 +2493,6 @@
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: