Index: ELF/Driver.h =================================================================== --- ELF/Driver.h +++ ELF/Driver.h @@ -20,8 +20,12 @@ extern class LinkerDriver *Driver; -// Entry point of the ELF linker. -void link(ArrayRef Args); +// An entry point of the ELF linker. It is not guranteed that the +// function will return. +void linkOrFail(ArrayRef Args); + +// The other entry point of the ELF linker which is guaranteed to return. +bool link(llvm::ArrayRef Args, raw_ostream &Diag); class LinkerDriver { public: Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -29,7 +29,7 @@ Configuration *elf2::Config; LinkerDriver *elf2::Driver; -void elf2::link(ArrayRef Args) { +void elf2::linkOrFail(ArrayRef Args) { Configuration C; LinkerDriver D; Config = &C; Index: ELF/DriverUtils.cpp =================================================================== --- ELF/DriverUtils.cpp +++ ELF/DriverUtils.cpp @@ -19,7 +19,9 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" +#include "llvm/Support/Program.h" #include "llvm/Support/StringSaver.h" +#include "llvm/Support/raw_ostream.h" using namespace llvm; @@ -118,3 +120,48 @@ sys::path::append(Path, Dir, File); return Path.str(); } + +// Returns LLD's path on the file system. +static ErrorOr getLldExecutable(StringRef Arg0) { + // First, look for "lld" from the current executable directory. + // (P just needs to be some symbol in the binary.) + void *P = (void *)(intptr_t)getLldExecutable; + SmallString<128> Dir; + Dir = sys::fs::getMainExecutable(Arg0.data(), &P); + sys::path::remove_filename(Dir); + if (ErrorOr S = sys::findProgramByName("lld", {Dir})) + return S; + + // If not found, look for "lld" from $PATH. + return sys::findProgramByName("lld"); +} + +// This is a wrapper for linkOrFail(). Unlike linkOrFail(), +// this function always returns. +bool elf2::link(ArrayRef Args, raw_ostream &Diag) { + // "-lld-no-exec" is the marker that we are in a subprocess. + if (Args.size() > 1 && Args[1] == StringRef("-lld-no-exec")) { + std::vector Argv(Args.begin(), Args.end()); + Argv.erase(Argv.begin() + 1); + linkOrFail(Argv); + exit(0); + } + + // We want to build arguments such that lld -flavor gnu Args[1]... + ErrorOr ExeOrErr = getLldExecutable(Args[0]); + if (!ExeOrErr) { + Diag << "lld is not found\n"; + return false; + } + const char *Exe = ExeOrErr->data(); + std::vector Argv = {Exe, "-flavor", "gnu", "-lld-no-exec"}; + Argv.insert(Argv.end(), Args.begin() + 1, Args.end()); + Argv.push_back(nullptr); + + // Start a subprocess and return its result. + std::string ErrMsg; + int Status = + sys::ExecuteAndWait(Exe, Argv.data(), nullptr, nullptr, 0, 0, &ErrMsg); + Diag << ErrMsg; + return !Status; +} Index: include/lld/Driver/Driver.h =================================================================== --- include/lld/Driver/Driver.h +++ include/lld/Driver/Driver.h @@ -125,7 +125,12 @@ } namespace elf2 { -void link(llvm::ArrayRef args); +// An entry point for the internal use. It is not guaranteed to return. +void linkOrFail(llvm::ArrayRef args); + +// If you want to call LLD ELF's main from your program, use this function. +// It is guaranteed to return. Returns true on success. +bool link(llvm::ArrayRef args, raw_ostream &diag = llvm::errs()); } /// Driver for lld unit tests Index: lib/Driver/UniversalDriver.cpp =================================================================== --- lib/Driver/UniversalDriver.cpp +++ lib/Driver/UniversalDriver.cpp @@ -205,7 +205,7 @@ case Flavor::old_gnu_ld: return GnuLdDriver::linkELF(args, diagnostics); case Flavor::gnu_ld: - elf2::link(args); + elf2::linkOrFail(args); return true; case Flavor::darwin_ld: return DarwinLdDriver::linkMachO(args, diagnostics);