[lld] c5ffe97 - [lld/mac] Implement support for searching dylibs with @rpath/ in install name

Nico Weber via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 7 03:23:02 PDT 2021


Author: Nico Weber
Date: 2021-06-07T06:22:52-04:00
New Revision: c5ffe9798850a699c2229899712ca9d153f2a4b8

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

LOG: [lld/mac] Implement support for searching dylibs with @rpath/ in install name

Also adjust a few comments, and move the DylibFile comment talking about
umbrella next to the parameter again.

Differential Revision: https://reviews.llvm.org/D103783

Added: 
    lld/test/MachO/link-search-at-rpath.s

Modified: 
    lld/MachO/DriverUtils.cpp
    lld/MachO/InputFiles.cpp
    lld/MachO/InputFiles.h
    lld/test/MachO/rpath.s

Removed: 
    


################################################################################
diff  --git a/lld/MachO/DriverUtils.cpp b/lld/MachO/DriverUtils.cpp
index 01b174297e52..f04327456350 100644
--- a/lld/MachO/DriverUtils.cpp
+++ b/lld/MachO/DriverUtils.cpp
@@ -216,10 +216,10 @@ DylibFile *macho::loadDylib(MemoryBufferRef mbref, DylibFile *umbrella,
     file = make<DylibFile>(**result, umbrella, isBundleLoader);
 
     // parseReexports() can recursively call loadDylib(). That's fine since
-    // we wrote DylibFile we just loaded to the loadDylib cache via the `file`
-    // reference. But the recursive load can grow loadDylibs, so the `file`
-    // reference might become invalid after parseReexports() -- so copy the
-    // pointer it refers to before going on.
+    // we wrote the DylibFile we just loaded to the loadDylib cache via the
+    // `file` reference. But the recursive load can grow loadDylibs, so the
+    // `file` reference might become invalid after parseReexports() -- so copy
+    // the pointer it refers to before continuing.
     newFile = file;
     if (newFile->exportingFile)
       newFile->parseReexports(**result);

diff  --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp
index 2fe338f3489f..9051ae12d023 100644
--- a/lld/MachO/InputFiles.cpp
+++ b/lld/MachO/InputFiles.cpp
@@ -760,7 +760,8 @@ static DylibFile *findDylib(StringRef path, DylibFile *umbrella,
               resolveDylibPath((root + path).str()))
         return loadDylib(*dylibPath, umbrella);
 
-  // TODO: Expand @rpath, handle -dylib_file
+  // TODO: Handle -dylib_file
+
   SmallString<128> newPath;
   if (config->outputType == MH_EXECUTE &&
       path.consume_front("@executable_path/")) {
@@ -771,6 +772,15 @@ static DylibFile *findDylib(StringRef path, DylibFile *umbrella,
   } else if (path.consume_front("@loader_path/")) {
     path::append(newPath, sys::path::parent_path(umbrella->getName()), path);
     path = newPath;
+  } else if (path.startswith("@rpath/")) {
+    for (StringRef rpath : umbrella->rpaths) {
+      newPath.clear();
+      if (rpath.consume_front("@loader_path/"))
+        path::append(newPath, sys::path::parent_path(umbrella->getName()));
+      path::append(newPath, rpath, path.drop_front(strlen("@rpath/")));
+      if (Optional<std::string> dylibPath = resolveDylibPath(newPath))
+        return loadDylib(*dylibPath, umbrella);
+    }
   }
 
   if (currentTopLevelTapi) {
@@ -854,6 +864,11 @@ DylibFile::DylibFile(MemoryBufferRef mb, DylibFile *umbrella,
   if (!checkCompatibility(this))
     return;
 
+  for (auto *cmd : findCommands<rpath_command>(hdr, LC_RPATH)) {
+    StringRef rpath{reinterpret_cast<const char *>(cmd) + cmd->path};
+    rpaths.push_back(rpath);
+  }
+
   // Initialize symbols.
   exportingFile = isImplicitlyLinked(installName) ? this : this->umbrella;
   if (const load_command *cmd = findCommand(hdr, LC_DYLD_INFO_ONLY)) {

diff  --git a/lld/MachO/InputFiles.h b/lld/MachO/InputFiles.h
index 3c723948242b..29640b6c5fae 100644
--- a/lld/MachO/InputFiles.h
+++ b/lld/MachO/InputFiles.h
@@ -127,16 +127,9 @@ class OpaqueFile : public InputFile {
   static bool classof(const InputFile *f) { return f->kind() == OpaqueKind; }
 };
 
-// .dylib file
+// .dylib or .tbd file
 class DylibFile : public InputFile {
 public:
-  explicit DylibFile(MemoryBufferRef mb, DylibFile *umbrella,
-                     bool isBundleLoader = false);
-
-  explicit DylibFile(const llvm::MachO::InterfaceFile &interface,
-                     DylibFile *umbrella = nullptr,
-                     bool isBundleLoader = false);
-
   // Mach-O dylibs can re-export other dylibs as sub-libraries, meaning that the
   // symbols in those sub-libraries will be available under the umbrella
   // library's namespace. Those sub-libraries can also have their own
@@ -144,6 +137,12 @@ class DylibFile : public InputFile {
   // the root dylib to ensure symbols in the child library are correctly bound
   // to the root. On the other hand, if a dylib is being directly loaded
   // (through an -lfoo flag), then `umbrella` should be a nullptr.
+  explicit DylibFile(MemoryBufferRef mb, DylibFile *umbrella,
+                     bool isBundleLoader = false);
+  explicit DylibFile(const llvm::MachO::InterfaceFile &interface,
+                     DylibFile *umbrella = nullptr,
+                     bool isBundleLoader = false);
+
   void parseLoadCommands(MemoryBufferRef mb);
   void parseReexports(const llvm::MachO::InterfaceFile &interface);
 
@@ -152,6 +151,7 @@ class DylibFile : public InputFile {
   StringRef installName;
   DylibFile *exportingFile = nullptr;
   DylibFile *umbrella;
+  SmallVector<StringRef, 2> rpaths;
   uint32_t compatibilityVersion = 0;
   uint32_t currentVersion = 0;
   int64_t ordinal = 0; // Ordinal numbering starts from 1, so 0 is a sentinel

diff  --git a/lld/test/MachO/link-search-at-rpath.s b/lld/test/MachO/link-search-at-rpath.s
new file mode 100644
index 000000000000..dbc0d4b3cbf6
--- /dev/null
+++ b/lld/test/MachO/link-search-at-rpath.s
@@ -0,0 +1,38 @@
+# REQUIRES: x86
+
+# RUN: rm -rf %t; split-file %s %t
+# RUN: mkdir %t/subdir
+# RUN: mkdir %t/subdir2
+
+# RUN: llvm-mc -filetype obj -triple x86_64-apple-darwin %t/foo.s -o %t/foo.o
+# RUN: llvm-mc -filetype obj -triple x86_64-apple-darwin %t/bar.s -o %t/bar.o
+# RUN: llvm-mc -filetype obj -triple x86_64-apple-darwin %t/main.s -o %t/main.o
+
+# RUN: %lld -dylib -install_name @rpath/libfoo.dylib %t/foo.o -o %t/subdir/libfoo.dylib
+
+# RUN: %lld -dylib -reexport_library %t/subdir/libfoo.dylib \
+# RUN:     -rpath @loader_path/../foo \
+# RUN:     -rpath @loader_path/../subdir \
+# RUN:     -rpath @loader_path/../foo \
+# RUN:     %t/bar.o -o %t/subdir2/libbar.dylib
+
+# RUN: %lld -lSystem %t/main.o %t/subdir2/libbar.dylib -o %t/test
+# RUN: %lld -dylib -lSystem %t/main.o %t/subdir2/libbar.dylib -o %t/libtest.dylib
+
+#--- foo.s
+.globl _foo
+_foo:
+  retq
+
+#--- bar.s
+.globl _bar
+_bar:
+  retq
+
+#--- main.s
+.section __TEXT,__text
+.global _main
+_main:
+  callq _foo
+  callq _bar
+  ret

diff  --git a/lld/test/MachO/rpath.s b/lld/test/MachO/rpath.s
index dc998889a47c..5b404a36b26b 100644
--- a/lld/test/MachO/rpath.s
+++ b/lld/test/MachO/rpath.s
@@ -3,11 +3,14 @@
 # RUN: %lld -o %t %t.o
 
 ## Check that -rpath generates LC_RPATH.
-# RUN: %lld -o %t %t.o -rpath /some/rpath
+# RUN: %lld -o %t %t.o -rpath /some/rpath -rpath /another/rpath
 # RUN: llvm-objdump --macho --all-headers %t | FileCheck %s
 # CHECK:      LC_RPATH
 # CHECK-NEXT: cmdsize 24
 # CHECK-NEXT: path /some/rpath
+# CHECK:      LC_RPATH
+# CHECK-NEXT: cmdsize 32
+# CHECK-NEXT: path /another/rpath
 
 .text
 .global _main


        


More information about the llvm-commits mailing list