-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[lld-macho]Fix bug in finding "chained" re-exported libs. #135241
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
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)
@llvm/pr-subscribers-lld Author: Vy Nguyen (oontvoo) ChangesDetails:
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) Full diff: https://github.com/llvm/llvm-project/pull/135241.diff 2 Files Affected:
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<StringRef> 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<StringRef> 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
|
@llvm/pr-subscribers-lld-macho Author: Vy Nguyen (oontvoo) ChangesDetails:
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) Full diff: https://github.com/llvm/llvm-project/pull/135241.diff 2 Files Affected:
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<StringRef> 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<StringRef> 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
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#134925 recently was kind of similar. But that was about tbd files and this here is about mach-o files.
I wonder if our behavior here is consistent across .tbd and .dylib inputs.
Whoops - the last commit didn't get pushed successfully - I've added it in PR/137672 |
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)
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)
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)
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)
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)
Details:
When we have the following scenario:
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)