From 6f4e255219f2a7878d3ac66d26313b9b8863e92f Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Mon, 23 Oct 2017 20:03:32 +0000 Subject: [PATCH] lld::COFF: better behavior when using as a library Previously, the COFF driver would call exit(0) when called as a library. Now it takes `ExitEarly` option, and if it is false, it doesn't exit. So it is now more library-friendly. Furthermore, link() calls freeArena() before returning, to clean up resources. Based on an Andrew Kelley's patch. Differential Revision: https://reviews.llvm.org/D39202 llvm-svn: 316370 --- lld/COFF/Config.h | 1 + lld/COFF/Driver.cpp | 19 ++++++++++--------- lld/COFF/Error.cpp | 5 +++-- lld/COFF/Error.h | 2 ++ lld/MinGW/Driver.cpp | 2 +- lld/include/lld/Common/Driver.h | 2 +- lld/tools/lld/lld.cpp | 2 +- 7 files changed, 19 insertions(+), 14 deletions(-) diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h index 995a398a3c91..7a281b3fccc5 100644 --- a/lld/COFF/Config.h +++ b/lld/COFF/Config.h @@ -166,6 +166,7 @@ struct Configuration { uint32_t MinorImageVersion = 0; uint32_t MajorOSVersion = 6; uint32_t MinorOSVersion = 0; + bool CanExitEarly = false; bool DynamicBase = true; bool AllowBind = true; bool NxCompat = true; diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp index 133cf40a83bf..168d99093c5f 100644 --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -54,18 +54,25 @@ BumpPtrAllocator BAlloc; StringSaver Saver{BAlloc}; std::vector SpecificAllocBase::Instances; -bool link(ArrayRef Args, raw_ostream &Diag) { +bool link(ArrayRef Args, bool CanExitEarly, raw_ostream &Diag) { ErrorCount = 0; ErrorOS = &Diag; Config = make(); Config->Argv = {Args.begin(), Args.end()}; Config->ColorDiagnostics = ErrorOS->has_colors(); + Config->CanExitEarly = CanExitEarly; Symtab = make(); Driver = make(); Driver->link(Args); + + // Call exit() if we can to avoid calling destructors. + if (CanExitEarly) + exitLld(ErrorCount ? 1 : 0); + + freeArena(); return !ErrorCount; } @@ -1087,7 +1094,7 @@ void LinkerDriver::link(ArrayRef ArgsArr) { if (!Args.hasArg(OPT_INPUT)) { fixupExports(); createImportLibrary(/*AsLib=*/true); - exit(0); + return; } // Handle /delayload @@ -1179,7 +1186,7 @@ void LinkerDriver::link(ArrayRef ArgsArr) { // This is useful because MSVC link.exe can generate complete PDBs. if (Args.hasArg(OPT_msvclto)) { invokeMSVC(Args); - exit(0); + return; } // Do LTO by compiling bitcode input files to a set of native COFF files then @@ -1273,12 +1280,6 @@ void LinkerDriver::link(ArrayRef ArgsArr) { // Write the result. writeResult(); - - if (ErrorCount) - return; - - // Call exit to avoid calling destructors. - exit(0); } } // namespace coff diff --git a/lld/COFF/Error.cpp b/lld/COFF/Error.cpp index 34abc280f6bf..550d9b969672 100644 --- a/lld/COFF/Error.cpp +++ b/lld/COFF/Error.cpp @@ -32,7 +32,7 @@ namespace coff { uint64_t ErrorCount; raw_ostream *ErrorOS; -static LLVM_ATTRIBUTE_NORETURN void exitLld(int Val) { +LLVM_ATTRIBUTE_NORETURN void exitLld(int Val) { // Dealloc/destroy ManagedStatic variables before calling // _exit(). In a non-LTO build, this is a nop. In an LTO // build allows us to get the output of -time-passes. @@ -78,7 +78,8 @@ void error(const Twine &Msg) { print("error: ", raw_ostream::RED); *ErrorOS << "too many errors emitted, stopping now" << " (use /ERRORLIMIT:0 to see all errors)\n"; - exitLld(1); + if (Config->CanExitEarly) + exitLld(1); } ++ErrorCount; diff --git a/lld/COFF/Error.h b/lld/COFF/Error.h index 1cc2dd4ed905..ac3bf81f30f4 100644 --- a/lld/COFF/Error.h +++ b/lld/COFF/Error.h @@ -27,6 +27,8 @@ LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg); LLVM_ATTRIBUTE_NORETURN void fatal(std::error_code EC, const Twine &Prefix); LLVM_ATTRIBUTE_NORETURN void fatal(llvm::Error &Err, const Twine &Prefix); +LLVM_ATTRIBUTE_NORETURN void exitLld(int Val); + template T check(ErrorOr V, const Twine &Prefix) { if (auto EC = V.getError()) fatal(EC, Prefix); diff --git a/lld/MinGW/Driver.cpp b/lld/MinGW/Driver.cpp index ebb66125fdd7..451ae2d6e461 100644 --- a/lld/MinGW/Driver.cpp +++ b/lld/MinGW/Driver.cpp @@ -217,5 +217,5 @@ bool mingw::link(ArrayRef ArgsArr, raw_ostream &Diag) { std::vector Vec; for (const std::string &S : LinkArgs) Vec.push_back(S.c_str()); - return coff::link(Vec); + return coff::link(Vec, true); } diff --git a/lld/include/lld/Common/Driver.h b/lld/include/lld/Common/Driver.h index b3fa47128169..dee46f808b10 100644 --- a/lld/include/lld/Common/Driver.h +++ b/lld/include/lld/Common/Driver.h @@ -15,7 +15,7 @@ namespace lld { namespace coff { -bool link(llvm::ArrayRef Args, +bool link(llvm::ArrayRef Args, bool CanExitEarly, llvm::raw_ostream &Diag = llvm::errs()); } diff --git a/lld/tools/lld/lld.cpp b/lld/tools/lld/lld.cpp index bbdba4837906..a819c20de447 100644 --- a/lld/tools/lld/lld.cpp +++ b/lld/tools/lld/lld.cpp @@ -115,7 +115,7 @@ int main(int Argc, const char **Argv) { return !mingw::link(Args); return !elf::link(Args, true); case WinLink: - return !coff::link(Args); + return !coff::link(Args, true); case Darwin: return !mach_o::link(Args); default: