[lld] 5e49ee8 - [lld][MachO] Add support for $ld$install_name symbols

Alexander Shaposhnikov via llvm-commits llvm-commits at lists.llvm.org
Sat Jun 5 12:59:11 PDT 2021


Author: Alexander Shaposhnikov
Date: 2021-06-05T12:58:59-07:00
New Revision: 5e49ee87947f46b83150ee3f505fe7c89edae743

URL: https://github.com/llvm/llvm-project/commit/5e49ee87947f46b83150ee3f505fe7c89edae743
DIFF: https://github.com/llvm/llvm-project/commit/5e49ee87947f46b83150ee3f505fe7c89edae743.diff

LOG: [lld][MachO] Add support for $ld$install_name symbols

This diff adds support for $ld$install_name symbols.

Test plan: make check-lld-macho

Differential revision: https://reviews.llvm.org/D103746

Added: 
    lld/test/MachO/special-symbol-ld-install-name.s

Modified: 
    lld/MachO/InputFiles.cpp
    lld/MachO/InputFiles.h

Removed: 
    


################################################################################
diff  --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp
index 4c2c9fde76d4..604430d83b5b 100644
--- a/lld/MachO/InputFiles.cpp
+++ b/lld/MachO/InputFiles.cpp
@@ -849,7 +849,7 @@ DylibFile::DylibFile(MemoryBufferRef mb, DylibFile *umbrella,
     parseTrie(buf + c->export_off, c->export_size,
               [&](const Twine &name, uint64_t flags) {
                 StringRef savedName = saver.save(name);
-                if (handleLdSymbol(savedName))
+                if (handleLDSymbol(savedName))
                   return;
                 bool isWeakDef = flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION;
                 bool isTlv = flags & EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL;
@@ -937,7 +937,7 @@ DylibFile::DylibFile(const InterfaceFile &interface, DylibFile *umbrella,
     if (!symbol->getArchitectures().has(config->arch()))
       continue;
 
-    if (handleLdSymbol(symbol->getName()))
+    if (handleLDSymbol(symbol->getName()))
       continue;
 
     switch (symbol->getKind()) {
@@ -974,18 +974,23 @@ void DylibFile::parseReexports(const InterfaceFile &interface) {
 // $ld$ symbols modify the properties/behavior of the library (e.g. its install
 // name, compatibility version or hide/add symbols) for specific target
 // versions.
-bool DylibFile::handleLdSymbol(StringRef originalName) {
-  // $ld$ previous $ <installname> $ <compatversion> $ <platformstr> $
-  // <startversion> $ <endversion> $ <symbol-name> $
+bool DylibFile::handleLDSymbol(StringRef originalName) {
   if (!originalName.startswith("$ld$"))
     return false;
 
   StringRef action;
   StringRef name;
   std::tie(action, name) = originalName.drop_front(4 /* $ld$ */).split('$');
-  if (action.empty() || action != "previous")
-    return true;
+  if (action == "previous")
+    handleLDPreviousSymbol(name, originalName);
+  else if (action == "install_name")
+    handleLDInstallNameSymbol(name, originalName);
+  return true;
+}
 
+void DylibFile::handleLDPreviousSymbol(StringRef name, StringRef originalName) {
+  // originalName: $ld$ previous $ <installname> $ <compatversion> $
+  // <platformstr> $ <startversion> $ <endversion> $ <symbol-name> $
   StringRef installName;
   StringRef compatVersion;
   StringRef platformStr;
@@ -1002,26 +1007,26 @@ bool DylibFile::handleLdSymbol(StringRef originalName) {
   std::tie(symbolName, rest) = symbolName.split('$');
   // TODO: ld64 contains some logic for non-empty symbolName as well.
   if (!symbolName.empty())
-    return true;
+    return;
   unsigned platform;
   if (platformStr.getAsInteger(10, platform) ||
       platform != static_cast<unsigned>(config->platform()))
-    return true;
+    return;
 
   VersionTuple start;
   if (start.tryParse(startVersion)) {
     warn("failed to parse start version, symbol '" + originalName +
          "' ignored");
-    return true;
+    return;
   }
   VersionTuple end;
   if (end.tryParse(endVersion)) {
     warn("failed to parse end version, symbol '" + originalName + "' ignored");
-    return true;
+    return;
   }
   if (config->platformInfo.minimum < start ||
       config->platformInfo.minimum >= end)
-    return true;
+    return;
 
   dylibName = saver.save(installName);
 
@@ -1030,12 +1035,26 @@ bool DylibFile::handleLdSymbol(StringRef originalName) {
     if (cVersion.tryParse(compatVersion)) {
       warn("failed to parse compatibility version, symbol '" + originalName +
            "' ignored");
-      return true;
+      return;
     }
     compatibilityVersion = encodeVersion(cVersion);
   }
+}
 
-  return true;
+void DylibFile::handleLDInstallNameSymbol(StringRef name,
+                                          StringRef originalName) {
+  // originalName: $ld$ install_name $ os<version> $ install_name
+  StringRef condition, installName;
+  std::tie(condition, installName) = name.split('$');
+  VersionTuple version;
+  if (!condition.startswith("os") ||
+      version.tryParse(condition.drop_front(2 /* os */))) {
+    warn("failed to parse os version, symbol '" + originalName + "' ignored");
+    return;
+  }
+  if (version != config->platformInfo.minimum)
+    return;
+  dylibName = saver.save(installName);
 }
 
 ArchiveFile::ArchiveFile(std::unique_ptr<object::Archive> &&f)

diff  --git a/lld/MachO/InputFiles.h b/lld/MachO/InputFiles.h
index 21a54347fdac..7c6fcc3ddda6 100644
--- a/lld/MachO/InputFiles.h
+++ b/lld/MachO/InputFiles.h
@@ -175,7 +175,9 @@ class DylibFile : public InputFile {
   bool isBundleLoader;
 
 private:
-  bool handleLdSymbol(StringRef name);
+  bool handleLDSymbol(StringRef originalName);
+  void handleLDPreviousSymbol(StringRef name, StringRef originalName);
+  void handleLDInstallNameSymbol(StringRef name, StringRef originalName);
 };
 
 // .a file

diff  --git a/lld/test/MachO/special-symbol-ld-install-name.s b/lld/test/MachO/special-symbol-ld-install-name.s
new file mode 100644
index 000000000000..ca5163f70da3
--- /dev/null
+++ b/lld/test/MachO/special-symbol-ld-install-name.s
@@ -0,0 +1,55 @@
+# REQUIRES: x86
+
+# RUN: rm -rf %t; split-file --no-leading-lines %s %t
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/foo.s -o %t/foo.o
+
+## Case 1: special symbol $ld$install_name affects the install name
+## since the specified version 11.0.0 matches the target version 11.0.0
+
+# RUN: %lld -o %t/libfoo1.dylib %t/libLDInstallName.tbd %t/foo.o -dylib -platform_version macos 11.0.0 11.0.0
+# RUN: llvm-objdump --macho --dylibs-used %t/libfoo1.dylib | FileCheck --check-prefix=CASE1 %s
+# CASE1: /New (compatibility version 1.1.1, current version 5.0.0)
+
+## Case 2: special symbol $ld$install_name does not affect the install name
+## since the specified version 11.0.0 does not match the target version 12.0.0
+
+# RUN: %lld -o %t/libfoo2.dylib %t/libLDInstallName.tbd %t/foo.o -dylib -platform_version macos 12.0.0 12.0.0
+# RUN: llvm-objdump --macho --dylibs-used %t/libfoo2.dylib | FileCheck --check-prefix=CASE2 %s
+# CASE2: /Old (compatibility version 1.1.1, current version 5.0.0)
+
+## Check that we emit a warning for an invalid os version.
+
+# RUN: %no_fatal_warnings_lld -o %t/libfoo3.dylib %t/libLDInstallNameInvalid.tbd %t/foo.o -dylib \
+# RUN:  -platform_version macos 11.0.0 11.0.0 2>&1 | FileCheck --check-prefix=INVALID-VERSION %s
+
+# INVALID-VERSION: failed to parse os version, symbol '$ld$install_name$os11.a$/New' ignored
+
+#--- foo.s
+.long	_xxx at GOTPCREL
+
+#--- libLDInstallName.tbd
+--- !tapi-tbd-v3
+archs:           [ x86_64 ]
+uuids:           [ 'x86_64: 19311012-01AB-342E-812B-73A74271A715' ]
+platform:        macosx
+install-name:    '/Old'
+current-version: 5
+compatibility-version: 1.1.1
+exports:
+  - archs:           [ x86_64 ]
+    symbols:         [ '$ld$install_name$os11.0$/New', _xxx ]
+...
+
+#--- libLDInstallNameInvalid.tbd
+--- !tapi-tbd-v3
+archs:           [ x86_64 ]
+uuids:           [ 'x86_64: 19311011-01AB-342E-112B-73A74271A715' ]
+platform:        macosx
+install-name:    '/Old'
+current-version: 5
+compatibility-version: 1.1.1
+exports:
+  - archs:           [ x86_64 ]
+    symbols:         [ '$ld$install_name$os11.a$/New', _xxx ]
+...


        


More information about the llvm-commits mailing list