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