brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.5 KiB · 0b71c08 Raw
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