From 503a6a57ccb5e8e1d7ba6e46288cb0eb8492c965 Mon Sep 17 00:00:00 2001 From: Vy Nguyen Date: Thu, 10 Apr 2025 15:20:04 -0400 Subject: [PATCH 1/3] [lld-macho]Fix bug in finding "chained" re-exported libs. Details: When we have the following scenario: - lib_a re-exports lib_b - lib_b re-exports @rpath/lib_c + lib_b contains LC_RPATH Previously, lld-macho cannot find lib_c because it was attempting to resolve the '@rpath' from lib_b (which had no LC_RPATH defined). The change here is to also consider all the LC_RPATH rom lib_b when trying to find lib_c. Inspired by real-life example when linking with libXCTestSwiftSupport.dylib (which re-exports XCTest, which re-exports XCTestCore) --- lld/MachO/InputFiles.cpp | 24 +++++++++++++++--- lld/test/MachO/reexport-with-rpath.s | 37 ++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 3 deletions(-) create mode 100644 lld/test/MachO/reexport-with-rpath.s diff --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp index 9adfbc9d3f6f5..9afa5feaa1693 100644 --- a/lld/MachO/InputFiles.cpp +++ b/lld/MachO/InputFiles.cpp @@ -1633,6 +1633,17 @@ static DylibFile *findDylib(StringRef path, DylibFile *umbrella, if (std::optional dylibPath = resolveDylibPath(newPath.str())) return loadDylib(*dylibPath, umbrella); } + // If not found in umbrella, try the rpaths specified via -rpath too. + for (StringRef rpath : config->runtimePaths) { + newPath.clear(); + if (rpath.consume_front("@loader_path/")) { + fs::real_path(umbrella->getName(), newPath); + path::remove_filename(newPath); + } + path::append(newPath, rpath, path.drop_front(strlen("@rpath/"))); + if (std::optional dylibPath = resolveDylibPath(newPath.str())) + return loadDylib(*dylibPath, umbrella); + } } // FIXME: Should this be further up? @@ -1678,9 +1689,16 @@ static bool isImplicitlyLinked(StringRef path) { void DylibFile::loadReexport(StringRef path, DylibFile *umbrella, const InterfaceFile *currentTopLevelTapi) { DylibFile *reexport = findDylib(path, umbrella, currentTopLevelTapi); - if (!reexport) - error(toString(this) + ": unable to locate re-export with install name " + - path); + if (!reexport) { + // If not found in umbrella, retry since some rpaths might have been + // defined in "this" dyblib (which contains the LC_REEXPORT_DYLIB cmd) and + // not in the umbrella. + DylibFile *reexport2 = findDylib(path, this, currentTopLevelTapi); + if (!reexport2) { + error(toString(this) + ": unable to locate re-export with install name " + + path); + } + } } DylibFile::DylibFile(MemoryBufferRef mb, DylibFile *umbrella, diff --git a/lld/test/MachO/reexport-with-rpath.s b/lld/test/MachO/reexport-with-rpath.s new file mode 100644 index 0000000000000..f1b00ddc9f7e5 --- /dev/null +++ b/lld/test/MachO/reexport-with-rpath.s @@ -0,0 +1,37 @@ +# REQUIRES: x86 +# RUN: rm -rf %t; split-file %s %t +# RUN: mkdir -p %t/cc/two/three +# RUN: mkdir -p %t/bb/two/three +# RUN: mkdir -p %t/aa/two/three + +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/c.s -o %t/c.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/b.s -o %t/b.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/a.s -o %t/a.o + +# RUN: %lld -dylib -install_name @rpath/two/three/libCee.dylib %t/c.o -o %t/cc/two/three/libCee.dylib +# RUN: %lld -dylib -install_name @rpath/two/three/libBee.dylib -L%t/cc/two/three -sub_library libCee -lCee %t/b.o -o %t/bb/two/three/libBee.dylib -rpath %t/cc +# RUN: %lld -dylib -install_name @rpath/two/three/libAee.dylib -L%t/bb/two/three -sub_library libBee -lBee %t/a.o -o %t/aa/two/three/libAee.dylib +################## + + +#--- c.s +.text +.global _c_func +_c_func: + mov $0, %rax + ret + +#--- b.s +.text +.global _b_func + +_b_func: + mov $0, %rax + ret + +#--- a.s +.text +.global _a_func +_a_func: + mov $0, %rax + ret From 4363bb8c99b10007f0450b7e1b8b941985ea76b6 Mon Sep 17 00:00:00 2001 From: Vy Nguyen Date: Thu, 10 Apr 2025 15:30:36 -0400 Subject: [PATCH 2/3] formatting --- lld/test/MachO/reexport-with-rpath.s | 2 -- 1 file changed, 2 deletions(-) diff --git a/lld/test/MachO/reexport-with-rpath.s b/lld/test/MachO/reexport-with-rpath.s index f1b00ddc9f7e5..431962a9c2d8a 100644 --- a/lld/test/MachO/reexport-with-rpath.s +++ b/lld/test/MachO/reexport-with-rpath.s @@ -11,8 +11,6 @@ # RUN: %lld -dylib -install_name @rpath/two/three/libCee.dylib %t/c.o -o %t/cc/two/three/libCee.dylib # RUN: %lld -dylib -install_name @rpath/two/three/libBee.dylib -L%t/cc/two/three -sub_library libCee -lCee %t/b.o -o %t/bb/two/three/libBee.dylib -rpath %t/cc # RUN: %lld -dylib -install_name @rpath/two/three/libAee.dylib -L%t/bb/two/three -sub_library libBee -lBee %t/a.o -o %t/aa/two/three/libAee.dylib -################## - #--- c.s .text From 1ee15f45e61ee308a8003d6f90f4095491fbc165 Mon Sep 17 00:00:00 2001 From: Vy Nguyen Date: Sat, 12 Apr 2025 00:34:43 -0400 Subject: [PATCH 3/3] fixed typo in InputFiles.cpp --- lld/MachO/InputFiles.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp index 9afa5feaa1693..7a0f8e0d5c4d5 100644 --- a/lld/MachO/InputFiles.cpp +++ b/lld/MachO/InputFiles.cpp @@ -1691,7 +1691,7 @@ void DylibFile::loadReexport(StringRef path, DylibFile *umbrella, DylibFile *reexport = findDylib(path, umbrella, currentTopLevelTapi); if (!reexport) { // If not found in umbrella, retry since some rpaths might have been - // defined in "this" dyblib (which contains the LC_REEXPORT_DYLIB cmd) and + // defined in "this" dylib (which contains the LC_REEXPORT_DYLIB cmd) and // not in the umbrella. DylibFile *reexport2 = findDylib(path, this, currentTopLevelTapi); if (!reexport2) {