203 lines · cpp
1//===- DriverDispatcher.cpp - Support using LLD as a library --------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "lld/Common/CommonLinkerContext.h"10#include "lld/Common/Driver.h"11#include "lld/Common/ErrorHandler.h"12#include "lld/Common/Memory.h"13#include "llvm/ADT/STLExtras.h"14#include "llvm/ADT/SmallVector.h"15#include "llvm/ADT/StringSwitch.h"16#include "llvm/ADT/Twine.h"17#include "llvm/Support/CommandLine.h"18#include "llvm/Support/CrashRecoveryContext.h"19#include "llvm/Support/Path.h"20#include "llvm/Support/Process.h"21#include "llvm/TargetParser/Host.h"22#include "llvm/TargetParser/Triple.h"23#include <cstdlib>24 25using namespace lld;26using namespace llvm;27using namespace llvm::sys;28 29static void err(const Twine &s) { llvm::errs() << s << "\n"; }30 31static Flavor getFlavor(StringRef s) {32 return StringSwitch<Flavor>(s)33 .CasesLower({"ld", "ld.lld", "gnu"}, Gnu)34 .CasesLower({"wasm", "ld-wasm"}, Wasm)35 .CaseLower("link", WinLink)36 .CasesLower({"ld64", "ld64.lld", "darwin"}, Darwin)37 .Default(Invalid);38}39 40static cl::TokenizerCallback getDefaultQuotingStyle() {41 if (Triple(sys::getProcessTriple()).getOS() == Triple::Win32)42 return cl::TokenizeWindowsCommandLine;43 return cl::TokenizeGNUCommandLine;44}45 46static bool isPETargetName(StringRef s) {47 return s == "i386pe" || s == "i386pep" || s == "thumb2pe" || s == "arm64pe" ||48 s == "arm64ecpe" || s == "arm64xpe" || s == "mipspe";49}50 51static std::optional<bool> isPETarget(llvm::ArrayRef<const char *> args) {52 for (auto it = args.begin(); it + 1 != args.end(); ++it) {53 if (StringRef(*it) != "-m")54 continue;55 return isPETargetName(*(it + 1));56 }57 58 // Expand response files (arguments in the form of @<filename>)59 // to allow detecting the -m argument from arguments in them.60 SmallVector<const char *, 256> expandedArgs(args.data(),61 args.data() + args.size());62 BumpPtrAllocator a;63 StringSaver saver(a);64 cl::ExpansionContext ectx(saver.getAllocator(), getDefaultQuotingStyle());65 if (Error e = ectx.expandResponseFiles(expandedArgs)) {66 err(toString(std::move(e)));67 return std::nullopt;68 }69 70 for (auto it = expandedArgs.begin(); it + 1 != expandedArgs.end(); ++it) {71 if (StringRef(*it) != "-m")72 continue;73 return isPETargetName(*(it + 1));74 }75 76#ifdef LLD_DEFAULT_LD_LLD_IS_MINGW77 return true;78#else79 return false;80#endif81}82 83static Flavor parseProgname(StringRef progname) {84 // Use GNU driver for "ld" by default.85 if (progname == "ld")86 return Gnu;87 88 // Progname may be something like "lld-gnu". Parse it.89 SmallVector<StringRef, 3> v;90 progname.split(v, "-");91 for (StringRef s : v)92 if (Flavor f = getFlavor(s))93 return f;94 return Invalid;95}96 97static Flavor98parseFlavorWithoutMinGW(llvm::SmallVectorImpl<const char *> &argsV) {99 // Parse -flavor option.100 if (argsV.size() > 1 && argsV[1] == StringRef("-flavor")) {101 if (argsV.size() <= 2) {102 err("missing arg value for '-flavor'");103 return Invalid;104 }105 Flavor f = getFlavor(argsV[2]);106 if (f == Invalid) {107 err("Unknown flavor: " + StringRef(argsV[2]));108 return Invalid;109 }110 argsV.erase(argsV.begin() + 1, argsV.begin() + 3);111 return f;112 }113 114 // Deduct the flavor from argv[0].115 StringRef arg0 = path::filename(argsV[0]);116 arg0.consume_back_insensitive(".exe");117 Flavor f = parseProgname(arg0);118 if (f == Invalid) {119 err("lld is a generic driver.\n"120 "Invoke ld.lld (Unix), ld64.lld (macOS), lld-link (Windows), wasm-ld"121 " (WebAssembly) instead");122 return Invalid;123 }124 return f;125}126 127static Flavor parseFlavor(llvm::SmallVectorImpl<const char *> &argsV) {128 Flavor f = parseFlavorWithoutMinGW(argsV);129 if (f == Gnu) {130 auto isPE = isPETarget(argsV);131 if (!isPE)132 return Invalid;133 if (*isPE)134 return MinGW;135 }136 return f;137}138 139static Driver whichDriver(llvm::SmallVectorImpl<const char *> &argsV,140 llvm::ArrayRef<DriverDef> drivers) {141 Flavor f = parseFlavor(argsV);142 auto it =143 llvm::find_if(drivers, [=](auto &driverdef) { return driverdef.f == f; });144 if (it == drivers.end()) {145 // Driver is invalid or not available in this build.146 return [](llvm::ArrayRef<const char *>, llvm::raw_ostream &,147 llvm::raw_ostream &, bool, bool) { return false; };148 }149 return it->d;150}151 152namespace lld {153bool inTestOutputDisabled = false;154 155/// 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,158 llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS,159 llvm::ArrayRef<DriverDef> drivers, bool exitEarly) {160 SmallVector<const char *, 256> argsV(args);161 Driver d = whichDriver(argsV, drivers);162 // Run the driver. If an error occurs, false will be returned.163 int r = !d(argsV, stdoutOS, stderrOS, exitEarly, inTestOutputDisabled);164 // At this point 'r' is either 1 for error, and 0 for no error.165 166 // Call exit() if we can to avoid calling destructors.167 if (exitEarly)168 exitLld(r);169 170 // Delete the global context and clear the global context pointer, so that it171 // cannot be accessed anymore.172 CommonLinkerContext::destroy();173 174 return r;175}176} // namespace lld177 178Result lld::lldMain(llvm::ArrayRef<const char *> args,179 llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS,180 llvm::ArrayRef<DriverDef> drivers) {181 int 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).186 llvm::CrashRecoveryContext crc;187 if (!crc.RunSafely([&]() {188 r = unsafeLldMain(args, stdoutOS, stderrOS, drivers,189 /*exitEarly=*/false);190 }))191 return {crc.RetCode, /*canRunAgain=*/false};192 }193 194 // 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.196 llvm::CrashRecoveryContext crc;197 if (!crc.RunSafely([&]() { CommonLinkerContext::destroy(); })) {198 // The memory is corrupted beyond any possible recovery.199 return {r, /*canRunAgain=*/false};200 }201 return {r, /*canRunAgain=*/true};202}203