Skip to content

Commit c5f6190

Browse files
authored
[lld-macho]Fix bug in finding "chained" re-exported libs. (#135241)
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)
1 parent e44f776 commit c5f6190

File tree

2 files changed

+56
-3
lines changed

2 files changed

+56
-3
lines changed

lld/MachO/InputFiles.cpp

+21-3
Original file line numberDiff line numberDiff line change
@@ -1633,6 +1633,17 @@ static DylibFile *findDylib(StringRef path, DylibFile *umbrella,
16331633
if (std::optional<StringRef> dylibPath = resolveDylibPath(newPath.str()))
16341634
return loadDylib(*dylibPath, umbrella);
16351635
}
1636+
// If not found in umbrella, try the rpaths specified via -rpath too.
1637+
for (StringRef rpath : config->runtimePaths) {
1638+
newPath.clear();
1639+
if (rpath.consume_front("@loader_path/")) {
1640+
fs::real_path(umbrella->getName(), newPath);
1641+
path::remove_filename(newPath);
1642+
}
1643+
path::append(newPath, rpath, path.drop_front(strlen("@rpath/")));
1644+
if (std::optional<StringRef> dylibPath = resolveDylibPath(newPath.str()))
1645+
return loadDylib(*dylibPath, umbrella);
1646+
}
16361647
}
16371648

16381649
// FIXME: Should this be further up?
@@ -1678,9 +1689,16 @@ static bool isImplicitlyLinked(StringRef path) {
16781689
void DylibFile::loadReexport(StringRef path, DylibFile *umbrella,
16791690
const InterfaceFile *currentTopLevelTapi) {
16801691
DylibFile *reexport = findDylib(path, umbrella, currentTopLevelTapi);
1681-
if (!reexport)
1682-
error(toString(this) + ": unable to locate re-export with install name " +
1683-
path);
1692+
if (!reexport) {
1693+
// If not found in umbrella, retry since some rpaths might have been
1694+
// defined in "this" dylib (which contains the LC_REEXPORT_DYLIB cmd) and
1695+
// not in the umbrella.
1696+
DylibFile *reexport2 = findDylib(path, this, currentTopLevelTapi);
1697+
if (!reexport2) {
1698+
error(toString(this) + ": unable to locate re-export with install name " +
1699+
path);
1700+
}
1701+
}
16841702
}
16851703

16861704
DylibFile::DylibFile(MemoryBufferRef mb, DylibFile *umbrella,

lld/test/MachO/reexport-with-rpath.s

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# REQUIRES: x86
2+
# RUN: rm -rf %t; split-file %s %t
3+
# RUN: mkdir -p %t/cc/two/three
4+
# RUN: mkdir -p %t/bb/two/three
5+
# RUN: mkdir -p %t/aa/two/three
6+
7+
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/c.s -o %t/c.o
8+
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/b.s -o %t/b.o
9+
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/a.s -o %t/a.o
10+
11+
# RUN: %lld -dylib -install_name @rpath/two/three/libCee.dylib %t/c.o -o %t/cc/two/three/libCee.dylib
12+
# 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
13+
# 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
14+
15+
#--- c.s
16+
.text
17+
.global _c_func
18+
_c_func:
19+
mov $0, %rax
20+
ret
21+
22+
#--- b.s
23+
.text
24+
.global _b_func
25+
26+
_b_func:
27+
mov $0, %rax
28+
ret
29+
30+
#--- a.s
31+
.text
32+
.global _a_func
33+
_a_func:
34+
mov $0, %rax
35+
ret

0 commit comments

Comments
 (0)