[lld-macho] Re-root absolute input file paths if -syslibroot is specified

Reviewed By: #lld-macho, gkm

Differential Revision: https://reviews.llvm.org/D100147
This commit is contained in:
Jez Ng 2021-04-15 21:14:30 -04:00
parent eb5b7d4497
commit db7a413e51
3 changed files with 99 additions and 17 deletions

View File

@ -76,16 +76,19 @@ static HeaderFileType getOutputType(const InputArgList &args) {
}
}
static Optional<std::string>
findAlongPathsWithExtensions(StringRef name, ArrayRef<StringRef> extensions) {
// Search for all possible combinations of `{root}/{name}.{extension}`.
// If \p extensions are not specified, then just search for `{root}/{name}`.
static Optional<StringRef>
findPathCombination(const Twine &name, const std::vector<StringRef> &roots,
ArrayRef<StringRef> extensions = {""}) {
SmallString<261> base;
for (StringRef dir : config->librarySearchPaths) {
for (StringRef dir : roots) {
base = dir;
path::append(base, Twine("lib") + name);
path::append(base, name);
for (StringRef ext : extensions) {
Twine location = base + ext;
if (fs::exists(location))
return location.str();
return saver.save(location.str());
else
depTracker->logFileNotFound(location);
}
@ -93,14 +96,29 @@ findAlongPathsWithExtensions(StringRef name, ArrayRef<StringRef> extensions) {
return {};
}
static Optional<std::string> findLibrary(StringRef name) {
static Optional<StringRef> findLibrary(StringRef name) {
if (config->searchDylibsFirst) {
if (Optional<std::string> path =
findAlongPathsWithExtensions(name, {".tbd", ".dylib"}))
if (Optional<StringRef> path = findPathCombination(
"lib" + name, config->librarySearchPaths, {".tbd", ".dylib"}))
return path;
return findAlongPathsWithExtensions(name, {".a"});
return findPathCombination("lib" + name, config->librarySearchPaths,
{".a"});
}
return findAlongPathsWithExtensions(name, {".tbd", ".dylib", ".a"});
return findPathCombination("lib" + name, config->librarySearchPaths,
{".tbd", ".dylib", ".a"});
}
// If -syslibroot is specified, absolute paths to non-object files may be
// rerooted.
static StringRef rerootPath(StringRef path) {
if (!path::is_absolute(path, path::Style::posix) || path.endswith(".o"))
return path;
if (Optional<StringRef> rerootedPath =
findPathCombination(path, config->systemLibraryRoots))
return *rerootedPath;
return path;
}
static Optional<std::string> findFramework(StringRef name) {
@ -337,7 +355,7 @@ static InputFile *addFile(StringRef path, bool forceLoadArchive,
}
static void addLibrary(StringRef name, bool isWeak) {
if (Optional<std::string> path = findLibrary(name)) {
if (Optional<StringRef> path = findLibrary(name)) {
auto *dylibFile = dyn_cast_or_null<DylibFile>(addFile(*path, false));
if (isWeak && dylibFile)
dylibFile->forceWeakImport = true;
@ -396,7 +414,7 @@ static void addFileList(StringRef path) {
return;
MemoryBufferRef mbref = *buffer;
for (StringRef path : args::getLines(mbref))
addFile(path, false);
addFile(rerootPath(path), false);
}
// An order file has one entry per line, in the following format:
@ -814,18 +832,18 @@ void createFiles(const InputArgList &args) {
switch (opt.getID()) {
case OPT_INPUT:
addFile(arg->getValue(), false);
addFile(rerootPath(arg->getValue()), false);
break;
case OPT_weak_library:
if (auto *dylibFile =
dyn_cast_or_null<DylibFile>(addFile(arg->getValue(), false)))
if (auto *dylibFile = dyn_cast_or_null<DylibFile>(
addFile(rerootPath(arg->getValue()), false)))
dylibFile->forceWeakImport = true;
break;
case OPT_filelist:
addFileList(arg->getValue());
break;
case OPT_force_load:
addFile(arg->getValue(), true);
addFile(rerootPath(arg->getValue()), true);
break;
case OPT_l:
case OPT_weak_l:

View File

@ -20,7 +20,7 @@
# CHECK-DAG: input-file: {{.*}}{{[/\]}}main.o
# CHECK-DAG: input-file: {{.*}}bar.o
# CHECK-NEXT: not-found: {{.*}}{{[/\]}}libdyld.{{.*}}
# CHECK: not-found: {{.*}}{{[/\]}}libdyld.{{.*}}
## There could be more not-found here but we are not checking those because it's brittle.
# CHECK: output-file: {{.*}}{{[/\]}}test.out

View File

@ -0,0 +1,64 @@
# REQUIRES: x86
# UNSUPPORTED: system-windows
## FIXME: In principle this test should pass on Windows
# RUN: rm -rf %t; split-file %s %t
## This test verifies that we attempt to re-root absolute paths if -syslibroot
## is specified. Therefore we would like to be able to specify an absolute path
## without worrying that it may match an actual file on the system outside the
## syslibroot. `chroot` would do the job but isn't cross-platform, so I've used
## this %t/%:t hack instead.
# RUN: mkdir -p %t/%:t
# 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/test.s -o %t/test.o
## bar.a is under %t/%:t, and so verifies that rerooting happens. foo.a isn't,
## and therefore verifies that we still fall back to the original path if no
## file exists at the rerooted path.
# RUN: llvm-ar rcs %t/foo.a %t/foo.o
# RUN: %lld -dylib %t/foo.o -o %t/libfoo.dylib
# RUN: llvm-ar rcs %t/%:t/bar.a %t/bar.o
# RUN: %lld -dylib %t/bar.o -o %t/%:t/libbar.dylib
## Test our various file-loading flags to make sure all bases are covered.
# RUN: %lld -lSystem -syslibroot %t %t/foo.a %t/bar.a %t/test.o -o /dev/null -t | FileCheck %s -DDIR="%t/%:t"
# RUN: %lld -lSystem -syslibroot %t -force_load %t/foo.a -force_load %t/bar.a %t/test.o -o /dev/null -t | FileCheck %s -DDIR="%t/%:t"
# RUN: %lld -lSystem -syslibroot %t %t/libfoo.dylib %t/libbar.dylib %t/test.o -o /dev/null -t | FileCheck %s -DDIR="%t/%:t"
# RUN: %lld -lSystem -syslibroot %t -weak_library %t/libfoo.dylib -weak_library %t/libbar.dylib %t/test.o -o /dev/null -t | FileCheck %s -DDIR="%t/%:t"
# RUN: echo "%t/libfoo.dylib" > %t/filelist
# RUN: echo "%t/libbar.dylib" >> %t/filelist
# RUN: %lld -lSystem -syslibroot %t -filelist %t/filelist %t/test.o -o /dev/null -t | FileCheck %s -DDIR="%t/%:t"
# CHECK: [[DIR]]/{{(lib)?}}bar
## Paths to object files don't get rerooted.
# RUN: mv %t/bar.o %t/%:t/bar.o
# RUN: not %lld -lSystem -syslibroot %t %t/foo.o %t/bar.o %t/test.o -o \
# RUN: /dev/null 2>&1 | FileCheck %s --check-prefix=OBJ
# OBJ: error: cannot open {{.*[\\/]}}bar.o: {{[Nn]}}o such file or directory
## Now create a "decoy" libfoo.dylib under %t/%:t to demonstrate that the
## rerooted path takes precedence over the original path. We will get an
## undefined symbol error since we aren't loading %t/libfoo.dylib.
# RUN: cp %t/%:t/libbar.dylib %t/%:t/libfoo.dylib
# RUN: not %lld -lSystem -syslibroot %t %t/libfoo.dylib %t/libbar.dylib %t/test.o \
# RUN: -o /dev/null 2>&1 | FileCheck %s --check-prefix=UNDEF
# UNDEF: error: undefined symbol: _foo
#--- foo.s
.globl _foo
_foo:
#--- bar.s
.globl _bar
_bar:
#--- test.s
.text
.globl _main
_main:
callq _foo
callq _bar
ret