106c3fb27SDimitry Andric //===- DriverDispatcher.cpp - Support using LLD as a library --------------===// 206c3fb27SDimitry Andric // 306c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 406c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 506c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 606c3fb27SDimitry Andric // 706c3fb27SDimitry Andric //===----------------------------------------------------------------------===// 806c3fb27SDimitry Andric 906c3fb27SDimitry Andric #include "lld/Common/CommonLinkerContext.h" 1006c3fb27SDimitry Andric #include "lld/Common/Driver.h" 1106c3fb27SDimitry Andric #include "lld/Common/ErrorHandler.h" 1206c3fb27SDimitry Andric #include "lld/Common/Memory.h" 1306c3fb27SDimitry Andric #include "llvm/ADT/STLExtras.h" 1406c3fb27SDimitry Andric #include "llvm/ADT/SmallVector.h" 1506c3fb27SDimitry Andric #include "llvm/ADT/StringSwitch.h" 1606c3fb27SDimitry Andric #include "llvm/ADT/Twine.h" 1706c3fb27SDimitry Andric #include "llvm/Support/CommandLine.h" 1806c3fb27SDimitry Andric #include "llvm/Support/CrashRecoveryContext.h" 1906c3fb27SDimitry Andric #include "llvm/Support/Path.h" 2006c3fb27SDimitry Andric #include "llvm/Support/Process.h" 2106c3fb27SDimitry Andric #include "llvm/TargetParser/Host.h" 2206c3fb27SDimitry Andric #include "llvm/TargetParser/Triple.h" 2306c3fb27SDimitry Andric #include <cstdlib> 2406c3fb27SDimitry Andric 2506c3fb27SDimitry Andric using namespace lld; 2606c3fb27SDimitry Andric using namespace llvm; 2706c3fb27SDimitry Andric using namespace llvm::sys; 2806c3fb27SDimitry Andric 2906c3fb27SDimitry Andric static void err(const Twine &s) { llvm::errs() << s << "\n"; } 3006c3fb27SDimitry Andric 3106c3fb27SDimitry Andric static Flavor getFlavor(StringRef s) { 3206c3fb27SDimitry Andric return StringSwitch<Flavor>(s) 3306c3fb27SDimitry Andric .CasesLower("ld", "ld.lld", "gnu", Gnu) 3406c3fb27SDimitry Andric .CasesLower("wasm", "ld-wasm", Wasm) 3506c3fb27SDimitry Andric .CaseLower("link", WinLink) 3606c3fb27SDimitry Andric .CasesLower("ld64", "ld64.lld", "darwin", Darwin) 3706c3fb27SDimitry Andric .Default(Invalid); 3806c3fb27SDimitry Andric } 3906c3fb27SDimitry Andric 4006c3fb27SDimitry Andric static cl::TokenizerCallback getDefaultQuotingStyle() { 4106c3fb27SDimitry Andric if (Triple(sys::getProcessTriple()).getOS() == Triple::Win32) 4206c3fb27SDimitry Andric return cl::TokenizeWindowsCommandLine; 4306c3fb27SDimitry Andric return cl::TokenizeGNUCommandLine; 4406c3fb27SDimitry Andric } 4506c3fb27SDimitry Andric 4606c3fb27SDimitry Andric static bool isPETargetName(StringRef s) { 47*0fca6ea1SDimitry Andric return s == "i386pe" || s == "i386pep" || s == "thumb2pe" || s == "arm64pe" || 48*0fca6ea1SDimitry Andric s == "arm64ecpe"; 4906c3fb27SDimitry Andric } 5006c3fb27SDimitry Andric 5106c3fb27SDimitry Andric static std::optional<bool> isPETarget(llvm::ArrayRef<const char *> args) { 5206c3fb27SDimitry Andric for (auto it = args.begin(); it + 1 != args.end(); ++it) { 5306c3fb27SDimitry Andric if (StringRef(*it) != "-m") 5406c3fb27SDimitry Andric continue; 5506c3fb27SDimitry Andric return isPETargetName(*(it + 1)); 5606c3fb27SDimitry Andric } 5706c3fb27SDimitry Andric 5806c3fb27SDimitry Andric // Expand response files (arguments in the form of @<filename>) 5906c3fb27SDimitry Andric // to allow detecting the -m argument from arguments in them. 6006c3fb27SDimitry Andric SmallVector<const char *, 256> expandedArgs(args.data(), 6106c3fb27SDimitry Andric args.data() + args.size()); 6206c3fb27SDimitry Andric BumpPtrAllocator a; 6306c3fb27SDimitry Andric StringSaver saver(a); 6406c3fb27SDimitry Andric cl::ExpansionContext ectx(saver.getAllocator(), getDefaultQuotingStyle()); 6506c3fb27SDimitry Andric if (Error e = ectx.expandResponseFiles(expandedArgs)) { 6606c3fb27SDimitry Andric err(toString(std::move(e))); 6706c3fb27SDimitry Andric return std::nullopt; 6806c3fb27SDimitry Andric } 6906c3fb27SDimitry Andric 7006c3fb27SDimitry Andric for (auto it = expandedArgs.begin(); it + 1 != expandedArgs.end(); ++it) { 7106c3fb27SDimitry Andric if (StringRef(*it) != "-m") 7206c3fb27SDimitry Andric continue; 7306c3fb27SDimitry Andric return isPETargetName(*(it + 1)); 7406c3fb27SDimitry Andric } 7506c3fb27SDimitry Andric 7606c3fb27SDimitry Andric #ifdef LLD_DEFAULT_LD_LLD_IS_MINGW 7706c3fb27SDimitry Andric return true; 7806c3fb27SDimitry Andric #else 7906c3fb27SDimitry Andric return false; 8006c3fb27SDimitry Andric #endif 8106c3fb27SDimitry Andric } 8206c3fb27SDimitry Andric 8306c3fb27SDimitry Andric static Flavor parseProgname(StringRef progname) { 8406c3fb27SDimitry Andric // Use GNU driver for "ld" by default. 8506c3fb27SDimitry Andric if (progname == "ld") 8606c3fb27SDimitry Andric return Gnu; 8706c3fb27SDimitry Andric 8806c3fb27SDimitry Andric // Progname may be something like "lld-gnu". Parse it. 8906c3fb27SDimitry Andric SmallVector<StringRef, 3> v; 9006c3fb27SDimitry Andric progname.split(v, "-"); 9106c3fb27SDimitry Andric for (StringRef s : v) 9206c3fb27SDimitry Andric if (Flavor f = getFlavor(s)) 9306c3fb27SDimitry Andric return f; 9406c3fb27SDimitry Andric return Invalid; 9506c3fb27SDimitry Andric } 9606c3fb27SDimitry Andric 9706c3fb27SDimitry Andric static Flavor 9806c3fb27SDimitry Andric parseFlavorWithoutMinGW(llvm::SmallVectorImpl<const char *> &argsV) { 9906c3fb27SDimitry Andric // Parse -flavor option. 10006c3fb27SDimitry Andric if (argsV.size() > 1 && argsV[1] == StringRef("-flavor")) { 10106c3fb27SDimitry Andric if (argsV.size() <= 2) { 10206c3fb27SDimitry Andric err("missing arg value for '-flavor'"); 10306c3fb27SDimitry Andric return Invalid; 10406c3fb27SDimitry Andric } 10506c3fb27SDimitry Andric Flavor f = getFlavor(argsV[2]); 10606c3fb27SDimitry Andric if (f == Invalid) { 10706c3fb27SDimitry Andric err("Unknown flavor: " + StringRef(argsV[2])); 10806c3fb27SDimitry Andric return Invalid; 10906c3fb27SDimitry Andric } 11006c3fb27SDimitry Andric argsV.erase(argsV.begin() + 1, argsV.begin() + 3); 11106c3fb27SDimitry Andric return f; 11206c3fb27SDimitry Andric } 11306c3fb27SDimitry Andric 11406c3fb27SDimitry Andric // Deduct the flavor from argv[0]. 11506c3fb27SDimitry Andric StringRef arg0 = path::filename(argsV[0]); 11606c3fb27SDimitry Andric if (arg0.ends_with_insensitive(".exe")) 11706c3fb27SDimitry Andric arg0 = arg0.drop_back(4); 11806c3fb27SDimitry Andric Flavor f = parseProgname(arg0); 11906c3fb27SDimitry Andric if (f == Invalid) { 12006c3fb27SDimitry Andric err("lld is a generic driver.\n" 12106c3fb27SDimitry Andric "Invoke ld.lld (Unix), ld64.lld (macOS), lld-link (Windows), wasm-ld" 12206c3fb27SDimitry Andric " (WebAssembly) instead"); 12306c3fb27SDimitry Andric return Invalid; 12406c3fb27SDimitry Andric } 12506c3fb27SDimitry Andric return f; 12606c3fb27SDimitry Andric } 12706c3fb27SDimitry Andric 12806c3fb27SDimitry Andric static Flavor parseFlavor(llvm::SmallVectorImpl<const char *> &argsV) { 12906c3fb27SDimitry Andric Flavor f = parseFlavorWithoutMinGW(argsV); 13006c3fb27SDimitry Andric if (f == Gnu) { 13106c3fb27SDimitry Andric auto isPE = isPETarget(argsV); 13206c3fb27SDimitry Andric if (!isPE) 13306c3fb27SDimitry Andric return Invalid; 13406c3fb27SDimitry Andric if (*isPE) 13506c3fb27SDimitry Andric return MinGW; 13606c3fb27SDimitry Andric } 13706c3fb27SDimitry Andric return f; 13806c3fb27SDimitry Andric } 13906c3fb27SDimitry Andric 14006c3fb27SDimitry Andric static Driver whichDriver(llvm::SmallVectorImpl<const char *> &argsV, 14106c3fb27SDimitry Andric llvm::ArrayRef<DriverDef> drivers) { 14206c3fb27SDimitry Andric Flavor f = parseFlavor(argsV); 14306c3fb27SDimitry Andric auto it = 14406c3fb27SDimitry Andric llvm::find_if(drivers, [=](auto &driverdef) { return driverdef.f == f; }); 14506c3fb27SDimitry Andric if (it == drivers.end()) { 14606c3fb27SDimitry Andric // Driver is invalid or not available in this build. 14706c3fb27SDimitry Andric return [](llvm::ArrayRef<const char *>, llvm::raw_ostream &, 14806c3fb27SDimitry Andric llvm::raw_ostream &, bool, bool) { return false; }; 14906c3fb27SDimitry Andric } 15006c3fb27SDimitry Andric return it->d; 15106c3fb27SDimitry Andric } 15206c3fb27SDimitry Andric 15306c3fb27SDimitry Andric namespace lld { 15406c3fb27SDimitry Andric bool inTestOutputDisabled = false; 15506c3fb27SDimitry Andric 15606c3fb27SDimitry Andric /// Universal linker main(). This linker emulates the gnu, darwin, or 15706c3fb27SDimitry Andric /// windows linker based on the argv[0] or -flavor option. 15806c3fb27SDimitry Andric int unsafeLldMain(llvm::ArrayRef<const char *> args, 15906c3fb27SDimitry Andric llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS, 16006c3fb27SDimitry Andric llvm::ArrayRef<DriverDef> drivers, bool exitEarly) { 16106c3fb27SDimitry Andric SmallVector<const char *, 256> argsV(args); 16206c3fb27SDimitry Andric Driver d = whichDriver(argsV, drivers); 16306c3fb27SDimitry Andric // Run the driver. If an error occurs, false will be returned. 16406c3fb27SDimitry Andric int r = !d(argsV, stdoutOS, stderrOS, exitEarly, inTestOutputDisabled); 16506c3fb27SDimitry Andric // At this point 'r' is either 1 for error, and 0 for no error. 16606c3fb27SDimitry Andric 16706c3fb27SDimitry Andric // Call exit() if we can to avoid calling destructors. 16806c3fb27SDimitry Andric if (exitEarly) 16906c3fb27SDimitry Andric exitLld(r); 17006c3fb27SDimitry Andric 17106c3fb27SDimitry Andric // Delete the global context and clear the global context pointer, so that it 17206c3fb27SDimitry Andric // cannot be accessed anymore. 17306c3fb27SDimitry Andric CommonLinkerContext::destroy(); 17406c3fb27SDimitry Andric 17506c3fb27SDimitry Andric return r; 17606c3fb27SDimitry Andric } 17706c3fb27SDimitry Andric } // namespace lld 17806c3fb27SDimitry Andric 17906c3fb27SDimitry Andric Result lld::lldMain(llvm::ArrayRef<const char *> args, 18006c3fb27SDimitry Andric llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS, 18106c3fb27SDimitry Andric llvm::ArrayRef<DriverDef> drivers) { 18206c3fb27SDimitry Andric int r = 0; 18306c3fb27SDimitry Andric { 18406c3fb27SDimitry Andric // The crash recovery is here only to be able to recover from arbitrary 18506c3fb27SDimitry Andric // control flow when fatal() is called (through setjmp/longjmp or 18606c3fb27SDimitry Andric // __try/__except). 18706c3fb27SDimitry Andric llvm::CrashRecoveryContext crc; 18806c3fb27SDimitry Andric if (!crc.RunSafely([&]() { 18906c3fb27SDimitry Andric r = unsafeLldMain(args, stdoutOS, stderrOS, drivers, 19006c3fb27SDimitry Andric /*exitEarly=*/false); 19106c3fb27SDimitry Andric })) 19206c3fb27SDimitry Andric return {crc.RetCode, /*canRunAgain=*/false}; 19306c3fb27SDimitry Andric } 19406c3fb27SDimitry Andric 19506c3fb27SDimitry Andric // Cleanup memory and reset everything back in pristine condition. This path 19606c3fb27SDimitry Andric // is only taken when LLD is in test, or when it is used as a library. 19706c3fb27SDimitry Andric llvm::CrashRecoveryContext crc; 19806c3fb27SDimitry Andric if (!crc.RunSafely([&]() { CommonLinkerContext::destroy(); })) { 19906c3fb27SDimitry Andric // The memory is corrupted beyond any possible recovery. 20006c3fb27SDimitry Andric return {r, /*canRunAgain=*/false}; 20106c3fb27SDimitry Andric } 20206c3fb27SDimitry Andric return {r, /*canRunAgain=*/true}; 20306c3fb27SDimitry Andric } 204