diff options
| -rw-r--r-- | lld/include/lld/ReaderWriter/MachOLinkingContext.h | 51 | ||||
| -rw-r--r-- | lld/lib/Driver/DarwinLdDriver.cpp | 41 | ||||
| -rw-r--r-- | lld/lib/Driver/DarwinLdOptions.td | 24 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp | 26 | ||||
| -rw-r--r-- | lld/unittests/DriverTests/DarwinLdDriverTest.cpp | 52 |
5 files changed, 193 insertions, 1 deletions
diff --git a/lld/include/lld/ReaderWriter/MachOLinkingContext.h b/lld/include/lld/ReaderWriter/MachOLinkingContext.h index 3ae78665cab..699d2497f03 100644 --- a/lld/include/lld/ReaderWriter/MachOLinkingContext.h +++ b/lld/include/lld/ReaderWriter/MachOLinkingContext.h @@ -72,6 +72,52 @@ public: void setDoNothing(bool value) { _doNothing = value; } bool doNothing() const { return _doNothing; } + /// \brief The dylib's binary compatibility version, in the raw uint32 format. + /// + /// When building a dynamic library, this is the compatibility version that + /// gets embedded into the result. Other Mach-O binaries that link against + /// this library will store the compatibility version in its load command. At + /// runtime, the loader will verify that the binary is compatible with the + /// installed dynamic library. + uint32_t compatibilityVersion() const { return _compatibilityVersion; } + + /// \brief The dylib's current version, in the the raw uint32 format. + /// + /// When building a dynamic library, this is the current version that gets + /// embedded into the result. Other Mach-O binaries that link against + /// this library will store the compatibility version in its load command. + uint32_t currentVersion() const { return _currentVersion; } + + /// \brief The dylib's install name. + /// + /// Binaries that link against the dylib will embed this path into the dylib + /// load command. When loading the binaries at runtime, this is the location + /// on disk that the loader will look for the dylib. + StringRef installName() const { return _installName; } + + /// \brief Whether or not the dylib has side effects during initialization. + /// + /// Dylibs marked as being dead strippable provide the guarantee that loading + /// the dylib has no side effects, allowing the linker to strip out the dylib + /// when linking a binary that does not use any of its symbols. + bool deadStrippableDylib() const { return _deadStrippableDylib; } + + /// \brief The path to the executable that will load the bundle at runtime. + /// + /// When building a Mach-O bundle, this executable will be examined if there + /// are undefined symbols after the main link phase. It is expected that this + /// binary will be loading the bundle at runtime and will provide the symbols + /// at that point. + StringRef bundleLoader() const { return _bundleLoader; } + + void setCompatibilityVersion(uint32_t vers) { _compatibilityVersion = vers; } + void setCurrentVersion(uint32_t vers) { _currentVersion = vers; } + void setInstallName(StringRef name) { _installName = name; } + void setDeadStrippableDylib(bool deadStrippable) { + _deadStrippableDylib = deadStrippable; + } + void setBundleLoader(StringRef loader) { _bundleLoader = loader; } + static Arch archFromCpuType(uint32_t cputype, uint32_t cpusubtype); static Arch archFromName(StringRef archName); static uint32_t cpuTypeFromArch(Arch arch); @@ -91,6 +137,11 @@ private: OS _os; uint32_t _osMinVersion; uint64_t _pageZeroSize; + uint32_t _compatibilityVersion; + uint32_t _currentVersion; + StringRef _installName; + bool _deadStrippableDylib; + StringRef _bundleLoader; mutable std::unique_ptr<mach_o::KindHandler> _kindHandler; mutable std::unique_ptr<Reader> _machoReader; mutable std::unique_ptr<Writer> _writer; diff --git a/lld/lib/Driver/DarwinLdDriver.cpp b/lld/lib/Driver/DarwinLdDriver.cpp index c029f0f77e2..880e8a71754 100644 --- a/lld/lib/Driver/DarwinLdDriver.cpp +++ b/lld/lib/Driver/DarwinLdDriver.cpp @@ -154,6 +154,47 @@ bool DarwinLdDriver::parse(int argc, const char *argv[], if (parsedArgs->getLastArg(OPT_all_load)) globalWholeArchive = true; + // Handle -install_name + if (llvm::opt::Arg *installName = parsedArgs->getLastArg(OPT_install_name)) + ctx.setInstallName(installName->getValue()); + + // Handle -mark_dead_strippable_dylib + if (parsedArgs->getLastArg(OPT_mark_dead_strippable_dylib)) + ctx.setDeadStrippableDylib(true); + + // Handle -compatibility_version and -current_version + if (llvm::opt::Arg *vers = + parsedArgs->getLastArg(OPT_compatibility_version)) { + if (ctx.outputFileType() != mach_o::MH_DYLIB) { + diagnostics + << "error: -compatibility_version can only be used with -dylib\n"; + return true; + } + uint32_t parsedVers; + if (MachOLinkingContext::parsePackedVersion(vers->getValue(), parsedVers)) { + diagnostics << "error: -compatibility_version value is malformed\n"; + return true; + } + ctx.setCompatibilityVersion(parsedVers); + } + + if (llvm::opt::Arg *vers = parsedArgs->getLastArg(OPT_current_version)) { + if (ctx.outputFileType() != mach_o::MH_DYLIB) { + diagnostics << "-current_version can only be used with -dylib\n"; + return true; + } + uint32_t parsedVers; + if (MachOLinkingContext::parsePackedVersion(vers->getValue(), parsedVers)) { + diagnostics << "error: -current_version value is malformed\n"; + return true; + } + ctx.setCurrentVersion(parsedVers); + } + + // Handle -bundle_loader + if (llvm::opt::Arg *loader = parsedArgs->getLastArg(OPT_bundle_loader)) + ctx.setBundleLoader(loader->getValue()); + // Handle -arch xxx if (llvm::opt::Arg *archStr = parsedArgs->getLastArg(OPT_arch)) { ctx.setArch(MachOLinkingContext::archFromName(archStr->getValue())); diff --git a/lld/lib/Driver/DarwinLdOptions.td b/lld/lib/Driver/DarwinLdOptions.td index f1f8a78d97b..ff09d6a00b2 100644 --- a/lld/lib/Driver/DarwinLdOptions.td +++ b/lld/lib/Driver/DarwinLdOptions.td @@ -37,6 +37,30 @@ def entry : Separate<["-"], "e">, HelpText<"entry symbol name">,Group<grp_main>; // dylib executable options def grp_dylib : OptionGroup<"opts">, HelpText<"DYLIB EXECUTABLE OPTIONS">; +def install_name : Separate<["-"], "install_name">, + HelpText<"The dylib's install name">, Group<grp_dylib>; +def mark_dead_strippable_dylib : Flag<["-"], "mark_dead_strippable_dylib">, + HelpText<"Marks the dylib as having no side effects during initialization">, + Group<grp_dylib>; +def compatibility_version : Separate<["-"], "compatibility_version">, + HelpText<"The dylib's compatibility version">, Group<grp_dylib>; +def current_version : Separate<["-"], "current_version">, + HelpText<"The dylib's current version">, Group<grp_dylib>; + +// dylib executable options - compatibility aliases +def dylib_install_name : Separate<["-"], "dylib_install_name">, + Alias<install_name>; +def dylib_compatibility_version : + Separate<["-"], "dylib_compatibility_version">, + Alias<compatibility_version>; +def dylib_current_version : Separate<["-"], "dylib_current_version">, + Alias<current_version>; + +// bundle executable options +def grp_bundle : OptionGroup<"opts">, HelpText<"BUNDLE EXECUTABLE OPTIONS">; +def bundle_loader : Separate<["-"], "bundle_loader">, + HelpText<"The executable that will be loading this Mach-O bundle">, + Group<grp_bundle>; // library options def grp_libs : OptionGroup<"libs">, HelpText<"LIBRARY OPTIONS">; diff --git a/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp b/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp index 9e86014181d..39996f47ed4 100644 --- a/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp +++ b/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp @@ -124,7 +124,8 @@ uint32_t MachOLinkingContext::cpuSubtypeFromArch(Arch arch) { MachOLinkingContext::MachOLinkingContext() : _outputFileType(mach_o::MH_EXECUTE), _outputFileTypeStatic(false), _doNothing(false), _arch(arch_unknown), _os(OS::macOSX), _osMinVersion(0), - _pageZeroSize(0x1000), _kindHandler(nullptr) {} + _pageZeroSize(0x1000), _compatibilityVersion(0), _currentVersion(0), + _deadStrippableDylib(false), _kindHandler(nullptr) {} MachOLinkingContext::~MachOLinkingContext() {} @@ -204,6 +205,29 @@ bool MachOLinkingContext::validateImpl(raw_ostream &diagnostics) { } } + if (_currentVersion && _outputFileType != mach_o::MH_DYLIB) { + diagnostics << "error: -current_version can only be used with dylibs\n"; + return true; + } + + if (_compatibilityVersion && _outputFileType != mach_o::MH_DYLIB) { + diagnostics + << "error: -compatibility_version can only be used with dylibs\n"; + return true; + } + + if (_deadStrippableDylib && _outputFileType != mach_o::MH_DYLIB) { + diagnostics + << "error: -mark_dead_strippable_dylib can only be used with dylibs.\n"; + return true; + } + + if (!_bundleLoader.empty() && outputFileType() != mach_o::MH_BUNDLE) { + diagnostics + << "error: -bundle_loader can only be used with Mach-O bundles\n"; + return true; + } + return false; } diff --git a/lld/unittests/DriverTests/DarwinLdDriverTest.cpp b/lld/unittests/DriverTests/DarwinLdDriverTest.cpp index 70dcba1756a..494c877b4a5 100644 --- a/lld/unittests/DriverTests/DarwinLdDriverTest.cpp +++ b/lld/unittests/DriverTests/DarwinLdDriverTest.cpp @@ -169,4 +169,56 @@ TEST_F(DarwinLdParserTest, iOS_Simulator6) { EXPECT_TRUE(_context.minOS("", "6.0")); } +TEST_F(DarwinLdParserTest, compatibilityVersion) { + EXPECT_FALSE( + parse("ld", "-dylib", "-compatibility_version", "1.2.3", "a.o", nullptr)); + EXPECT_EQ(_context.compatibilityVersion(), 0x10203U); +} + +TEST_F(DarwinLdParserTest, compatibilityVersionInvalidType) { + EXPECT_TRUE(parse("ld", "-bundle", "-compatibility_version", "1.2.3", "a.o", + nullptr)); +} + +TEST_F(DarwinLdParserTest, compatibilityVersionInvalidValue) { + EXPECT_TRUE(parse("ld", "-bundle", "-compatibility_version", "1,2,3", "a.o", + nullptr)); +} + +TEST_F(DarwinLdParserTest, currentVersion) { + EXPECT_FALSE( + parse("ld", "-dylib", "-current_version", "1.2.3", "a.o", nullptr)); + EXPECT_EQ(_context.currentVersion(), 0x10203U); +} + +TEST_F(DarwinLdParserTest, currentVersionInvalidType) { + EXPECT_TRUE( + parse("ld", "-bundle", "-current_version", "1.2.3", "a.o", nullptr)); +} + +TEST_F(DarwinLdParserTest, currentVersionInvalidValue) { + EXPECT_TRUE( + parse("ld", "-bundle", "-current_version", "1,2,3", "a.o", nullptr)); +} + +TEST_F(DarwinLdParserTest, bundleLoader) { + EXPECT_FALSE( + parse("ld", "-bundle", "-bundle_loader", "/bin/ls", "a.o", nullptr)); + EXPECT_EQ(_context.bundleLoader(), "/bin/ls"); +} + +TEST_F(DarwinLdParserTest, bundleLoaderInvalidType) { + EXPECT_TRUE(parse("ld", "-bundle_loader", "/bin/ls", "a.o", nullptr)); +} + +TEST_F(DarwinLdParserTest, deadStrippableDylib) { + EXPECT_FALSE( + parse("ld", "-dylib", "-mark_dead_strippable_dylib", "a.o", nullptr)); + EXPECT_EQ(true, _context.deadStrippableDylib()); +} + +TEST_F(DarwinLdParserTest, deadStrippableDylibInvalidType) { + EXPECT_TRUE(parse("ld", "-mark_dead_strippable_dylib", "a.o", nullptr)); +} + } // end anonymous namespace |

