summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/include/lld/ReaderWriter/MachOLinkingContext.h51
-rw-r--r--lld/lib/Driver/DarwinLdDriver.cpp41
-rw-r--r--lld/lib/Driver/DarwinLdOptions.td24
-rw-r--r--lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp26
-rw-r--r--lld/unittests/DriverTests/DarwinLdDriverTest.cpp52
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
OpenPOWER on IntegriCloud