Path: blob/main/contrib/llvm-project/lld/Common/DriverDispatcher.cpp
34879 views
//===- DriverDispatcher.cpp - Support using LLD as a library --------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "lld/Common/CommonLinkerContext.h"9#include "lld/Common/Driver.h"10#include "lld/Common/ErrorHandler.h"11#include "lld/Common/Memory.h"12#include "llvm/ADT/STLExtras.h"13#include "llvm/ADT/SmallVector.h"14#include "llvm/ADT/StringSwitch.h"15#include "llvm/ADT/Twine.h"16#include "llvm/Support/CommandLine.h"17#include "llvm/Support/CrashRecoveryContext.h"18#include "llvm/Support/Path.h"19#include "llvm/Support/Process.h"20#include "llvm/TargetParser/Host.h"21#include "llvm/TargetParser/Triple.h"22#include <cstdlib>2324using namespace lld;25using namespace llvm;26using namespace llvm::sys;2728static void err(const Twine &s) { llvm::errs() << s << "\n"; }2930static Flavor getFlavor(StringRef s) {31return StringSwitch<Flavor>(s)32.CasesLower("ld", "ld.lld", "gnu", Gnu)33.CasesLower("wasm", "ld-wasm", Wasm)34.CaseLower("link", WinLink)35.CasesLower("ld64", "ld64.lld", "darwin", Darwin)36.Default(Invalid);37}3839static cl::TokenizerCallback getDefaultQuotingStyle() {40if (Triple(sys::getProcessTriple()).getOS() == Triple::Win32)41return cl::TokenizeWindowsCommandLine;42return cl::TokenizeGNUCommandLine;43}4445static bool isPETargetName(StringRef s) {46return s == "i386pe" || s == "i386pep" || s == "thumb2pe" || s == "arm64pe" ||47s == "arm64ecpe";48}4950static std::optional<bool> isPETarget(llvm::ArrayRef<const char *> args) {51for (auto it = args.begin(); it + 1 != args.end(); ++it) {52if (StringRef(*it) != "-m")53continue;54return isPETargetName(*(it + 1));55}5657// Expand response files (arguments in the form of @<filename>)58// to allow detecting the -m argument from arguments in them.59SmallVector<const char *, 256> expandedArgs(args.data(),60args.data() + args.size());61BumpPtrAllocator a;62StringSaver saver(a);63cl::ExpansionContext ectx(saver.getAllocator(), getDefaultQuotingStyle());64if (Error e = ectx.expandResponseFiles(expandedArgs)) {65err(toString(std::move(e)));66return std::nullopt;67}6869for (auto it = expandedArgs.begin(); it + 1 != expandedArgs.end(); ++it) {70if (StringRef(*it) != "-m")71continue;72return isPETargetName(*(it + 1));73}7475#ifdef LLD_DEFAULT_LD_LLD_IS_MINGW76return true;77#else78return false;79#endif80}8182static Flavor parseProgname(StringRef progname) {83// Use GNU driver for "ld" by default.84if (progname == "ld")85return Gnu;8687// Progname may be something like "lld-gnu". Parse it.88SmallVector<StringRef, 3> v;89progname.split(v, "-");90for (StringRef s : v)91if (Flavor f = getFlavor(s))92return f;93return Invalid;94}9596static Flavor97parseFlavorWithoutMinGW(llvm::SmallVectorImpl<const char *> &argsV) {98// Parse -flavor option.99if (argsV.size() > 1 && argsV[1] == StringRef("-flavor")) {100if (argsV.size() <= 2) {101err("missing arg value for '-flavor'");102return Invalid;103}104Flavor f = getFlavor(argsV[2]);105if (f == Invalid) {106err("Unknown flavor: " + StringRef(argsV[2]));107return Invalid;108}109argsV.erase(argsV.begin() + 1, argsV.begin() + 3);110return f;111}112113// Deduct the flavor from argv[0].114StringRef arg0 = path::filename(argsV[0]);115if (arg0.ends_with_insensitive(".exe"))116arg0 = arg0.drop_back(4);117Flavor f = parseProgname(arg0);118if (f == Invalid) {119err("lld is a generic driver.\n"120"Invoke ld.lld (Unix), ld64.lld (macOS), lld-link (Windows), wasm-ld"121" (WebAssembly) instead");122return Invalid;123}124return f;125}126127static Flavor parseFlavor(llvm::SmallVectorImpl<const char *> &argsV) {128Flavor f = parseFlavorWithoutMinGW(argsV);129if (f == Gnu) {130auto isPE = isPETarget(argsV);131if (!isPE)132return Invalid;133if (*isPE)134return MinGW;135}136return f;137}138139static Driver whichDriver(llvm::SmallVectorImpl<const char *> &argsV,140llvm::ArrayRef<DriverDef> drivers) {141Flavor f = parseFlavor(argsV);142auto it =143llvm::find_if(drivers, [=](auto &driverdef) { return driverdef.f == f; });144if (it == drivers.end()) {145// Driver is invalid or not available in this build.146return [](llvm::ArrayRef<const char *>, llvm::raw_ostream &,147llvm::raw_ostream &, bool, bool) { return false; };148}149return it->d;150}151152namespace lld {153bool inTestOutputDisabled = false;154155/// Universal linker main(). This linker emulates the gnu, darwin, or156/// windows linker based on the argv[0] or -flavor option.157int unsafeLldMain(llvm::ArrayRef<const char *> args,158llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS,159llvm::ArrayRef<DriverDef> drivers, bool exitEarly) {160SmallVector<const char *, 256> argsV(args);161Driver d = whichDriver(argsV, drivers);162// Run the driver. If an error occurs, false will be returned.163int r = !d(argsV, stdoutOS, stderrOS, exitEarly, inTestOutputDisabled);164// At this point 'r' is either 1 for error, and 0 for no error.165166// Call exit() if we can to avoid calling destructors.167if (exitEarly)168exitLld(r);169170// Delete the global context and clear the global context pointer, so that it171// cannot be accessed anymore.172CommonLinkerContext::destroy();173174return r;175}176} // namespace lld177178Result lld::lldMain(llvm::ArrayRef<const char *> args,179llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS,180llvm::ArrayRef<DriverDef> drivers) {181int r = 0;182{183// The crash recovery is here only to be able to recover from arbitrary184// control flow when fatal() is called (through setjmp/longjmp or185// __try/__except).186llvm::CrashRecoveryContext crc;187if (!crc.RunSafely([&]() {188r = unsafeLldMain(args, stdoutOS, stderrOS, drivers,189/*exitEarly=*/false);190}))191return {crc.RetCode, /*canRunAgain=*/false};192}193194// Cleanup memory and reset everything back in pristine condition. This path195// is only taken when LLD is in test, or when it is used as a library.196llvm::CrashRecoveryContext crc;197if (!crc.RunSafely([&]() { CommonLinkerContext::destroy(); })) {198// The memory is corrupted beyond any possible recovery.199return {r, /*canRunAgain=*/false};200}201return {r, /*canRunAgain=*/true};202}203204205