brintos

brintos / llvm-project-archived public Read only

0
0
Text · 27.6 KiB · 8d598be Raw
740 lines · cpp
1//===-- BareMetal.cpp - Bare Metal ToolChain --------------------*- C++ -*-===//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 "BareMetal.h"10 11#include "Gnu.h"12#include "clang/Driver/CommonArgs.h"13#include "clang/Driver/InputInfo.h"14 15#include "Arch/AArch64.h"16#include "Arch/ARM.h"17#include "Arch/RISCV.h"18#include "clang/Driver/Compilation.h"19#include "clang/Driver/Driver.h"20#include "clang/Driver/MultilibBuilder.h"21#include "clang/Options/Options.h"22#include "llvm/ADT/StringExtras.h"23#include "llvm/Option/ArgList.h"24#include "llvm/Support/Path.h"25#include "llvm/Support/VirtualFileSystem.h"26 27#include <sstream>28 29using namespace llvm::opt;30using namespace clang;31using namespace clang::driver;32using namespace clang::driver::tools;33using namespace clang::driver::toolchains;34 35static bool isRISCVBareMetal(const llvm::Triple &Triple) {36  if (!Triple.isRISCV())37    return false;38 39  if (Triple.getVendor() != llvm::Triple::UnknownVendor)40    return false;41 42  if (Triple.getOS() != llvm::Triple::UnknownOS)43    return false;44 45  return Triple.getEnvironmentName() == "elf";46}47 48/// Is the triple powerpc[64][le]-*-none-eabi?49static bool isPPCBareMetal(const llvm::Triple &Triple) {50  return Triple.isPPC() && Triple.getOS() == llvm::Triple::UnknownOS &&51         Triple.getEnvironment() == llvm::Triple::EABI;52}53 54static bool findRISCVMultilibs(const Driver &D,55                               const llvm::Triple &TargetTriple,56                               const ArgList &Args, DetectedMultilibs &Result) {57  Multilib::flags_list Flags;58  std::string Arch = riscv::getRISCVArch(Args, TargetTriple);59  StringRef Abi = tools::riscv::getRISCVABI(Args, TargetTriple);60 61  if (TargetTriple.isRISCV64()) {62    MultilibBuilder Imac =63        MultilibBuilder().flag("-march=rv64imac").flag("-mabi=lp64");64    MultilibBuilder Imafdc = MultilibBuilder("/rv64imafdc/lp64d")65                                 .flag("-march=rv64imafdc")66                                 .flag("-mabi=lp64d");67 68    // Multilib reuse69    bool UseImafdc =70        (Arch == "rv64imafdc") || (Arch == "rv64gc"); // gc => imafdc71 72    addMultilibFlag((Arch == "rv64imac"), "-march=rv64imac", Flags);73    addMultilibFlag(UseImafdc, "-march=rv64imafdc", Flags);74    addMultilibFlag(Abi == "lp64", "-mabi=lp64", Flags);75    addMultilibFlag(Abi == "lp64d", "-mabi=lp64d", Flags);76 77    Result.Multilibs =78        MultilibSetBuilder().Either(Imac, Imafdc).makeMultilibSet();79    return Result.Multilibs.select(D, Flags, Result.SelectedMultilibs);80  }81  if (TargetTriple.isRISCV32()) {82    MultilibBuilder Imac =83        MultilibBuilder().flag("-march=rv32imac").flag("-mabi=ilp32");84    MultilibBuilder I = MultilibBuilder("/rv32i/ilp32")85                            .flag("-march=rv32i")86                            .flag("-mabi=ilp32");87    MultilibBuilder Im = MultilibBuilder("/rv32im/ilp32")88                             .flag("-march=rv32im")89                             .flag("-mabi=ilp32");90    MultilibBuilder Iac = MultilibBuilder("/rv32iac/ilp32")91                              .flag("-march=rv32iac")92                              .flag("-mabi=ilp32");93    MultilibBuilder Imafc = MultilibBuilder("/rv32imafc/ilp32f")94                                .flag("-march=rv32imafc")95                                .flag("-mabi=ilp32f");96 97    // Multilib reuse98    bool UseI = (Arch == "rv32i") || (Arch == "rv32ic");    // ic => i99    bool UseIm = (Arch == "rv32im") || (Arch == "rv32imc"); // imc => im100    bool UseImafc = (Arch == "rv32imafc") || (Arch == "rv32imafdc") ||101                    (Arch == "rv32gc"); // imafdc,gc => imafc102 103    addMultilibFlag(UseI, "-march=rv32i", Flags);104    addMultilibFlag(UseIm, "-march=rv32im", Flags);105    addMultilibFlag((Arch == "rv32iac"), "-march=rv32iac", Flags);106    addMultilibFlag((Arch == "rv32imac"), "-march=rv32imac", Flags);107    addMultilibFlag(UseImafc, "-march=rv32imafc", Flags);108    addMultilibFlag(Abi == "ilp32", "-mabi=ilp32", Flags);109    addMultilibFlag(Abi == "ilp32f", "-mabi=ilp32f", Flags);110 111    Result.Multilibs =112        MultilibSetBuilder().Either(I, Im, Iac, Imac, Imafc).makeMultilibSet();113    return Result.Multilibs.select(D, Flags, Result.SelectedMultilibs);114  }115  return false;116}117 118static std::string computeClangRuntimesSysRoot(const Driver &D,119                                               bool IncludeTriple) {120  if (!D.SysRoot.empty())121    return D.SysRoot;122 123  SmallString<128> SysRootDir(D.Dir);124  llvm::sys::path::append(SysRootDir, "..", "lib", "clang-runtimes");125 126  if (IncludeTriple)127    llvm::sys::path::append(SysRootDir, D.getTargetTriple());128 129  return std::string(SysRootDir);130}131 132// Only consider the GCC toolchain based on the values provided through the133// `--gcc-toolchain` and `--gcc-install-dir` flags. The function below returns134// whether the GCC toolchain was initialized successfully.135bool BareMetal::initGCCInstallation(const llvm::Triple &Triple,136                                    const llvm::opt::ArgList &Args) {137  if (Args.getLastArg(options::OPT_gcc_toolchain) ||138      Args.getLastArg(clang::options::OPT_gcc_install_dir_EQ)) {139    GCCInstallation.init(Triple, Args);140    return GCCInstallation.isValid();141  }142  return false;143}144 145// This logic is adapted from RISCVToolChain.cpp as part of the ongoing effort146// to merge RISCVToolChain into the Baremetal toolchain. It infers the presence147// of a valid GCC toolchain by checking whether the `crt0.o` file exists in the148// `bin/../<target-triple>/lib` directory.149static bool detectGCCToolchainAdjacent(const Driver &D) {150  SmallString<128> GCCDir;151  llvm::sys::path::append(GCCDir, D.Dir, "..", D.getTargetTriple(),152                          "lib/crt0.o");153  return llvm::sys::fs::exists(GCCDir);154}155 156// If no sysroot is provided the driver will first attempt to infer it from the157// values of `--gcc-install-dir` or `--gcc-toolchain`, which specify the158// location of a GCC toolchain.159// If neither flag is used, the sysroot defaults to either:160//    - `bin/../<target-triple>`161//    - `bin/../lib/clang-runtimes/<target-triple>`162//163// To use the `clang-runtimes` path, ensure that `../<target-triple>/lib/crt0.o`164// does not exist relative to the driver.165std::string BareMetal::computeSysRoot() const {166  // Use Baremetal::sysroot if it has already been set.167  if (!SysRoot.empty())168    return SysRoot;169 170  // Use the sysroot specified via the `--sysroot` command-line flag, if171  // provided.172  const Driver &D = getDriver();173  if (!D.SysRoot.empty())174    return D.SysRoot;175 176  // Attempt to infer sysroot from a valid GCC installation.177  // If no valid GCC installation, check for a GCC toolchain alongside Clang.178  SmallString<128> inferredSysRoot;179  if (IsGCCInstallationValid) {180    llvm::sys::path::append(inferredSysRoot, GCCInstallation.getParentLibPath(),181                            "..", GCCInstallation.getTriple().str());182  } else if (detectGCCToolchainAdjacent(D)) {183    // Use the triple as provided to the driver. Unlike the parsed triple184    // this has not been normalized to always contain every field.185    llvm::sys::path::append(inferredSysRoot, D.Dir, "..", D.getTargetTriple());186  }187  // If a valid sysroot was inferred and exists, use it188  if (!inferredSysRoot.empty() && llvm::sys::fs::exists(inferredSysRoot))189    return std::string(inferredSysRoot);190 191  // Use the clang-runtimes path.192  return computeClangRuntimesSysRoot(D, /*IncludeTriple*/ true);193}194 195std::string BareMetal::getCompilerRTPath() const {196  const Driver &D = getDriver();197  if (IsGCCInstallationValid || detectGCCToolchainAdjacent(getDriver())) {198    SmallString<128> Path(D.ResourceDir);199    llvm::sys::path::append(Path, "lib");200    return std::string(Path.str());201  }202  return ToolChain::getCompilerRTPath();203}204 205static void addMultilibsFilePaths(const Driver &D, const MultilibSet &Multilibs,206                                  const Multilib &Multilib,207                                  StringRef InstallPath,208                                  ToolChain::path_list &Paths) {209  if (const auto &PathsCallback = Multilibs.filePathsCallback())210    for (const auto &Path : PathsCallback(Multilib))211      addPathIfExists(D, InstallPath + Path, Paths);212}213 214// GCC mutltilibs will only work for those targets that have their multlib215// structure encoded into GCCInstallation. Baremetal toolchain supports ARM,216// AArch64, RISCV and PPC and of these only RISCV have GCC multilibs hardcoded217// in GCCInstallation.218BareMetal::BareMetal(const Driver &D, const llvm::Triple &Triple,219                     const ArgList &Args)220    : Generic_ELF(D, Triple, Args) {221  IsGCCInstallationValid = initGCCInstallation(Triple, Args);222  std::string ComputedSysRoot = computeSysRoot();223  if (IsGCCInstallationValid) {224    if (!isRISCVBareMetal(Triple))225      D.Diag(clang::diag::warn_drv_multilib_not_available_for_target);226 227    Multilibs = GCCInstallation.getMultilibs();228    SelectedMultilibs.assign({GCCInstallation.getMultilib()});229 230    path_list &Paths = getFilePaths();231    // Add toolchain/multilib specific file paths.232    addMultilibsFilePaths(D, Multilibs, SelectedMultilibs.back(),233                          GCCInstallation.getInstallPath(), Paths);234    // Adding filepath for locating crt{begin,end}.o files.235    Paths.push_back(GCCInstallation.getInstallPath().str());236    // Adding filepath for locating crt0.o file.237    Paths.push_back(ComputedSysRoot + "/lib");238 239    ToolChain::path_list &PPaths = getProgramPaths();240    // Multilib cross-compiler GCC installations put ld in a triple-prefixed241    // directory off of the parent of the GCC installation.242    PPaths.push_back(Twine(GCCInstallation.getParentLibPath() + "/../" +243                           GCCInstallation.getTriple().str() + "/bin")244                         .str());245    PPaths.push_back((GCCInstallation.getParentLibPath() + "/../bin").str());246  } else {247    getProgramPaths().push_back(getDriver().Dir);248    findMultilibs(D, Triple, Args);249    const SmallString<128> SysRootDir(computeSysRoot());250    if (!SysRootDir.empty()) {251      for (const Multilib &M : getOrderedMultilibs()) {252        SmallString<128> Dir(SysRootDir);253        llvm::sys::path::append(Dir, M.osSuffix(), "lib");254        getFilePaths().push_back(std::string(Dir));255        getLibraryPaths().push_back(std::string(Dir));256      }257    }258  }259}260 261static void262findMultilibsFromYAML(const ToolChain &TC, const Driver &D,263                      StringRef MultilibPath, const ArgList &Args,264                      DetectedMultilibs &Result,265                      SmallVector<StringRef> &CustomFlagsMacroDefines) {266  llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> MB =267      D.getVFS().getBufferForFile(MultilibPath);268  if (!MB)269    return;270  Multilib::flags_list Flags = TC.getMultilibFlags(Args);271  llvm::ErrorOr<MultilibSet> ErrorOrMultilibSet =272      MultilibSet::parseYaml(*MB.get());273  if (ErrorOrMultilibSet.getError())274    return;275  Result.Multilibs = ErrorOrMultilibSet.get();276  if (Result.Multilibs.select(D, Flags, Result.SelectedMultilibs,277                              &CustomFlagsMacroDefines))278    return;279  D.Diag(clang::diag::warn_drv_missing_multilib) << llvm::join(Flags, " ");280  std::stringstream ss;281 282  // If multilib selection didn't complete successfully, report a list283  // of all the configurations the user could have provided.284  for (const Multilib &Multilib : Result.Multilibs)285    if (!Multilib.isError())286      ss << "\n" << llvm::join(Multilib.flags(), " ");287  D.Diag(clang::diag::note_drv_available_multilibs) << ss.str();288 289  // Now report any custom error messages requested by the YAML. We do290  // this after displaying the list of available multilibs, because291  // that list is probably large, and (in interactive use) risks292  // scrolling the useful error message off the top of the user's293  // terminal.294  for (const Multilib &Multilib : Result.SelectedMultilibs)295    if (Multilib.isError())296      D.Diag(clang::diag::err_drv_multilib_custom_error)297          << Multilib.getErrorMessage();298 299  // If there was an error, clear the SelectedMultilibs vector, in300  // case it contains partial data.301  Result.SelectedMultilibs.clear();302}303 304static constexpr llvm::StringLiteral MultilibFilename = "multilib.yaml";305 306static std::optional<llvm::SmallString<128>>307getMultilibConfigPath(const Driver &D, const llvm::Triple &Triple,308                      const ArgList &Args) {309  llvm::SmallString<128> MultilibPath;310  if (Arg *ConfigFileArg = Args.getLastArg(options::OPT_multi_lib_config)) {311    MultilibPath = ConfigFileArg->getValue();312    if (!D.getVFS().exists(MultilibPath)) {313      D.Diag(clang::diag::err_drv_no_such_file) << MultilibPath.str();314      return {};315    }316  } else {317    MultilibPath = computeClangRuntimesSysRoot(D, /*IncludeTriple=*/false);318    llvm::sys::path::append(MultilibPath, MultilibFilename);319  }320  return MultilibPath;321}322 323void BareMetal::findMultilibs(const Driver &D, const llvm::Triple &Triple,324                              const ArgList &Args) {325  DetectedMultilibs Result;326  // Look for a multilib.yaml before trying target-specific hardwired logic.327  // If it exists, always do what it specifies.328  std::optional<llvm::SmallString<128>> MultilibPath =329      getMultilibConfigPath(D, Triple, Args);330  if (!MultilibPath)331    return;332  if (D.getVFS().exists(*MultilibPath)) {333    // If multilib.yaml is found, update sysroot so it doesn't use a target334    // specific suffix335    SysRoot = computeClangRuntimesSysRoot(D, /*IncludeTriple=*/false);336    SmallVector<StringRef> CustomFlagMacroDefines;337    findMultilibsFromYAML(*this, D, *MultilibPath, Args, Result,338                          CustomFlagMacroDefines);339    SelectedMultilibs = Result.SelectedMultilibs;340    Multilibs = Result.Multilibs;341    MultilibMacroDefines.append(CustomFlagMacroDefines.begin(),342                                CustomFlagMacroDefines.end());343  } else if (isRISCVBareMetal(Triple) && !detectGCCToolchainAdjacent(D)) {344    if (findRISCVMultilibs(D, Triple, Args, Result)) {345      SelectedMultilibs = Result.SelectedMultilibs;346      Multilibs = Result.Multilibs;347    }348  }349}350 351bool BareMetal::handlesTarget(const llvm::Triple &Triple) {352  return arm::isARMEABIBareMetal(Triple) ||353         aarch64::isAArch64BareMetal(Triple) || isRISCVBareMetal(Triple) ||354         isPPCBareMetal(Triple);355}356 357Tool *BareMetal::buildLinker() const {358  return new tools::baremetal::Linker(*this);359}360 361Tool *BareMetal::buildStaticLibTool() const {362  return new tools::baremetal::StaticLibTool(*this);363}364 365BareMetal::OrderedMultilibs BareMetal::getOrderedMultilibs() const {366  // Get multilibs in reverse order because they're ordered most-specific last.367  if (!SelectedMultilibs.empty())368    return llvm::reverse(SelectedMultilibs);369 370  // No multilibs selected so return a single default multilib.371  static const llvm::SmallVector<Multilib> Default = {Multilib()};372  return llvm::reverse(Default);373}374 375ToolChain::CXXStdlibType BareMetal::GetDefaultCXXStdlibType() const {376  if (getTriple().isRISCV() && IsGCCInstallationValid)377    return ToolChain::CST_Libstdcxx;378  return ToolChain::CST_Libcxx;379}380 381ToolChain::RuntimeLibType BareMetal::GetDefaultRuntimeLibType() const {382  if (getTriple().isRISCV() && IsGCCInstallationValid)383    return ToolChain::RLT_Libgcc;384  return ToolChain::RLT_CompilerRT;385}386 387// TODO: Add a validity check for GCCInstallation.388//       If valid, use `UNW_Libgcc`; otherwise, use `UNW_None`.389ToolChain::UnwindLibType390BareMetal::GetUnwindLibType(const llvm::opt::ArgList &Args) const {391  if (getTriple().isRISCV())392    return ToolChain::UNW_None;393 394  return ToolChain::GetUnwindLibType(Args);395}396 397void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs,398                                          ArgStringList &CC1Args) const {399  if (DriverArgs.hasArg(options::OPT_nostdinc))400    return;401 402  if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {403    SmallString<128> Dir(getDriver().ResourceDir);404    llvm::sys::path::append(Dir, "include");405    addSystemInclude(DriverArgs, CC1Args, Dir.str());406  }407 408  if (DriverArgs.hasArg(options::OPT_nostdlibinc))409    return;410 411  if (std::optional<std::string> Path = getStdlibIncludePath())412    addSystemInclude(DriverArgs, CC1Args, *Path);413 414  const SmallString<128> SysRootDir(computeSysRoot());415  if (!SysRootDir.empty()) {416    for (const Multilib &M : getOrderedMultilibs()) {417      SmallString<128> Dir(SysRootDir);418      llvm::sys::path::append(Dir, M.includeSuffix());419      llvm::sys::path::append(Dir, "include");420      addSystemInclude(DriverArgs, CC1Args, Dir.str());421    }422  }423}424 425void BareMetal::addClangTargetOptions(const ArgList &DriverArgs,426                                      ArgStringList &CC1Args,427                                      Action::OffloadKind) const {428  CC1Args.push_back("-nostdsysteminc");429}430 431void BareMetal::addLibStdCxxIncludePaths(432    const llvm::opt::ArgList &DriverArgs,433    llvm::opt::ArgStringList &CC1Args) const {434  if (!IsGCCInstallationValid)435    return;436  const GCCVersion &Version = GCCInstallation.getVersion();437  StringRef TripleStr = GCCInstallation.getTriple().str();438  const Multilib &Multilib = GCCInstallation.getMultilib();439  addLibStdCXXIncludePaths(computeSysRoot() + "/include/c++/" + Version.Text,440                           TripleStr, Multilib.includeSuffix(), DriverArgs,441                           CC1Args);442}443 444void BareMetal::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,445                                             ArgStringList &CC1Args) const {446  if (DriverArgs.hasArg(options::OPT_nostdinc, options::OPT_nostdlibinc,447                        options::OPT_nostdincxx))448    return;449 450  const Driver &D = getDriver();451  std::string Target = getTripleString();452 453  auto AddCXXIncludePath = [&](StringRef Path) {454    std::string Version = detectLibcxxVersion(Path);455    if (Version.empty())456      return;457 458    {459      // First the per-target include dir: include/<target>/c++/v1.460      SmallString<128> TargetDir(Path);461      llvm::sys::path::append(TargetDir, Target, "c++", Version);462      addSystemInclude(DriverArgs, CC1Args, TargetDir);463    }464 465    {466      // Then the generic dir: include/c++/v1.467      SmallString<128> Dir(Path);468      llvm::sys::path::append(Dir, "c++", Version);469      addSystemInclude(DriverArgs, CC1Args, Dir);470    }471  };472 473  switch (GetCXXStdlibType(DriverArgs)) {474  case ToolChain::CST_Libcxx: {475    SmallString<128> P(D.Dir);476    llvm::sys::path::append(P, "..", "include");477    AddCXXIncludePath(P);478    break;479  }480  case ToolChain::CST_Libstdcxx:481    addLibStdCxxIncludePaths(DriverArgs, CC1Args);482    break;483  }484 485  std::string SysRootDir(computeSysRoot());486  if (SysRootDir.empty())487    return;488 489  for (const Multilib &M : getOrderedMultilibs()) {490    SmallString<128> Dir(SysRootDir);491    llvm::sys::path::append(Dir, M.gccSuffix());492    switch (GetCXXStdlibType(DriverArgs)) {493    case ToolChain::CST_Libcxx: {494      // First check sysroot/usr/include/c++/v1 if it exists.495      SmallString<128> TargetDir(Dir);496      llvm::sys::path::append(TargetDir, "usr", "include", "c++", "v1");497      if (D.getVFS().exists(TargetDir)) {498        addSystemInclude(DriverArgs, CC1Args, TargetDir.str());499        break;500      }501      // Add generic path if nothing else succeeded so far.502      llvm::sys::path::append(Dir, "include", "c++", "v1");503      addSystemInclude(DriverArgs, CC1Args, Dir.str());504      break;505    }506    case ToolChain::CST_Libstdcxx: {507      llvm::sys::path::append(Dir, "include", "c++");508      std::error_code EC;509      Generic_GCC::GCCVersion Version = {"", -1, -1, -1, "", "", ""};510      // Walk the subdirs, and find the one with the newest gcc version:511      for (llvm::vfs::directory_iterator512               LI = D.getVFS().dir_begin(Dir.str(), EC),513               LE;514           !EC && LI != LE; LI = LI.increment(EC)) {515        StringRef VersionText = llvm::sys::path::filename(LI->path());516        auto CandidateVersion = Generic_GCC::GCCVersion::Parse(VersionText);517        if (CandidateVersion.Major == -1)518          continue;519        if (CandidateVersion <= Version)520          continue;521        Version = CandidateVersion;522      }523      if (Version.Major != -1) {524        llvm::sys::path::append(Dir, Version.Text);525        addSystemInclude(DriverArgs, CC1Args, Dir.str());526      }527      break;528    }529    }530  }531}532 533void baremetal::StaticLibTool::ConstructJob(Compilation &C, const JobAction &JA,534                                            const InputInfo &Output,535                                            const InputInfoList &Inputs,536                                            const ArgList &Args,537                                            const char *LinkingOutput) const {538  const Driver &D = getToolChain().getDriver();539 540  // Silence warning for "clang -g foo.o -o foo"541  Args.ClaimAllArgs(options::OPT_g_Group);542  // and "clang -emit-llvm foo.o -o foo"543  Args.ClaimAllArgs(options::OPT_emit_llvm);544  // and for "clang -w foo.o -o foo". Other warning options are already545  // handled somewhere else.546  Args.ClaimAllArgs(options::OPT_w);547  // Silence warnings when linking C code with a C++ '-stdlib' argument.548  Args.ClaimAllArgs(options::OPT_stdlib_EQ);549 550  // ar tool command "llvm-ar <options> <output_file> <input_files>".551  ArgStringList CmdArgs;552  // Create and insert file members with a deterministic index.553  CmdArgs.push_back("rcsD");554  CmdArgs.push_back(Output.getFilename());555 556  for (const auto &II : Inputs) {557    if (II.isFilename()) {558      CmdArgs.push_back(II.getFilename());559    }560  }561 562  // Delete old output archive file if it already exists before generating a new563  // archive file.564  const char *OutputFileName = Output.getFilename();565  if (Output.isFilename() && llvm::sys::fs::exists(OutputFileName)) {566    if (std::error_code EC = llvm::sys::fs::remove(OutputFileName)) {567      D.Diag(diag::err_drv_unable_to_remove_file) << EC.message();568      return;569    }570  }571 572  const char *Exec = Args.MakeArgString(getToolChain().GetStaticLibToolPath());573  C.addCommand(std::make_unique<Command>(JA, *this,574                                         ResponseFileSupport::AtFileCurCP(),575                                         Exec, CmdArgs, Inputs, Output));576}577 578void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA,579                                     const InputInfo &Output,580                                     const InputInfoList &Inputs,581                                     const ArgList &Args,582                                     const char *LinkingOutput) const {583  ArgStringList CmdArgs;584 585  auto &TC = static_cast<const toolchains::BareMetal &>(getToolChain());586  const Driver &D = getToolChain().getDriver();587  const llvm::Triple::ArchType Arch = TC.getArch();588  const llvm::Triple &Triple = getToolChain().getEffectiveTriple();589  const bool IsStaticPIE = getStaticPIE(Args, TC);590 591  if (!D.SysRoot.empty())592    CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));593 594  CmdArgs.push_back("-Bstatic");595  if (IsStaticPIE) {596    CmdArgs.push_back("-pie");597    CmdArgs.push_back("--no-dynamic-linker");598    CmdArgs.push_back("-z");599    CmdArgs.push_back("text");600  }601 602  if (const char *LDMOption = getLDMOption(TC.getTriple(), Args)) {603    CmdArgs.push_back("-m");604    CmdArgs.push_back(LDMOption);605  } else {606    D.Diag(diag::err_target_unknown_triple) << Triple.str();607    return;608  }609 610  if (Triple.isRISCV()) {611    CmdArgs.push_back("-X");612    if (Args.hasArg(options::OPT_mno_relax))613      CmdArgs.push_back("--no-relax");614  }615 616  if (Triple.isARM() || Triple.isThumb()) {617    bool IsBigEndian = arm::isARMBigEndian(Triple, Args);618    if (IsBigEndian)619      arm::appendBE8LinkFlag(Args, CmdArgs, Triple);620    CmdArgs.push_back(IsBigEndian ? "-EB" : "-EL");621  } else if (Triple.isAArch64()) {622    CmdArgs.push_back(Arch == llvm::Triple::aarch64_be ? "-EB" : "-EL");623  }624 625  bool NeedCRTs =626      !Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles);627 628  const char *CRTBegin, *CRTEnd;629  if (NeedCRTs) {630    if (!Args.hasArg(options::OPT_r)) {631      const char *crt = "crt0.o";632      if (IsStaticPIE)633        crt = "rcrt1.o";634      CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath(crt)));635    }636    if (TC.hasValidGCCInstallation() || detectGCCToolchainAdjacent(D)) {637      auto RuntimeLib = TC.GetRuntimeLibType(Args);638      switch (RuntimeLib) {639      case (ToolChain::RLT_Libgcc): {640        CRTBegin = IsStaticPIE ? "crtbeginS.o" : "crtbegin.o";641        CRTEnd = IsStaticPIE ? "crtendS.o" : "crtend.o";642        break;643      }644      case (ToolChain::RLT_CompilerRT): {645        CRTBegin =646            TC.getCompilerRTArgString(Args, "crtbegin", ToolChain::FT_Object);647        CRTEnd =648            TC.getCompilerRTArgString(Args, "crtend", ToolChain::FT_Object);649        break;650      }651      }652      CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath(CRTBegin)));653    }654  }655 656  Args.addAllArgs(CmdArgs,657                  {options::OPT_L, options::OPT_u, options::OPT_T_Group,658                   options::OPT_s, options::OPT_t, options::OPT_r});659 660  TC.AddFilePathLibArgs(Args, CmdArgs);661 662  for (const auto &LibPath : TC.getLibraryPaths())663    CmdArgs.push_back(Args.MakeArgString(llvm::Twine("-L", LibPath)));664 665  if (D.isUsingLTO())666    addLTOOptions(TC, Args, CmdArgs, Output, Inputs,667                  D.getLTOMode() == LTOK_Thin);668 669  AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);670 671  if (TC.ShouldLinkCXXStdlib(Args)) {672    bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) &&673                               !Args.hasArg(options::OPT_static);674    if (OnlyLibstdcxxStatic)675      CmdArgs.push_back("-Bstatic");676    TC.AddCXXStdlibLibArgs(Args, CmdArgs);677    if (OnlyLibstdcxxStatic)678      CmdArgs.push_back("-Bdynamic");679    CmdArgs.push_back("-lm");680  }681 682  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {683    CmdArgs.push_back("--start-group");684    AddRunTimeLibs(TC, D, CmdArgs, Args);685    if (!Args.hasArg(options::OPT_nolibc))686      CmdArgs.push_back("-lc");687    if (TC.hasValidGCCInstallation() || detectGCCToolchainAdjacent(D))688      CmdArgs.push_back("-lgloss");689    CmdArgs.push_back("--end-group");690  }691 692  if ((TC.hasValidGCCInstallation() || detectGCCToolchainAdjacent(D)) &&693      NeedCRTs)694    CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath(CRTEnd)));695 696  // The R_ARM_TARGET2 relocation must be treated as R_ARM_REL32 on arm*-*-elf697  // and arm*-*-eabi (the default is R_ARM_GOT_PREL, used on arm*-*-linux and698  // arm*-*-*bsd).699  if (arm::isARMEABIBareMetal(TC.getTriple()))700    CmdArgs.push_back("--target2=rel");701 702  CmdArgs.push_back("-o");703  CmdArgs.push_back(Output.getFilename());704 705  C.addCommand(std::make_unique<Command>(706      JA, *this, ResponseFileSupport::AtFileCurCP(),707      Args.MakeArgString(TC.GetLinkerPath()), CmdArgs, Inputs, Output));708}709 710// BareMetal toolchain allows all sanitizers where the compiler generates valid711// code, ignoring all runtime library support issues on the assumption that712// baremetal targets typically implement their own runtime support.713SanitizerMask BareMetal::getSupportedSanitizers() const {714  const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64;715  const bool IsAArch64 = getTriple().getArch() == llvm::Triple::aarch64 ||716                         getTriple().getArch() == llvm::Triple::aarch64_be;717  const bool IsRISCV64 = getTriple().getArch() == llvm::Triple::riscv64;718  SanitizerMask Res = ToolChain::getSupportedSanitizers();719  Res |= SanitizerKind::Address;720  Res |= SanitizerKind::KernelAddress;721  Res |= SanitizerKind::PointerCompare;722  Res |= SanitizerKind::PointerSubtract;723  Res |= SanitizerKind::Fuzzer;724  Res |= SanitizerKind::FuzzerNoLink;725  Res |= SanitizerKind::Vptr;726  Res |= SanitizerKind::SafeStack;727  Res |= SanitizerKind::Thread;728  Res |= SanitizerKind::Scudo;729  if (IsX86_64 || IsAArch64 || IsRISCV64) {730    Res |= SanitizerKind::HWAddress;731    Res |= SanitizerKind::KernelHWAddress;732  }733  return Res;734}735 736SmallVector<std::string>737BareMetal::getMultilibMacroDefinesStr(llvm::opt::ArgList &Args) const {738  return MultilibMacroDefines;739}740