Index: lld/ELF/Config.h =================================================================== --- lld/ELF/Config.h +++ lld/ELF/Config.h @@ -82,6 +82,7 @@ uint8_t OSABI = 0; llvm::CachePruningPolicy ThinLTOCachePolicy; llvm::StringMap SectionStartMap; + llvm::StringRef Chroot; llvm::StringRef DynamicLinker; llvm::StringRef Entry; llvm::StringRef Emulation; Index: lld/ELF/Driver.cpp =================================================================== --- lld/ELF/Driver.cpp +++ lld/ELF/Driver.cpp @@ -619,6 +619,7 @@ Config->AuxiliaryList = getArgs(Args, OPT_auxiliary); Config->Bsymbolic = Args.hasArg(OPT_Bsymbolic); Config->BsymbolicFunctions = Args.hasArg(OPT_Bsymbolic_functions); + Config->Chroot = Args.getLastArgValue(OPT_chroot); Config->CompressDebugSections = getCompressDebugSections(Args); Config->DefineCommon = getArg(Args, OPT_define_common, OPT_no_define_common, !Args.hasArg(OPT_relocatable)); Index: lld/ELF/DriverUtils.cpp =================================================================== --- lld/ELF/DriverUtils.cpp +++ lld/ELF/DriverUtils.cpp @@ -138,6 +138,7 @@ std::string elf::createResponseFile(const opt::InputArgList &Args) { SmallString<0> Data; raw_svector_ostream OS(Data); + OS << "--chroot .\n"; // Copy the command line to the output while rewriting paths. for (auto *Arg : Args) { Index: lld/ELF/InputFiles.cpp =================================================================== --- lld/ELF/InputFiles.cpp +++ lld/ELF/InputFiles.cpp @@ -40,7 +40,13 @@ InputFile::InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {} Optional elf::readFile(StringRef Path) { + // The --chroot option changes our virtual root directory. + // This is useful when you are dealing with files created by --reproduce. + if (!Config->Chroot.empty() && Path.startswith("/")) + Path = Saver.save(Config->Chroot + Path); + log(Path); + auto MBOrErr = MemoryBuffer::getFile(Path); if (auto EC = MBOrErr.getError()) { error("cannot open " + Path + ": " + EC.message()); Index: lld/ELF/Options.td =================================================================== --- lld/ELF/Options.td +++ lld/ELF/Options.td @@ -44,6 +44,9 @@ def as_needed: F<"as-needed">, HelpText<"Only set DT_NEEDED for shared libraries if used">; +// -chroot doesn't have a help text because it is an internal option. +def chroot: S<"chroot">; + def color_diagnostics: F<"color-diagnostics">, HelpText<"Use colors in diagnostics">; Index: lld/ELF/ScriptParser.cpp =================================================================== --- lld/ELF/ScriptParser.cpp +++ lld/ELF/ScriptParser.cpp @@ -256,7 +256,7 @@ } } - if (sys::path::is_absolute(S)) { + if (S.startswith("/")) { Driver->addFile(S, /*WithLOption=*/false); } else if (S.startswith("=")) { if (Config->Sysroot.empty()) Index: lld/test/ELF/chroot.s =================================================================== --- /dev/null +++ lld/test/ELF/chroot.s @@ -0,0 +1,12 @@ +# REQUIRES: x86 +# RUN: rm -rf %t.dir +# RUN: mkdir %t.dir +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.dir/chroot.o +# RUN: ld.lld --chroot %t.dir -o %t.exe /chroot.o + +# RUN: echo 'INPUT(/chroot.o)' > %t.dir/scr +# RUN: ld.lld --chroot %t.dir -o %t.exe /scr + +.globl _start +_start: + ret Index: lld/test/ELF/reproduce.s =================================================================== --- lld/test/ELF/reproduce.s +++ lld/test/ELF/reproduce.s @@ -39,6 +39,7 @@ # RUN: --dynamic-linker "some unusual/path" -soname 'foo bar' -soname='foo bar' # RUN: tar xf repro2.tar # RUN: FileCheck %s --check-prefix=RSP2 < repro2/response.txt +# RSP2: --chroot . # RSP2: "{{.*}}foo bar" # RSP2-NEXT: -L "{{.*}}foo bar" # RSP2-NEXT: -L {{.+}}file