From 6592c09789e806aee0a8d375f62cdc54d81d7671 Mon Sep 17 00:00:00 2001 From: Alex Lorenz Date: Fri, 14 Dec 2018 01:14:10 +0000 Subject: [PATCH] [macho] save the SDK version stored in module metadata into the version min and build version load commands in the object file This commit introduces a new metadata node called "SDK Version". It will be set by the frontend to mark the platform SDK (macOS/iOS/etc) version which was used during that particular compilation. This node is used when machine code is emitted, by either saving the SDK version into the appropriate macho load command (version min/build version), or by emitting the assembly for these load commands with the SDK version specified as well. The assembly for both load commands is extended by allowing it to contain the sdk_version X, Y [, Z] trailing directive to represent the SDK version respectively. rdar://45774000 Differential Revision: https://reviews.llvm.org/D55612 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@349119 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/IR/Module.h | 12 ++ include/llvm/MC/MCAssembler.h | 11 +- include/llvm/MC/MCObjectFileInfo.h | 8 ++ include/llvm/MC/MCStreamer.h | 10 +- lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 2 +- lib/IR/Module.cpp | 40 +++++++ lib/MC/MCAsmStreamer.cpp | 25 +++- lib/MC/MCAssembler.cpp | 1 + lib/MC/MCMachOStreamer.cpp | 20 ++-- lib/MC/MCParser/DarwinAsmParser.cpp | 107 ++++++++++++++---- lib/MC/MCStreamer.cpp | 5 +- lib/MC/MachObjectWriter.cpp | 23 ++-- lib/Object/ModuleSymbolTable.cpp | 1 + .../ARM/build-version-sdk-version-errors.c | 19 ++++ test/MC/MachO/ARM/build-version-sdk-version.s | 13 +++ .../MC/MachO/build-version-with-sdk-version.s | 13 +++ test/MC/MachO/darwin-sdk-version.ll | 18 +++ ...version-min-load-command-with-sdk-errors.s | 10 ++ .../osx-version-min-load-command-with-sdk.s | 12 ++ 19 files changed, 297 insertions(+), 53 deletions(-) create mode 100644 test/MC/MachO/ARM/build-version-sdk-version-errors.c create mode 100644 test/MC/MachO/ARM/build-version-sdk-version.s create mode 100644 test/MC/MachO/build-version-with-sdk-version.s create mode 100644 test/MC/MachO/darwin-sdk-version.ll create mode 100644 test/MC/MachO/osx-version-min-load-command-with-sdk-errors.s create mode 100644 test/MC/MachO/osx-version-min-load-command-with-sdk.s diff --git a/include/llvm/IR/Module.h b/include/llvm/IR/Module.h index 91e44addbd6..ef4a4a9840b 100644 --- a/include/llvm/IR/Module.h +++ b/include/llvm/IR/Module.h @@ -49,6 +49,7 @@ class MemoryBuffer; class RandomNumberGenerator; template class SmallPtrSetImpl; class StructType; +class VersionTuple; /// A Module instance is used to store all the information related to an /// LLVM module. Modules are the top level container of all other LLVM @@ -868,6 +869,17 @@ public: /// Set that PLT should be avoid for RTLib calls. void setRtLibUseGOT(); + /// @name Utility functions for querying and setting the build SDK version + /// @{ + + /// Attach a build SDK version metadata to this module. + void setSDKVersion(const VersionTuple &V); + + /// Get the build SDK version metadata. + /// + /// An empty version is returned if no such metadata is attached. + VersionTuple getSDKVersion() const; + /// @} /// Take ownership of the given memory buffer. void setOwnedMemoryBuffer(std::unique_ptr MB); diff --git a/include/llvm/MC/MCAssembler.h b/include/llvm/MC/MCAssembler.h index 0f9499d705e..986c6e17548 100644 --- a/include/llvm/MC/MCAssembler.h +++ b/include/llvm/MC/MCAssembler.h @@ -23,6 +23,7 @@ #include "llvm/MC/MCFragment.h" #include "llvm/MC/MCLinkerOptimizationHint.h" #include "llvm/MC/MCSymbol.h" +#include "llvm/Support/VersionTuple.h" #include #include #include @@ -94,6 +95,8 @@ public: unsigned Major; unsigned Minor; unsigned Update; + /// An optional version of the SDK that was used to build the source. + VersionTuple SDKVersion; }; private: @@ -255,20 +258,24 @@ public: /// MachO deployment target version information. const VersionInfoType &getVersionInfo() const { return VersionInfo; } void setVersionMin(MCVersionMinType Type, unsigned Major, unsigned Minor, - unsigned Update) { + unsigned Update, + VersionTuple SDKVersion = VersionTuple()) { VersionInfo.EmitBuildVersion = false; VersionInfo.TypeOrPlatform.Type = Type; VersionInfo.Major = Major; VersionInfo.Minor = Minor; VersionInfo.Update = Update; + VersionInfo.SDKVersion = SDKVersion; } void setBuildVersion(MachO::PlatformType Platform, unsigned Major, - unsigned Minor, unsigned Update) { + unsigned Minor, unsigned Update, + VersionTuple SDKVersion = VersionTuple()) { VersionInfo.EmitBuildVersion = true; VersionInfo.TypeOrPlatform.Platform = Platform; VersionInfo.Major = Major; VersionInfo.Minor = Minor; VersionInfo.Update = Update; + VersionInfo.SDKVersion = SDKVersion; } /// Reuse an assembler instance diff --git a/include/llvm/MC/MCObjectFileInfo.h b/include/llvm/MC/MCObjectFileInfo.h index 97c1f270ba3..f8142ccd8ac 100644 --- a/include/llvm/MC/MCObjectFileInfo.h +++ b/include/llvm/MC/MCObjectFileInfo.h @@ -18,6 +18,7 @@ #include "llvm/ADT/Triple.h" #include "llvm/MC/MCSymbol.h" #include "llvm/Support/CodeGen.h" +#include "llvm/Support/VersionTuple.h" namespace llvm { class MCContext; @@ -390,6 +391,7 @@ private: bool PositionIndependent; MCContext *Ctx; Triple TT; + VersionTuple SDKVersion; void initMachOMCObjectFileInfo(const Triple &T); void initELFMCObjectFileInfo(const Triple &T, bool Large); @@ -399,6 +401,12 @@ private: public: const Triple &getTargetTriple() const { return TT; } + + void setSDKVersion(const VersionTuple &TheSDKVersion) { + SDKVersion = TheSDKVersion; + } + + const VersionTuple &getSDKVersion() const { return SDKVersion; } }; } // end namespace llvm diff --git a/include/llvm/MC/MCStreamer.h b/include/llvm/MC/MCStreamer.h index edf0a72d9c1..c9b91746e64 100644 --- a/include/llvm/MC/MCStreamer.h +++ b/include/llvm/MC/MCStreamer.h @@ -28,6 +28,7 @@ #include "llvm/Support/MD5.h" #include "llvm/Support/SMLoc.h" #include "llvm/Support/TargetParser.h" +#include "llvm/Support/VersionTuple.h" #include #include #include @@ -452,14 +453,17 @@ public: /// Specify the Mach-O minimum deployment target version. virtual void EmitVersionMin(MCVersionMinType Type, unsigned Major, - unsigned Minor, unsigned Update) {} + unsigned Minor, unsigned Update, + VersionTuple SDKVersion) {} /// Emit/Specify Mach-O build version command. /// \p Platform should be one of MachO::PlatformType. virtual void EmitBuildVersion(unsigned Platform, unsigned Major, - unsigned Minor, unsigned Update) {} + unsigned Minor, unsigned Update, + VersionTuple SDKVersion) {} - void EmitVersionForTarget(const Triple &Target); + void EmitVersionForTarget(const Triple &Target, + const VersionTuple &SDKVersion); /// Note in the output that the specified \p Func is a Thumb mode /// function (ARM target only). diff --git a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index a1622da33a6..c38457ff59e 100644 --- a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -263,7 +263,7 @@ bool AsmPrinter::doInitialization(Module &M) { // use the directive, where it would need the same conditionalization // anyway. const Triple &Target = TM.getTargetTriple(); - OutStreamer->EmitVersionForTarget(Target); + OutStreamer->EmitVersionForTarget(Target, M.getSDKVersion()); // Allow the target to emit any magic that it wants at the start of the file. EmitStartOfAsmFile(M); diff --git a/lib/IR/Module.cpp b/lib/IR/Module.cpp index 7d02a3956ff..70a16cbbf24 100644 --- a/lib/IR/Module.cpp +++ b/lib/IR/Module.cpp @@ -46,6 +46,7 @@ #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/RandomNumberGenerator.h" +#include "llvm/Support/VersionTuple.h" #include #include #include @@ -547,6 +548,45 @@ void Module::setRtLibUseGOT() { addModuleFlag(ModFlagBehavior::Max, "RtLibUseGOT", 1); } +void Module::setSDKVersion(const VersionTuple &V) { + SmallVector Entries; + Entries.push_back(V.getMajor()); + if (auto Minor = V.getMinor()) { + Entries.push_back(*Minor); + if (auto Subminor = V.getSubminor()) + Entries.push_back(*Subminor); + // Ignore the 'build' component as it can't be represented in the object + // file. + } + addModuleFlag(ModFlagBehavior::Warning, "SDK Version", + ConstantDataArray::get(Context, Entries)); +} + +VersionTuple Module::getSDKVersion() const { + auto *CM = dyn_cast_or_null(getModuleFlag("SDK Version")); + if (!CM) + return {}; + auto *Arr = dyn_cast_or_null(CM->getValue()); + if (!Arr) + return {}; + auto getVersionComponent = [&](unsigned Index) -> Optional { + if (Index >= Arr->getNumElements()) + return None; + return (unsigned)Arr->getElementAsInteger(Index); + }; + auto Major = getVersionComponent(0); + if (!Major) + return {}; + VersionTuple Result = VersionTuple(*Major); + if (auto Minor = getVersionComponent(1)) { + Result = VersionTuple(*Major, *Minor); + if (auto Subminor = getVersionComponent(2)) { + Result = VersionTuple(*Major, *Minor, *Subminor); + } + } + return Result; +} + GlobalVariable *llvm::collectUsedGlobalVariables( const Module &M, SmallPtrSetImpl &Set, bool CompilerUsed) { const char *Name = CompilerUsed ? "llvm.compiler.used" : "llvm.used"; diff --git a/lib/MC/MCAsmStreamer.cpp b/lib/MC/MCAsmStreamer.cpp index 463e9066616..0daec983dfd 100644 --- a/lib/MC/MCAsmStreamer.cpp +++ b/lib/MC/MCAsmStreamer.cpp @@ -147,9 +147,9 @@ public: void EmitLinkerOptions(ArrayRef Options) override; void EmitDataRegion(MCDataRegionType Kind) override; void EmitVersionMin(MCVersionMinType Kind, unsigned Major, unsigned Minor, - unsigned Update) override; + unsigned Update, VersionTuple SDKVersion) override; void EmitBuildVersion(unsigned Platform, unsigned Major, unsigned Minor, - unsigned Update) override; + unsigned Update, VersionTuple SDKVersion) override; void EmitThumbFunc(MCSymbol *Func) override; void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) override; @@ -514,11 +514,26 @@ static const char *getVersionMinDirective(MCVersionMinType Type) { llvm_unreachable("Invalid MC version min type"); } +static void EmitSDKVersionSuffix(raw_ostream &OS, + const VersionTuple &SDKVersion) { + if (SDKVersion.empty()) + return; + OS << '\t' << "sdk_version " << SDKVersion.getMajor(); + if (auto Minor = SDKVersion.getMinor()) { + OS << ", " << *Minor; + if (auto Subminor = SDKVersion.getSubminor()) { + OS << ", " << *Subminor; + } + } +} + void MCAsmStreamer::EmitVersionMin(MCVersionMinType Type, unsigned Major, - unsigned Minor, unsigned Update) { + unsigned Minor, unsigned Update, + VersionTuple SDKVersion) { OS << '\t' << getVersionMinDirective(Type) << ' ' << Major << ", " << Minor; if (Update) OS << ", " << Update; + EmitSDKVersionSuffix(OS, SDKVersion); EmitEOL(); } @@ -534,11 +549,13 @@ static const char *getPlatformName(MachO::PlatformType Type) { } void MCAsmStreamer::EmitBuildVersion(unsigned Platform, unsigned Major, - unsigned Minor, unsigned Update) { + unsigned Minor, unsigned Update, + VersionTuple SDKVersion) { const char *PlatformName = getPlatformName((MachO::PlatformType)Platform); OS << "\t.build_version " << PlatformName << ", " << Major << ", " << Minor; if (Update) OS << ", " << Update; + EmitSDKVersionSuffix(OS, SDKVersion); EmitEOL(); } diff --git a/lib/MC/MCAssembler.cpp b/lib/MC/MCAssembler.cpp index 1e23b6d816e..cde6a93a164 100644 --- a/lib/MC/MCAssembler.cpp +++ b/lib/MC/MCAssembler.cpp @@ -111,6 +111,7 @@ void MCAssembler::reset() { ELFHeaderEFlags = 0; LOHContainer.reset(); VersionInfo.Major = 0; + VersionInfo.SDKVersion = VersionTuple(); // reset objects owned by us if (getBackendPtr()) diff --git a/lib/MC/MCMachOStreamer.cpp b/lib/MC/MCMachOStreamer.cpp index 43e69605787..b30317e7467 100644 --- a/lib/MC/MCMachOStreamer.cpp +++ b/lib/MC/MCMachOStreamer.cpp @@ -89,10 +89,10 @@ public: void EmitAssemblerFlag(MCAssemblerFlag Flag) override; void EmitLinkerOptions(ArrayRef Options) override; void EmitDataRegion(MCDataRegionType Kind) override; - void EmitVersionMin(MCVersionMinType Kind, unsigned Major, - unsigned Minor, unsigned Update) override; - void EmitBuildVersion(unsigned Platform, unsigned Major, - unsigned Minor, unsigned Update) override; + void EmitVersionMin(MCVersionMinType Kind, unsigned Major, unsigned Minor, + unsigned Update, VersionTuple SDKVersion) override; + void EmitBuildVersion(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; @@ -270,14 +270,16 @@ void MCMachOStreamer::EmitDataRegion(MCDataRegionType Kind) { } void MCMachOStreamer::EmitVersionMin(MCVersionMinType Kind, unsigned Major, - unsigned Minor, unsigned Update) { - getAssembler().setVersionMin(Kind, Major, Minor, Update); + unsigned Minor, unsigned Update, + VersionTuple SDKVersion) { + getAssembler().setVersionMin(Kind, Major, Minor, Update, SDKVersion); } void MCMachOStreamer::EmitBuildVersion(unsigned Platform, unsigned Major, - unsigned Minor, unsigned Update) { + unsigned Minor, unsigned Update, + VersionTuple SDKVersion) { getAssembler().setBuildVersion((MachO::PlatformType)Platform, Major, Minor, - Update); + Update, SDKVersion); } void MCMachOStreamer::EmitThumbFunc(MCSymbol *Symbol) { @@ -507,7 +509,7 @@ MCStreamer *llvm::createMachOStreamer(MCContext &Context, new MCMachOStreamer(Context, std::move(MAB), std::move(OW), std::move(CE), DWARFMustBeAtTheEnd, LabelSections); const Triple &Target = Context.getObjectFileInfo()->getTargetTriple(); - S->EmitVersionForTarget(Target); + S->EmitVersionForTarget(Target, Context.getObjectFileInfo()->getSDKVersion()); if (RelaxAll) S->getAssembler().setRelaxAll(true); return S; diff --git a/lib/MC/MCParser/DarwinAsmParser.cpp b/lib/MC/MCParser/DarwinAsmParser.cpp index e6fc1fac81b..07926d6c1c9 100644 --- a/lib/MC/MCParser/DarwinAsmParser.cpp +++ b/lib/MC/MCParser/DarwinAsmParser.cpp @@ -459,7 +459,12 @@ public: bool parseBuildVersion(StringRef Directive, SMLoc Loc); bool parseVersionMin(StringRef Directive, SMLoc Loc, MCVersionMinType Type); + bool parseMajorMinorVersionComponent(unsigned *Major, unsigned *Minor, + const char *VersionName); + bool parseOptionalTrailingVersionComponent(unsigned *Component, + const char *ComponentName); bool parseVersion(unsigned *Major, unsigned *Minor, unsigned *Update); + bool parseSDKVersion(VersionTuple &SDKVersion); void checkVersion(StringRef Directive, StringRef Arg, SMLoc Loc, Triple::OSType ExpectedOS); }; @@ -1000,43 +1005,89 @@ bool DarwinAsmParser::parseDirectiveDataRegionEnd(StringRef, SMLoc) { return false; } -/// parseVersion ::= major, minor [, update] -bool DarwinAsmParser::parseVersion(unsigned *Major, unsigned *Minor, - unsigned *Update) { +static bool isSDKVersionToken(const AsmToken &Tok) { + return Tok.is(AsmToken::Identifier) && Tok.getIdentifier() == "sdk_version"; +} + +/// parseMajorMinorVersionComponent ::= major, minor +bool DarwinAsmParser::parseMajorMinorVersionComponent(unsigned *Major, + unsigned *Minor, + const char *VersionName) { // Get the major version number. if (getLexer().isNot(AsmToken::Integer)) - return TokError("invalid OS major version number, integer expected"); + return TokError(Twine("invalid ") + VersionName + + " major version number, integer expected"); int64_t MajorVal = getLexer().getTok().getIntVal(); if (MajorVal > 65535 || MajorVal <= 0) - return TokError("invalid OS major version number"); + return TokError(Twine("invalid ") + VersionName + " major version number"); *Major = (unsigned)MajorVal; Lex(); if (getLexer().isNot(AsmToken::Comma)) - return TokError("OS minor version number required, comma expected"); + return TokError(Twine(VersionName) + + " minor version number required, comma expected"); Lex(); // Get the minor version number. if (getLexer().isNot(AsmToken::Integer)) - return TokError("invalid OS minor version number, integer expected"); + return TokError(Twine("invalid ") + VersionName + + " minor version number, integer expected"); int64_t MinorVal = getLexer().getTok().getIntVal(); if (MinorVal > 255 || MinorVal < 0) - return TokError("invalid OS minor version number"); + return TokError(Twine("invalid ") + VersionName + " minor version number"); *Minor = MinorVal; Lex(); + return false; +} + +/// parseOptionalTrailingVersionComponent ::= , version_number +bool DarwinAsmParser::parseOptionalTrailingVersionComponent( + unsigned *Component, const char *ComponentName) { + assert(getLexer().is(AsmToken::Comma) && "comma expected"); + Lex(); + if (getLexer().isNot(AsmToken::Integer)) + return TokError(Twine("invalid ") + ComponentName + + " version number, integer expected"); + int64_t Val = getLexer().getTok().getIntVal(); + if (Val > 255 || Val < 0) + return TokError(Twine("invalid ") + ComponentName + " version number"); + *Component = Val; + Lex(); + return false; +} + +/// parseVersion ::= parseMajorMinorVersionComponent +/// parseOptionalTrailingVersionComponent +bool DarwinAsmParser::parseVersion(unsigned *Major, unsigned *Minor, + unsigned *Update) { + if (parseMajorMinorVersionComponent(Major, Minor, "OS")) + return true; // Get the update level, if specified *Update = 0; - if (getLexer().is(AsmToken::EndOfStatement)) + if (getLexer().is(AsmToken::EndOfStatement) || + isSDKVersionToken(getLexer().getTok())) return false; if (getLexer().isNot(AsmToken::Comma)) return TokError("invalid OS update specifier, comma expected"); + if (parseOptionalTrailingVersionComponent(Update, "OS update")) + return true; + return false; +} + +bool DarwinAsmParser::parseSDKVersion(VersionTuple &SDKVersion) { + assert(isSDKVersionToken(getLexer().getTok()) && "expected sdk_version"); Lex(); - if (getLexer().isNot(AsmToken::Integer)) - return TokError("invalid OS update version number, integer expected"); - int64_t UpdateVal = getLexer().getTok().getIntVal(); - if (UpdateVal > 255 || UpdateVal < 0) - return TokError("invalid OS update version number"); - *Update = UpdateVal; - Lex(); + unsigned Major, Minor; + if (parseMajorMinorVersionComponent(&Major, &Minor, "SDK")) + return true; + SDKVersion = VersionTuple(Major, Minor); + + // Get the subminor version, if specified. + if (getLexer().is(AsmToken::Comma)) { + unsigned Subminor; + if (parseOptionalTrailingVersionComponent(&Subminor, "SDK subminor")) + return true; + SDKVersion = VersionTuple(Major, Minor, Subminor); + } return false; } @@ -1066,10 +1117,10 @@ static Triple::OSType getOSTypeFromMCVM(MCVersionMinType Type) { } /// parseVersionMin -/// ::= .ios_version_min parseVersion -/// | .macosx_version_min parseVersion -/// | .tvos_version_min parseVersion -/// | .watchos_version_min parseVersion +/// ::= .ios_version_min parseVersion parseSDKVersion +/// | .macosx_version_min parseVersion parseSDKVersion +/// | .tvos_version_min parseVersion parseSDKVersion +/// | .watchos_version_min parseVersion parseSDKVersion bool DarwinAsmParser::parseVersionMin(StringRef Directive, SMLoc Loc, MCVersionMinType Type) { unsigned Major; @@ -1078,13 +1129,16 @@ bool DarwinAsmParser::parseVersionMin(StringRef Directive, SMLoc Loc, if (parseVersion(&Major, &Minor, &Update)) return true; + VersionTuple SDKVersion; + if (isSDKVersionToken(getLexer().getTok()) && parseSDKVersion(SDKVersion)) + return true; + if (parseToken(AsmToken::EndOfStatement)) return addErrorSuffix(Twine(" in '") + Directive + "' directive"); Triple::OSType ExpectedOS = getOSTypeFromMCVM(Type); checkVersion(Directive, StringRef(), Loc, ExpectedOS); - - getStreamer().EmitVersionMin(Type, Major, Minor, Update); + getStreamer().EmitVersionMin(Type, Major, Minor, Update, SDKVersion); return false; } @@ -1100,7 +1154,7 @@ static Triple::OSType getOSTypeFromPlatform(MachO::PlatformType Type) { } /// parseBuildVersion -/// ::= .build_version (macos|ios|tvos|watchos), parseVersion +/// ::= .build_version (macos|ios|tvos|watchos), parseVersion parseSDKVersion bool DarwinAsmParser::parseBuildVersion(StringRef Directive, SMLoc Loc) { StringRef PlatformName; SMLoc PlatformLoc = getTok().getLoc(); @@ -1126,14 +1180,17 @@ bool DarwinAsmParser::parseBuildVersion(StringRef Directive, SMLoc Loc) { if (parseVersion(&Major, &Minor, &Update)) return true; + VersionTuple SDKVersion; + if (isSDKVersionToken(getLexer().getTok()) && parseSDKVersion(SDKVersion)) + return true; + if (parseToken(AsmToken::EndOfStatement)) return addErrorSuffix(" in '.build_version' directive"); Triple::OSType ExpectedOS = getOSTypeFromPlatform((MachO::PlatformType)Platform); checkVersion(Directive, PlatformName, Loc, ExpectedOS); - - getStreamer().EmitBuildVersion(Platform, Major, Minor, Update); + getStreamer().EmitBuildVersion(Platform, Major, Minor, Update, SDKVersion); return false; } diff --git a/lib/MC/MCStreamer.cpp b/lib/MC/MCStreamer.cpp index 3722c0ad3c8..733dd4019dc 100644 --- a/lib/MC/MCStreamer.cpp +++ b/lib/MC/MCStreamer.cpp @@ -1045,7 +1045,8 @@ MCSymbol *MCStreamer::endSection(MCSection *Section) { return Sym; } -void MCStreamer::EmitVersionForTarget(const Triple &Target) { +void MCStreamer::EmitVersionForTarget(const Triple &Target, + const VersionTuple &SDKVersion) { if (!Target.isOSBinFormatMachO() || !Target.isOSDarwin()) return; // Do we even know the version? @@ -1071,5 +1072,5 @@ void MCStreamer::EmitVersionForTarget(const Triple &Target) { Target.getiOSVersion(Major, Minor, Update); } if (Major != 0) - EmitVersionMin(VersionType, Major, Minor, Update); + EmitVersionMin(VersionType, Major, Minor, Update, SDKVersion); } diff --git a/lib/MC/MachObjectWriter.cpp b/lib/MC/MachObjectWriter.cpp index c2e8dc1ef65..2fa65658ccf 100644 --- a/lib/MC/MachObjectWriter.cpp +++ b/lib/MC/MachObjectWriter.cpp @@ -846,18 +846,27 @@ uint64_t MachObjectWriter::writeObject(MCAssembler &Asm, // Write out the deployment target information, if it's available. if (VersionInfo.Major != 0) { - assert(VersionInfo.Update < 256 && "unencodable update target version"); - assert(VersionInfo.Minor < 256 && "unencodable minor target version"); - assert(VersionInfo.Major < 65536 && "unencodable major target version"); - uint32_t EncodedVersion = VersionInfo.Update | (VersionInfo.Minor << 8) | - (VersionInfo.Major << 16); + 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(0); // SDK version. + W.write(SDKVersion); W.write(0); // Empty tools list. } else { MachO::LoadCommandType LCType @@ -865,7 +874,7 @@ uint64_t MachObjectWriter::writeObject(MCAssembler &Asm, W.write(LCType); W.write(sizeof(MachO::version_min_command)); W.write(EncodedVersion); - W.write(0); // reserved. + W.write(SDKVersion); } } diff --git a/lib/Object/ModuleSymbolTable.cpp b/lib/Object/ModuleSymbolTable.cpp index b353ef3c835..33ce7d8109f 100644 --- a/lib/Object/ModuleSymbolTable.cpp +++ b/lib/Object/ModuleSymbolTable.cpp @@ -100,6 +100,7 @@ initializeRecordStreamer(const Module &M, MCObjectFileInfo MOFI; MCContext MCCtx(MAI.get(), MRI.get(), &MOFI); MOFI.InitMCObjectFileInfo(TT, /*PIC*/ false, MCCtx); + MOFI.setSDKVersion(M.getSDKVersion()); RecordStreamer Streamer(MCCtx, M); T->createNullTargetStreamer(Streamer); diff --git a/test/MC/MachO/ARM/build-version-sdk-version-errors.c b/test/MC/MachO/ARM/build-version-sdk-version-errors.c new file mode 100644 index 00000000000..bd568d58129 --- /dev/null +++ b/test/MC/MachO/ARM/build-version-sdk-version-errors.c @@ -0,0 +1,19 @@ +// RUN: not llvm-mc -triple x86_64-apple-macos %s 2>&1 | FileCheck %s + +.build_version macos,3,4,5 sdk_version +// CHECK: invalid SDK major version number, integer expected + +.build_version macos,3,4,5 sdk_version 10 +// CHECK: SDK minor version number required, comma expected + +.build_version macos,3,4,5 sdk_version 10, +// CHECK: invalid SDK minor version number, integer expected + +.build_version macos,3,4,5 sdk_version 10,1, +// CHECK: invalid SDK subminor version number, integer expected + +.build_version macos,3,4,5 sdk_version 10,10000 +// CHECK: invalid SDK minor version number + +.build_version macos,3,4,5 sdk_version 10,255,10000 +// CHECK: invalid SDK subminor version number diff --git a/test/MC/MachO/ARM/build-version-sdk-version.s b/test/MC/MachO/ARM/build-version-sdk-version.s new file mode 100644 index 00000000000..98f6d4d7bd2 --- /dev/null +++ b/test/MC/MachO/ARM/build-version-sdk-version.s @@ -0,0 +1,13 @@ +// RUN: llvm-mc -triple x86_64-apple-macos %s | FileCheck %s + +.build_version macos,3,4,5 sdk_version 10,14 +// CHECK: .build_version macos, 3, 4, 5 sdk_version 10, 14 + +.build_version ios,6,7 sdk_version 6,1,0 +// CHECK: .build_version ios, 6, 7 sdk_version 6, 1, 0 + +.build_version tvos,8,9 sdk_version 9,0,10 +// CHECK: .build_version tvos, 8, 9 sdk_version 9, 0, 10 + +.build_version watchos,10,11 sdk_version 10,11 +// CHECK: .build_version watchos, 10, 11 sdk_version 10, 11 diff --git a/test/MC/MachO/build-version-with-sdk-version.s b/test/MC/MachO/build-version-with-sdk-version.s new file mode 100644 index 00000000000..e96c2d520e1 --- /dev/null +++ b/test/MC/MachO/build-version-with-sdk-version.s @@ -0,0 +1,13 @@ +// RUN: llvm-mc -triple x86_64-apple-macos %s -filetype=obj -o - | llvm-readobj --macho-version-min | FileCheck %s + +// Test the formation of the sdk_version component of the version load +// command in the MachO. +.build_version macos, 10,13,2 sdk_version 10,14,1 + +// CHECK: MinVersion { +// CHECK: Cmd: LC_BUILD_VERSION +// CHECK: Size: 24 +// CHECK: Platform: macos +// CHECK: Version: 10.13.2 +// CHECK: SDK: 10.14.1 +// CHECK: } diff --git a/test/MC/MachO/darwin-sdk-version.ll b/test/MC/MachO/darwin-sdk-version.ll new file mode 100644 index 00000000000..5052e058ead --- /dev/null +++ b/test/MC/MachO/darwin-sdk-version.ll @@ -0,0 +1,18 @@ +; 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.14"; +!llvm.module.flags = !{!0}; +!0 = !{i32 2, !"SDK Version", [3 x i32] [ i32 10, i32 14, i32 2 ] }; + +define void @foo() { +entry: + ret void +} + +; CHECK: cmd LC_VERSION_MIN_MACOSX +; CHECK-NEXT: cmdsize 16 +; CHECK-NEXT: version 10.14 +; CHECK-NEXT: sdk 10.14.2 + +; ASM: .macosx_version_min 10, 14 sdk_version 10, 14, 2 diff --git a/test/MC/MachO/osx-version-min-load-command-with-sdk-errors.s b/test/MC/MachO/osx-version-min-load-command-with-sdk-errors.s new file mode 100644 index 00000000000..9547d07e319 --- /dev/null +++ b/test/MC/MachO/osx-version-min-load-command-with-sdk-errors.s @@ -0,0 +1,10 @@ +// RUN: not llvm-mc -triple x86_64-apple-macos %s -o - 2>&1 | FileCheck %s + +.macosx_version_min 10,13,2 sdk_version 10 +// CHECK: SDK minor version number required, comma expected + +.macosx_version_min 10,13,2 sdk_version 10, +// CHECK: invalid SDK minor version number, integer expected + +.macosx_version_min 10,13,2 sdk_version 10 +// CHECK: SDK minor version number required, comma expected diff --git a/test/MC/MachO/osx-version-min-load-command-with-sdk.s b/test/MC/MachO/osx-version-min-load-command-with-sdk.s new file mode 100644 index 00000000000..d2ad463d1d6 --- /dev/null +++ b/test/MC/MachO/osx-version-min-load-command-with-sdk.s @@ -0,0 +1,12 @@ +// RUN: llvm-mc -triple x86_64-apple-macos %s -filetype=obj -o - | llvm-readobj --macho-version-min | FileCheck %s + +// Test the formation of the sdk_version component of the version load +// command in the MachO. +.macosx_version_min 10,13,2 sdk_version 10,14 + +// CHECK: MinVersion { +// CHECK: Cmd: LC_VERSION_MIN_MACOSX +// CHECK: Size: 16 +// CHECK: Version: 10.13.2 +// CHECK: SDK: 10.14 +// CHECK: }