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);
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/")) {
} 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) {
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)) {
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
// 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);
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
--- /dev/null
+# 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
# 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