From 0756aa397856d88f458c6836b24d36ca60fd1044 Mon Sep 17 00:00:00 2001 From: Alex Lorenz Date: Tue, 7 Dec 2021 17:51:44 -0800 Subject: [PATCH] [macho] add support for emitting macho files with two build version load commands This patch extends LLVM IR to add metadata that can be used to emit macho files with two build version load commands. It utilizes "darwin.target_variant.triple" and "darwin.target_variant.SDK Version" metadata names for that, which will be set by a future patch in clang. MachO uses two build version load commands to represent an object file / binary that is targeting both the macOS target, and the Mac Catalyst target. At runtime, a dynamic library that supports both targets can be loaded from either a native macOS or a Mac Catalyst app on a macOS system. We want to add support to this to upstream to LLVM to be able to build compiler-rt for both targets, to finish the complete support for the Mac Catalyst platform, which is right now targetable by upstream clang, but the compiler-rt bits aren't supported because of the lack of this multiple build version support. Differential Revision: https://reviews.llvm.org/D112189 --- llvm/include/llvm/IR/Module.h | 11 +++ llvm/include/llvm/MC/MCAssembler.h | 16 +++++ llvm/include/llvm/MC/MCObjectFileInfo.h | 19 +++++ llvm/include/llvm/MC/MCStreamer.h | 10 ++- llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 6 +- llvm/lib/IR/Module.cpp | 18 ++++- llvm/lib/MC/MCAsmStreamer.cpp | 9 +++ llvm/lib/MC/MCAssembler.cpp | 3 + llvm/lib/MC/MCMachOStreamer.cpp | 15 +++- llvm/lib/MC/MCStreamer.cpp | 50 +++++++++++--- llvm/lib/MC/MachObjectWriter.cpp | 80 +++++++++++++--------- .../test/MC/MachO/darwin-target-variant-reverse.ll | 25 +++++++ llvm/test/MC/MachO/darwin-target-variant.ll | 29 ++++++++ 13 files changed, 246 insertions(+), 45 deletions(-) create mode 100644 llvm/test/MC/MachO/darwin-target-variant-reverse.ll create mode 100644 llvm/test/MC/MachO/darwin-target-variant.ll diff --git a/llvm/include/llvm/IR/Module.h b/llvm/include/llvm/IR/Module.h index bd3a196..4ddbd6f 100644 --- a/llvm/include/llvm/IR/Module.h +++ b/llvm/include/llvm/IR/Module.h @@ -934,6 +934,17 @@ public: /// Set the partial sample profile ratio in the profile summary module flag, /// if applicable. void setPartialSampleProfileRatio(const ModuleSummaryIndex &Index); + + /// Get the target variant triple which is a string describing a variant of + /// the target host platform. For example, Mac Catalyst can be a variant + /// target triple for a macOS target. + /// @returns a string containing the target variant triple. + StringRef getDarwinTargetVariantTriple() const; + + /// Get the target variant version build SDK version metadata. + /// + /// An empty version is returned if no such metadata is attached. + VersionTuple getDarwinTargetVariantSDKVersion() const; }; /// Given "llvm.used" or "llvm.compiler.used" as a global name, collect the diff --git a/llvm/include/llvm/MC/MCAssembler.h b/llvm/include/llvm/MC/MCAssembler.h index 1f670e3..9d5cb62 100644 --- a/llvm/include/llvm/MC/MCAssembler.h +++ b/llvm/include/llvm/MC/MCAssembler.h @@ -153,6 +153,7 @@ private: MCLOHContainer LOHContainer; VersionInfoType VersionInfo; + VersionInfoType DarwinTargetVariantVersionInfo; /// Evaluate a fixup to a relocatable expression and the value which should be /// placed into the fixup. @@ -285,6 +286,21 @@ public: VersionInfo.SDKVersion = SDKVersion; } + const VersionInfoType &getDarwinTargetVariantVersionInfo() const { + return DarwinTargetVariantVersionInfo; + } + void setDarwinTargetVariantBuildVersion(MachO::PlatformType Platform, + unsigned Major, unsigned Minor, + unsigned Update, + VersionTuple SDKVersion) { + DarwinTargetVariantVersionInfo.EmitBuildVersion = true; + DarwinTargetVariantVersionInfo.TypeOrPlatform.Platform = Platform; + DarwinTargetVariantVersionInfo.Major = Major; + DarwinTargetVariantVersionInfo.Minor = Minor; + DarwinTargetVariantVersionInfo.Update = Update; + DarwinTargetVariantVersionInfo.SDKVersion = SDKVersion; + } + /// Reuse an assembler instance /// void reset(); diff --git a/llvm/include/llvm/MC/MCObjectFileInfo.h b/llvm/include/llvm/MC/MCObjectFileInfo.h index ba7450a..5e0ccca 100644 --- a/llvm/include/llvm/MC/MCObjectFileInfo.h +++ b/llvm/include/llvm/MC/MCObjectFileInfo.h @@ -427,6 +427,8 @@ private: bool PositionIndependent = false; MCContext *Ctx = nullptr; VersionTuple SDKVersion; + Optional DarwinTargetVariantTriple; + VersionTuple DarwinTargetVariantSDKVersion; void initMachOMCObjectFileInfo(const Triple &T); void initELFMCObjectFileInfo(const Triple &T, bool Large); @@ -442,6 +444,23 @@ public: } const VersionTuple &getSDKVersion() const { return SDKVersion; } + + void setDarwinTargetVariantTriple(const Triple &T) { + DarwinTargetVariantTriple = T; + } + + const Triple *getDarwinTargetVariantTriple() const { + return DarwinTargetVariantTriple ? DarwinTargetVariantTriple.getPointer() + : nullptr; + } + + void setDarwinTargetVariantSDKVersion(const VersionTuple &TheSDKVersion) { + DarwinTargetVariantSDKVersion = TheSDKVersion; + } + + const VersionTuple &getDarwinTargetVariantSDKVersion() const { + return DarwinTargetVariantSDKVersion; + } }; } // end namespace llvm diff --git a/llvm/include/llvm/MC/MCStreamer.h b/llvm/include/llvm/MC/MCStreamer.h index e00f50f..428e403 100644 --- a/llvm/include/llvm/MC/MCStreamer.h +++ b/llvm/include/llvm/MC/MCStreamer.h @@ -496,8 +496,16 @@ public: unsigned Minor, unsigned Update, VersionTuple SDKVersion) {} + virtual void emitDarwinTargetVariantBuildVersion(unsigned Platform, + unsigned Major, + unsigned Minor, + unsigned Update, + VersionTuple SDKVersion) {} + void emitVersionForTarget(const Triple &Target, - const VersionTuple &SDKVersion); + const VersionTuple &SDKVersion, + const Triple *DarwinTargetVariantTriple, + const VersionTuple &DarwinTargetVariantSDKVersion); /// Note in the output that the specified \p Func is a Thumb mode /// function (ARM target only). diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 828cb76..183f451 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -288,7 +288,11 @@ bool AsmPrinter::doInitialization(Module &M) { // use the directive, where it would need the same conditionalization // anyway. const Triple &Target = TM.getTargetTriple(); - OutStreamer->emitVersionForTarget(Target, M.getSDKVersion()); + Triple TVT(M.getDarwinTargetVariantTriple()); + OutStreamer->emitVersionForTarget( + Target, M.getSDKVersion(), + M.getDarwinTargetVariantTriple().empty() ? nullptr : &TVT, + M.getDarwinTargetVariantSDKVersion()); // Allow the target to emit any magic that it wants at the start of the file. emitStartOfAsmFile(M); diff --git a/llvm/lib/IR/Module.cpp b/llvm/lib/IR/Module.cpp index 63ea41f..a0485a5 100644 --- a/llvm/lib/IR/Module.cpp +++ b/llvm/lib/IR/Module.cpp @@ -750,8 +750,8 @@ void Module::setSDKVersion(const VersionTuple &V) { ConstantDataArray::get(Context, Entries)); } -VersionTuple Module::getSDKVersion() const { - auto *CM = dyn_cast_or_null(getModuleFlag("SDK Version")); +static VersionTuple getSDKVersionMD(Metadata *MD) { + auto *CM = dyn_cast_or_null(MD); if (!CM) return {}; auto *Arr = dyn_cast_or_null(CM->getValue()); @@ -775,6 +775,10 @@ VersionTuple Module::getSDKVersion() const { return Result; } +VersionTuple Module::getSDKVersion() const { + return getSDKVersionMD(getModuleFlag("SDK Version")); +} + GlobalVariable *llvm::collectUsedGlobalVariables( const Module &M, SmallVectorImpl &Vec, bool CompilerUsed) { const char *Name = CompilerUsed ? "llvm.compiler.used" : "llvm.used"; @@ -809,3 +813,13 @@ void Module::setPartialSampleProfileRatio(const ModuleSummaryIndex &Index) { } } } + +StringRef Module::getDarwinTargetVariantTriple() const { + if (const auto *MD = getModuleFlag("darwin.target_variant.triple")) + return cast(MD)->getString(); + return ""; +} + +VersionTuple Module::getDarwinTargetVariantSDKVersion() const { + return getSDKVersionMD(getModuleFlag("darwin.target_variant.SDK Version")); +} diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp index 2ca9210..6cd3bf0 100644 --- a/llvm/lib/MC/MCAsmStreamer.cpp +++ b/llvm/lib/MC/MCAsmStreamer.cpp @@ -168,6 +168,9 @@ public: unsigned Update, VersionTuple SDKVersion) override; void emitBuildVersion(unsigned Platform, unsigned Major, unsigned Minor, unsigned Update, VersionTuple SDKVersion) override; + void emitDarwinTargetVariantBuildVersion(unsigned Platform, unsigned Major, + unsigned Minor, unsigned Update, + VersionTuple SDKVersion) override; void emitThumbFunc(MCSymbol *Func) override; void emitAssignment(MCSymbol *Symbol, const MCExpr *Value) override; @@ -640,6 +643,12 @@ void MCAsmStreamer::emitBuildVersion(unsigned Platform, unsigned Major, EmitEOL(); } +void MCAsmStreamer::emitDarwinTargetVariantBuildVersion( + unsigned Platform, unsigned Major, unsigned Minor, unsigned Update, + VersionTuple SDKVersion) { + emitBuildVersion(Platform, Major, Minor, Update, SDKVersion); +} + void MCAsmStreamer::emitThumbFunc(MCSymbol *Func) { // This needs to emit to a temporary string to get properly quoted // MCSymbols when they have spaces in them. diff --git a/llvm/lib/MC/MCAssembler.cpp b/llvm/lib/MC/MCAssembler.cpp index d5e9f4f..a8837bb 100644 --- a/llvm/lib/MC/MCAssembler.cpp +++ b/llvm/lib/MC/MCAssembler.cpp @@ -89,6 +89,7 @@ MCAssembler::MCAssembler(MCContext &Context, BundleAlignSize(0), RelaxAll(false), SubsectionsViaSymbols(false), IncrementalLinkerCompatible(false), ELFHeaderEFlags(0) { VersionInfo.Major = 0; // Major version == 0 for "none specified" + DarwinTargetVariantVersionInfo.Major = 0; } MCAssembler::~MCAssembler() = default; @@ -109,6 +110,8 @@ void MCAssembler::reset() { LOHContainer.reset(); VersionInfo.Major = 0; VersionInfo.SDKVersion = VersionTuple(); + DarwinTargetVariantVersionInfo.Major = 0; + DarwinTargetVariantVersionInfo.SDKVersion = VersionTuple(); // reset objects owned by us if (getBackendPtr()) diff --git a/llvm/lib/MC/MCMachOStreamer.cpp b/llvm/lib/MC/MCMachOStreamer.cpp index aa94b14..3edf7a3 100644 --- a/llvm/lib/MC/MCMachOStreamer.cpp +++ b/llvm/lib/MC/MCMachOStreamer.cpp @@ -92,6 +92,9 @@ public: unsigned Update, VersionTuple SDKVersion) override; void emitBuildVersion(unsigned Platform, unsigned Major, unsigned Minor, unsigned Update, VersionTuple SDKVersion) override; + void emitDarwinTargetVariantBuildVersion(unsigned Platform, unsigned Major, + unsigned Minor, unsigned Update, + VersionTuple SDKVersion) override; void emitThumbFunc(MCSymbol *Func) override; bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override; void emitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) override; @@ -283,6 +286,13 @@ void MCMachOStreamer::emitBuildVersion(unsigned Platform, unsigned Major, Update, SDKVersion); } +void MCMachOStreamer::emitDarwinTargetVariantBuildVersion( + unsigned Platform, unsigned Major, unsigned Minor, unsigned Update, + VersionTuple SDKVersion) { + getAssembler().setDarwinTargetVariantBuildVersion( + (MachO::PlatformType)Platform, Major, Minor, Update, SDKVersion); +} + void MCMachOStreamer::emitThumbFunc(MCSymbol *Symbol) { // Remember that the function is a thumb function. Fixup and relocation // values will need adjusted. @@ -516,7 +526,10 @@ MCStreamer *llvm::createMachOStreamer(MCContext &Context, new MCMachOStreamer(Context, std::move(MAB), std::move(OW), std::move(CE), DWARFMustBeAtTheEnd, LabelSections); const Triple &Target = Context.getTargetTriple(); - S->emitVersionForTarget(Target, Context.getObjectFileInfo()->getSDKVersion()); + S->emitVersionForTarget( + Target, Context.getObjectFileInfo()->getSDKVersion(), + Context.getObjectFileInfo()->getDarwinTargetVariantTriple(), + Context.getObjectFileInfo()->getDarwinTargetVariantSDKVersion()); if (RelaxAll) S->getAssembler().setRelaxAll(true); return S; diff --git a/llvm/lib/MC/MCStreamer.cpp b/llvm/lib/MC/MCStreamer.cpp index b0da490..b056311 100644 --- a/llvm/lib/MC/MCStreamer.cpp +++ b/llvm/lib/MC/MCStreamer.cpp @@ -1308,8 +1308,10 @@ getMachoBuildVersionPlatformType(const Triple &Target) { llvm_unreachable("unexpected OS type"); } -void MCStreamer::emitVersionForTarget(const Triple &Target, - const VersionTuple &SDKVersion) { +void MCStreamer::emitVersionForTarget( + const Triple &Target, const VersionTuple &SDKVersion, + const Triple *DarwinTargetVariantTriple, + const VersionTuple &DarwinTargetVariantSDKVersion) { if (!Target.isOSBinFormatMachO() || !Target.isOSDarwin()) return; // Do we even know the version? @@ -1336,13 +1338,45 @@ void MCStreamer::emitVersionForTarget(const Triple &Target, auto LinkedTargetVersion = targetVersionOrMinimumSupportedOSVersion(Target, Version); auto BuildVersionOSVersion = getMachoBuildVersionSupportedOS(Target); + bool ShouldEmitBuildVersion = false; if (BuildVersionOSVersion.empty() || - LinkedTargetVersion >= BuildVersionOSVersion) - return emitBuildVersion(getMachoBuildVersionPlatformType(Target), - LinkedTargetVersion.getMajor(), - LinkedTargetVersion.getMinor().getValueOr(0), - LinkedTargetVersion.getSubminor().getValueOr(0), - SDKVersion); + LinkedTargetVersion >= BuildVersionOSVersion) { + if (Target.isMacCatalystEnvironment() && DarwinTargetVariantTriple && + DarwinTargetVariantTriple->isMacOSX()) { + emitVersionForTarget(*DarwinTargetVariantTriple, + DarwinTargetVariantSDKVersion, + /*TargetVariantTriple=*/nullptr, + /*TargetVariantSDKVersion=*/VersionTuple()); + emitDarwinTargetVariantBuildVersion( + getMachoBuildVersionPlatformType(Target), + LinkedTargetVersion.getMajor(), + LinkedTargetVersion.getMinor().getValueOr(0), + LinkedTargetVersion.getSubminor().getValueOr(0), SDKVersion); + return; + } + emitBuildVersion(getMachoBuildVersionPlatformType(Target), + LinkedTargetVersion.getMajor(), + LinkedTargetVersion.getMinor().getValueOr(0), + LinkedTargetVersion.getSubminor().getValueOr(0), + SDKVersion); + ShouldEmitBuildVersion = true; + } + + if (const Triple *TVT = DarwinTargetVariantTriple) { + if (Target.isMacOSX() && TVT->isMacCatalystEnvironment()) { + auto TVLinkedTargetVersion = + targetVersionOrMinimumSupportedOSVersion(*TVT, TVT->getiOSVersion()); + emitDarwinTargetVariantBuildVersion( + getMachoBuildVersionPlatformType(*TVT), + TVLinkedTargetVersion.getMajor(), + TVLinkedTargetVersion.getMinor().getValueOr(0), + TVLinkedTargetVersion.getSubminor().getValueOr(0), + DarwinTargetVariantSDKVersion); + } + } + + if (ShouldEmitBuildVersion) + return; emitVersionMin(getMachoVersionMinLoadCommandType(Target), LinkedTargetVersion.getMajor(), diff --git a/llvm/lib/MC/MachObjectWriter.cpp b/llvm/lib/MC/MachObjectWriter.cpp index 277d88c..3961cf3 100644 --- a/llvm/lib/MC/MachObjectWriter.cpp +++ b/llvm/lib/MC/MachObjectWriter.cpp @@ -779,6 +779,17 @@ uint64_t MachObjectWriter::writeObject(MCAssembler &Asm, LoadCommandsSize += sizeof(MachO::version_min_command); } + const MCAssembler::VersionInfoType &TargetVariantVersionInfo = + Layout.getAssembler().getDarwinTargetVariantVersionInfo(); + + // Add the target variant version info load command size, if used. + if (TargetVariantVersionInfo.Major != 0) { + ++NumLoadCommands; + assert(TargetVariantVersionInfo.EmitBuildVersion && + "target variant should use build version"); + LoadCommandsSize += sizeof(MachO::build_version_command); + } + // Add the data-in-code load command size, if used. unsigned NumDataRegions = Asm.getDataRegions().size(); if (NumDataRegions) { @@ -862,38 +873,43 @@ uint64_t MachObjectWriter::writeObject(MCAssembler &Asm, } // Write out the deployment target information, if it's available. - if (VersionInfo.Major != 0) { - auto EncodeVersion = [](VersionTuple V) -> uint32_t { - assert(!V.empty() && "empty version"); - unsigned Update = V.getSubminor() ? *V.getSubminor() : 0; - unsigned Minor = V.getMinor() ? *V.getMinor() : 0; - assert(Update < 256 && "unencodable update target version"); - assert(Minor < 256 && "unencodable minor target version"); - assert(V.getMajor() < 65536 && "unencodable major target version"); - return Update | (Minor << 8) | (V.getMajor() << 16); - }; - uint32_t EncodedVersion = EncodeVersion( - VersionTuple(VersionInfo.Major, VersionInfo.Minor, VersionInfo.Update)); - uint32_t SDKVersion = !VersionInfo.SDKVersion.empty() - ? EncodeVersion(VersionInfo.SDKVersion) - : 0; - if (VersionInfo.EmitBuildVersion) { - // FIXME: Currently empty tools. Add clang version in the future. - W.write(MachO::LC_BUILD_VERSION); - W.write(sizeof(MachO::build_version_command)); - W.write(VersionInfo.TypeOrPlatform.Platform); - W.write(EncodedVersion); - W.write(SDKVersion); - W.write(0); // Empty tools list. - } else { - MachO::LoadCommandType LCType - = getLCFromMCVM(VersionInfo.TypeOrPlatform.Type); - W.write(LCType); - W.write(sizeof(MachO::version_min_command)); - W.write(EncodedVersion); - W.write(SDKVersion); - } - } + auto EmitDeploymentTargetVersion = + [&](const MCAssembler::VersionInfoType &VersionInfo) { + auto EncodeVersion = [](VersionTuple V) -> uint32_t { + assert(!V.empty() && "empty version"); + unsigned Update = V.getSubminor() ? *V.getSubminor() : 0; + unsigned Minor = V.getMinor() ? *V.getMinor() : 0; + assert(Update < 256 && "unencodable update target version"); + assert(Minor < 256 && "unencodable minor target version"); + assert(V.getMajor() < 65536 && "unencodable major target version"); + return Update | (Minor << 8) | (V.getMajor() << 16); + }; + uint32_t EncodedVersion = EncodeVersion(VersionTuple( + VersionInfo.Major, VersionInfo.Minor, VersionInfo.Update)); + uint32_t SDKVersion = !VersionInfo.SDKVersion.empty() + ? EncodeVersion(VersionInfo.SDKVersion) + : 0; + if (VersionInfo.EmitBuildVersion) { + // FIXME: Currently empty tools. Add clang version in the future. + W.write(MachO::LC_BUILD_VERSION); + W.write(sizeof(MachO::build_version_command)); + W.write(VersionInfo.TypeOrPlatform.Platform); + W.write(EncodedVersion); + W.write(SDKVersion); + W.write(0); // Empty tools list. + } else { + MachO::LoadCommandType LCType = + getLCFromMCVM(VersionInfo.TypeOrPlatform.Type); + W.write(LCType); + W.write(sizeof(MachO::version_min_command)); + W.write(EncodedVersion); + W.write(SDKVersion); + } + }; + if (VersionInfo.Major != 0) + EmitDeploymentTargetVersion(VersionInfo); + if (TargetVariantVersionInfo.Major != 0) + EmitDeploymentTargetVersion(TargetVariantVersionInfo); // Write the data-in-code load command, if used. uint64_t DataInCodeTableEnd = RelocTableEnd + NumDataRegions * 8; diff --git a/llvm/test/MC/MachO/darwin-target-variant-reverse.ll b/llvm/test/MC/MachO/darwin-target-variant-reverse.ll new file mode 100644 index 0000000..6d51cd8 --- /dev/null +++ b/llvm/test/MC/MachO/darwin-target-variant-reverse.ll @@ -0,0 +1,25 @@ +; RUN: llc %s -filetype=obj -o - | llvm-objdump --macho --private-headers - | FileCheck %s + +target triple = "x86_64-apple-ios13.1-macabi"; +!llvm.module.flags = !{!0, !1, !2}; +!0 = !{i32 2, !"SDK Version", [2 x i32] [ i32 13, i32 1 ] }; +!1 = !{i32 1, !"darwin.target_variant.triple", !"x86_64-apple-macos10.15"}; +!2 = !{i32 2, !"darwin.target_variant.SDK Version", [2 x i32] [ i32 10, i32 15 ] }; + +define void @foo() { +entry: + ret void +} + +; CHECK: cmd LC_BUILD_VERSION +; CHECK-NEXT: cmdsize 24 +; CHECK-NEXT: platform macos +; CHECK-NEXT: sdk 10.15 +; CHECK-NEXT: minos 10.15 +; CHECK-NEXT: ntools 0 +; CHECK: cmd LC_BUILD_VERSION +; CHECK-NEXT: cmdsize 24 +; CHECK-NEXT: platform macCatalyst +; CHECK-NEXT: sdk 13.1 +; CHECK-NEXT: minos 13.1 +; CHECK-NEXT: ntools 0 diff --git a/llvm/test/MC/MachO/darwin-target-variant.ll b/llvm/test/MC/MachO/darwin-target-variant.ll new file mode 100644 index 0000000..d506ed9 --- /dev/null +++ b/llvm/test/MC/MachO/darwin-target-variant.ll @@ -0,0 +1,29 @@ +; RUN: llc %s -filetype=obj -o - | llvm-objdump --macho --private-headers - | FileCheck %s +; RUN: llc %s -filetype=asm -o - | FileCheck --check-prefix=ASM %s + +target triple = "x86_64-apple-macos10.15"; +!llvm.module.flags = !{!0, !1, !2}; +!0 = !{i32 2, !"SDK Version", [3 x i32] [ i32 10, i32 15, i32 1 ] }; +!1 = !{i32 1, !"darwin.target_variant.triple", !"x86_64-apple-ios13.1-macabi"}; +!2 = !{i32 2, !"darwin.target_variant.SDK Version", [2 x i32] [ i32 13, i32 2 ] }; + +define void @foo() { +entry: + ret void +} + +; CHECK: cmd LC_BUILD_VERSION +; CHECK-NEXT: cmdsize 24 +; CHECK-NEXT: platform macos +; CHECK-NEXT: sdk 10.15.1 +; CHECK-NEXT: minos 10.15 +; CHECK-NEXT: ntools 0 +; CHECK: cmd LC_BUILD_VERSION +; CHECK-NEXT: cmdsize 24 +; CHECK-NEXT: platform macCatalyst +; CHECK-NEXT: sdk 13.2 +; CHECK-NEXT: minos 13.1 +; CHECK-NEXT: ntools 0 + +; ASM: .build_version macos, 10, 15 sdk_version 10, 15, 1 +; ASM: .build_version macCatalyst, 13, 1 sdk_version 13, 2 -- 2.7.4