10b57cec5SDimitry Andric //===-- BareMetal.cpp - Bare Metal ToolChain --------------------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "BareMetal.h" 100b57cec5SDimitry Andric 110b57cec5SDimitry Andric #include "CommonArgs.h" 120b57cec5SDimitry Andric #include "Gnu.h" 13fe6060f1SDimitry Andric #include "clang/Driver/InputInfo.h" 140b57cec5SDimitry Andric 1506c3fb27SDimitry Andric #include "Arch/ARM.h" 16e8d8bef9SDimitry Andric #include "Arch/RISCV.h" 170b57cec5SDimitry Andric #include "clang/Driver/Compilation.h" 180b57cec5SDimitry Andric #include "clang/Driver/Driver.h" 190b57cec5SDimitry Andric #include "clang/Driver/DriverDiagnostic.h" 2006c3fb27SDimitry Andric #include "clang/Driver/MultilibBuilder.h" 210b57cec5SDimitry Andric #include "clang/Driver/Options.h" 2206c3fb27SDimitry Andric #include "llvm/ADT/StringExtras.h" 230b57cec5SDimitry Andric #include "llvm/Option/ArgList.h" 240b57cec5SDimitry Andric #include "llvm/Support/Path.h" 250b57cec5SDimitry Andric #include "llvm/Support/VirtualFileSystem.h" 260b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 270b57cec5SDimitry Andric 2806c3fb27SDimitry Andric #include <sstream> 2906c3fb27SDimitry Andric 300b57cec5SDimitry Andric using namespace llvm::opt; 310b57cec5SDimitry Andric using namespace clang; 320b57cec5SDimitry Andric using namespace clang::driver; 330b57cec5SDimitry Andric using namespace clang::driver::tools; 340b57cec5SDimitry Andric using namespace clang::driver::toolchains; 350b57cec5SDimitry Andric 36e8d8bef9SDimitry Andric static bool findRISCVMultilibs(const Driver &D, 37e8d8bef9SDimitry Andric const llvm::Triple &TargetTriple, 38e8d8bef9SDimitry Andric const ArgList &Args, DetectedMultilibs &Result) { 39e8d8bef9SDimitry Andric Multilib::flags_list Flags; 40*0fca6ea1SDimitry Andric std::string Arch = riscv::getRISCVArch(Args, TargetTriple); 41e8d8bef9SDimitry Andric StringRef Abi = tools::riscv::getRISCVABI(Args, TargetTriple); 42e8d8bef9SDimitry Andric 43bdd1243dSDimitry Andric if (TargetTriple.isRISCV64()) { 4406c3fb27SDimitry Andric MultilibBuilder Imac = 4506c3fb27SDimitry Andric MultilibBuilder().flag("-march=rv64imac").flag("-mabi=lp64"); 4606c3fb27SDimitry Andric MultilibBuilder Imafdc = MultilibBuilder("/rv64imafdc/lp64d") 4706c3fb27SDimitry Andric .flag("-march=rv64imafdc") 4806c3fb27SDimitry Andric .flag("-mabi=lp64d"); 49e8d8bef9SDimitry Andric 50e8d8bef9SDimitry Andric // Multilib reuse 51e8d8bef9SDimitry Andric bool UseImafdc = 52e8d8bef9SDimitry Andric (Arch == "rv64imafdc") || (Arch == "rv64gc"); // gc => imafdc 53e8d8bef9SDimitry Andric 5406c3fb27SDimitry Andric addMultilibFlag((Arch == "rv64imac"), "-march=rv64imac", Flags); 5506c3fb27SDimitry Andric addMultilibFlag(UseImafdc, "-march=rv64imafdc", Flags); 5606c3fb27SDimitry Andric addMultilibFlag(Abi == "lp64", "-mabi=lp64", Flags); 5706c3fb27SDimitry Andric addMultilibFlag(Abi == "lp64d", "-mabi=lp64d", Flags); 58e8d8bef9SDimitry Andric 5906c3fb27SDimitry Andric Result.Multilibs = 6006c3fb27SDimitry Andric MultilibSetBuilder().Either(Imac, Imafdc).makeMultilibSet(); 6106c3fb27SDimitry Andric return Result.Multilibs.select(Flags, Result.SelectedMultilibs); 62e8d8bef9SDimitry Andric } 63bdd1243dSDimitry Andric if (TargetTriple.isRISCV32()) { 6406c3fb27SDimitry Andric MultilibBuilder Imac = 6506c3fb27SDimitry Andric MultilibBuilder().flag("-march=rv32imac").flag("-mabi=ilp32"); 6606c3fb27SDimitry Andric MultilibBuilder I = MultilibBuilder("/rv32i/ilp32") 6706c3fb27SDimitry Andric .flag("-march=rv32i") 6806c3fb27SDimitry Andric .flag("-mabi=ilp32"); 6906c3fb27SDimitry Andric MultilibBuilder Im = MultilibBuilder("/rv32im/ilp32") 7006c3fb27SDimitry Andric .flag("-march=rv32im") 7106c3fb27SDimitry Andric .flag("-mabi=ilp32"); 7206c3fb27SDimitry Andric MultilibBuilder Iac = MultilibBuilder("/rv32iac/ilp32") 7306c3fb27SDimitry Andric .flag("-march=rv32iac") 7406c3fb27SDimitry Andric .flag("-mabi=ilp32"); 7506c3fb27SDimitry Andric MultilibBuilder Imafc = MultilibBuilder("/rv32imafc/ilp32f") 7606c3fb27SDimitry Andric .flag("-march=rv32imafc") 7706c3fb27SDimitry Andric .flag("-mabi=ilp32f"); 78e8d8bef9SDimitry Andric 79e8d8bef9SDimitry Andric // Multilib reuse 80e8d8bef9SDimitry Andric bool UseI = (Arch == "rv32i") || (Arch == "rv32ic"); // ic => i 81e8d8bef9SDimitry Andric bool UseIm = (Arch == "rv32im") || (Arch == "rv32imc"); // imc => im 82e8d8bef9SDimitry Andric bool UseImafc = (Arch == "rv32imafc") || (Arch == "rv32imafdc") || 83e8d8bef9SDimitry Andric (Arch == "rv32gc"); // imafdc,gc => imafc 84e8d8bef9SDimitry Andric 8506c3fb27SDimitry Andric addMultilibFlag(UseI, "-march=rv32i", Flags); 8606c3fb27SDimitry Andric addMultilibFlag(UseIm, "-march=rv32im", Flags); 8706c3fb27SDimitry Andric addMultilibFlag((Arch == "rv32iac"), "-march=rv32iac", Flags); 8806c3fb27SDimitry Andric addMultilibFlag((Arch == "rv32imac"), "-march=rv32imac", Flags); 8906c3fb27SDimitry Andric addMultilibFlag(UseImafc, "-march=rv32imafc", Flags); 9006c3fb27SDimitry Andric addMultilibFlag(Abi == "ilp32", "-mabi=ilp32", Flags); 9106c3fb27SDimitry Andric addMultilibFlag(Abi == "ilp32f", "-mabi=ilp32f", Flags); 92e8d8bef9SDimitry Andric 9306c3fb27SDimitry Andric Result.Multilibs = 9406c3fb27SDimitry Andric MultilibSetBuilder().Either(I, Im, Iac, Imac, Imafc).makeMultilibSet(); 9506c3fb27SDimitry Andric return Result.Multilibs.select(Flags, Result.SelectedMultilibs); 96e8d8bef9SDimitry Andric } 97e8d8bef9SDimitry Andric return false; 98e8d8bef9SDimitry Andric } 99e8d8bef9SDimitry Andric 1000b57cec5SDimitry Andric BareMetal::BareMetal(const Driver &D, const llvm::Triple &Triple, 1010b57cec5SDimitry Andric const ArgList &Args) 1020b57cec5SDimitry Andric : ToolChain(D, Triple, Args) { 1030b57cec5SDimitry Andric getProgramPaths().push_back(getDriver().Dir); 1040b57cec5SDimitry Andric 105e8d8bef9SDimitry Andric findMultilibs(D, Triple, Args); 106e8d8bef9SDimitry Andric SmallString<128> SysRoot(computeSysRoot()); 107e8d8bef9SDimitry Andric if (!SysRoot.empty()) { 10806c3fb27SDimitry Andric for (const Multilib &M : getOrderedMultilibs()) { 10906c3fb27SDimitry Andric SmallString<128> Dir(SysRoot); 11006c3fb27SDimitry Andric llvm::sys::path::append(Dir, M.osSuffix(), "lib"); 11106c3fb27SDimitry Andric getFilePaths().push_back(std::string(Dir)); 11206c3fb27SDimitry Andric getLibraryPaths().push_back(std::string(Dir)); 11306c3fb27SDimitry Andric } 114e8d8bef9SDimitry Andric } 115e8d8bef9SDimitry Andric } 1160b57cec5SDimitry Andric 11706c3fb27SDimitry Andric /// Is the triple {arm,armeb,thumb,thumbeb}-none-none-{eabi,eabihf} ? 1180b57cec5SDimitry Andric static bool isARMBareMetal(const llvm::Triple &Triple) { 1190b57cec5SDimitry Andric if (Triple.getArch() != llvm::Triple::arm && 12006c3fb27SDimitry Andric Triple.getArch() != llvm::Triple::thumb && 12106c3fb27SDimitry Andric Triple.getArch() != llvm::Triple::armeb && 12206c3fb27SDimitry Andric Triple.getArch() != llvm::Triple::thumbeb) 1230b57cec5SDimitry Andric return false; 1240b57cec5SDimitry Andric 1250b57cec5SDimitry Andric if (Triple.getVendor() != llvm::Triple::UnknownVendor) 1260b57cec5SDimitry Andric return false; 1270b57cec5SDimitry Andric 1280b57cec5SDimitry Andric if (Triple.getOS() != llvm::Triple::UnknownOS) 1290b57cec5SDimitry Andric return false; 1300b57cec5SDimitry Andric 1310b57cec5SDimitry Andric if (Triple.getEnvironment() != llvm::Triple::EABI && 1320b57cec5SDimitry Andric Triple.getEnvironment() != llvm::Triple::EABIHF) 1330b57cec5SDimitry Andric return false; 1340b57cec5SDimitry Andric 1350b57cec5SDimitry Andric return true; 1360b57cec5SDimitry Andric } 1370b57cec5SDimitry Andric 13806c3fb27SDimitry Andric /// Is the triple {aarch64.aarch64_be}-none-elf? 139349cc55cSDimitry Andric static bool isAArch64BareMetal(const llvm::Triple &Triple) { 14006c3fb27SDimitry Andric if (Triple.getArch() != llvm::Triple::aarch64 && 14106c3fb27SDimitry Andric Triple.getArch() != llvm::Triple::aarch64_be) 142349cc55cSDimitry Andric return false; 143349cc55cSDimitry Andric 144349cc55cSDimitry Andric if (Triple.getVendor() != llvm::Triple::UnknownVendor) 145349cc55cSDimitry Andric return false; 146349cc55cSDimitry Andric 147349cc55cSDimitry Andric if (Triple.getOS() != llvm::Triple::UnknownOS) 148349cc55cSDimitry Andric return false; 149349cc55cSDimitry Andric 150349cc55cSDimitry Andric return Triple.getEnvironmentName() == "elf"; 151349cc55cSDimitry Andric } 152349cc55cSDimitry Andric 153e8d8bef9SDimitry Andric static bool isRISCVBareMetal(const llvm::Triple &Triple) { 154bdd1243dSDimitry Andric if (!Triple.isRISCV()) 155e8d8bef9SDimitry Andric return false; 156e8d8bef9SDimitry Andric 157e8d8bef9SDimitry Andric if (Triple.getVendor() != llvm::Triple::UnknownVendor) 158e8d8bef9SDimitry Andric return false; 159e8d8bef9SDimitry Andric 160e8d8bef9SDimitry Andric if (Triple.getOS() != llvm::Triple::UnknownOS) 161e8d8bef9SDimitry Andric return false; 162e8d8bef9SDimitry Andric 163e8d8bef9SDimitry Andric return Triple.getEnvironmentName() == "elf"; 164e8d8bef9SDimitry Andric } 165e8d8bef9SDimitry Andric 16606c3fb27SDimitry Andric /// Is the triple powerpc[64][le]-*-none-eabi? 16706c3fb27SDimitry Andric static bool isPPCBareMetal(const llvm::Triple &Triple) { 16806c3fb27SDimitry Andric return Triple.isPPC() && Triple.getOS() == llvm::Triple::UnknownOS && 16906c3fb27SDimitry Andric Triple.getEnvironment() == llvm::Triple::EABI; 17006c3fb27SDimitry Andric } 17106c3fb27SDimitry Andric 17206c3fb27SDimitry Andric static void findMultilibsFromYAML(const ToolChain &TC, const Driver &D, 17306c3fb27SDimitry Andric StringRef MultilibPath, const ArgList &Args, 17406c3fb27SDimitry Andric DetectedMultilibs &Result) { 17506c3fb27SDimitry Andric llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> MB = 17606c3fb27SDimitry Andric D.getVFS().getBufferForFile(MultilibPath); 17706c3fb27SDimitry Andric if (!MB) 17806c3fb27SDimitry Andric return; 17906c3fb27SDimitry Andric Multilib::flags_list Flags = TC.getMultilibFlags(Args); 18006c3fb27SDimitry Andric llvm::ErrorOr<MultilibSet> ErrorOrMultilibSet = 18106c3fb27SDimitry Andric MultilibSet::parseYaml(*MB.get()); 18206c3fb27SDimitry Andric if (ErrorOrMultilibSet.getError()) 18306c3fb27SDimitry Andric return; 18406c3fb27SDimitry Andric Result.Multilibs = ErrorOrMultilibSet.get(); 18506c3fb27SDimitry Andric if (Result.Multilibs.select(Flags, Result.SelectedMultilibs)) 18606c3fb27SDimitry Andric return; 18706c3fb27SDimitry Andric D.Diag(clang::diag::warn_drv_missing_multilib) << llvm::join(Flags, " "); 18806c3fb27SDimitry Andric std::stringstream ss; 18906c3fb27SDimitry Andric for (const Multilib &Multilib : Result.Multilibs) 19006c3fb27SDimitry Andric ss << "\n" << llvm::join(Multilib.flags(), " "); 19106c3fb27SDimitry Andric D.Diag(clang::diag::note_drv_available_multilibs) << ss.str(); 19206c3fb27SDimitry Andric } 19306c3fb27SDimitry Andric 19406c3fb27SDimitry Andric static constexpr llvm::StringLiteral MultilibFilename = "multilib.yaml"; 19506c3fb27SDimitry Andric 19606c3fb27SDimitry Andric // Get the sysroot, before multilib takes effect. 19706c3fb27SDimitry Andric static std::string computeBaseSysRoot(const Driver &D, 19806c3fb27SDimitry Andric const llvm::Triple &Triple) { 19906c3fb27SDimitry Andric if (!D.SysRoot.empty()) 20006c3fb27SDimitry Andric return D.SysRoot; 20106c3fb27SDimitry Andric 20206c3fb27SDimitry Andric SmallString<128> SysRootDir(D.Dir); 20306c3fb27SDimitry Andric llvm::sys::path::append(SysRootDir, "..", "lib", "clang-runtimes"); 20406c3fb27SDimitry Andric 20506c3fb27SDimitry Andric SmallString<128> MultilibPath(SysRootDir); 20606c3fb27SDimitry Andric llvm::sys::path::append(MultilibPath, MultilibFilename); 20706c3fb27SDimitry Andric 20806c3fb27SDimitry Andric // New behaviour: if multilib.yaml is found then use clang-runtimes as the 20906c3fb27SDimitry Andric // sysroot. 21006c3fb27SDimitry Andric if (D.getVFS().exists(MultilibPath)) 21106c3fb27SDimitry Andric return std::string(SysRootDir); 21206c3fb27SDimitry Andric 21306c3fb27SDimitry Andric // Otherwise fall back to the old behaviour of appending the target triple. 21406c3fb27SDimitry Andric llvm::sys::path::append(SysRootDir, D.getTargetTriple()); 21506c3fb27SDimitry Andric return std::string(SysRootDir); 21606c3fb27SDimitry Andric } 21706c3fb27SDimitry Andric 218e8d8bef9SDimitry Andric void BareMetal::findMultilibs(const Driver &D, const llvm::Triple &Triple, 219e8d8bef9SDimitry Andric const ArgList &Args) { 220e8d8bef9SDimitry Andric DetectedMultilibs Result; 221e8d8bef9SDimitry Andric if (isRISCVBareMetal(Triple)) { 222e8d8bef9SDimitry Andric if (findRISCVMultilibs(D, Triple, Args, Result)) { 22306c3fb27SDimitry Andric SelectedMultilibs = Result.SelectedMultilibs; 224e8d8bef9SDimitry Andric Multilibs = Result.Multilibs; 225e8d8bef9SDimitry Andric } 22606c3fb27SDimitry Andric } else { 22706c3fb27SDimitry Andric llvm::SmallString<128> MultilibPath(computeBaseSysRoot(D, Triple)); 22806c3fb27SDimitry Andric llvm::sys::path::append(MultilibPath, MultilibFilename); 22906c3fb27SDimitry Andric findMultilibsFromYAML(*this, D, MultilibPath, Args, Result); 23006c3fb27SDimitry Andric SelectedMultilibs = Result.SelectedMultilibs; 23106c3fb27SDimitry Andric Multilibs = Result.Multilibs; 232e8d8bef9SDimitry Andric } 233e8d8bef9SDimitry Andric } 234e8d8bef9SDimitry Andric 2350b57cec5SDimitry Andric bool BareMetal::handlesTarget(const llvm::Triple &Triple) { 236349cc55cSDimitry Andric return isARMBareMetal(Triple) || isAArch64BareMetal(Triple) || 23706c3fb27SDimitry Andric isRISCVBareMetal(Triple) || isPPCBareMetal(Triple); 2380b57cec5SDimitry Andric } 2390b57cec5SDimitry Andric 2400b57cec5SDimitry Andric Tool *BareMetal::buildLinker() const { 2410b57cec5SDimitry Andric return new tools::baremetal::Linker(*this); 2420b57cec5SDimitry Andric } 2430b57cec5SDimitry Andric 24406c3fb27SDimitry Andric Tool *BareMetal::buildStaticLibTool() const { 24506c3fb27SDimitry Andric return new tools::baremetal::StaticLibTool(*this); 24606c3fb27SDimitry Andric } 24706c3fb27SDimitry Andric 248e8d8bef9SDimitry Andric std::string BareMetal::computeSysRoot() const { 24906c3fb27SDimitry Andric return computeBaseSysRoot(getDriver(), getTriple()); 25006c3fb27SDimitry Andric } 251e8d8bef9SDimitry Andric 25206c3fb27SDimitry Andric BareMetal::OrderedMultilibs BareMetal::getOrderedMultilibs() const { 25306c3fb27SDimitry Andric // Get multilibs in reverse order because they're ordered most-specific last. 25406c3fb27SDimitry Andric if (!SelectedMultilibs.empty()) 25506c3fb27SDimitry Andric return llvm::reverse(SelectedMultilibs); 256e8d8bef9SDimitry Andric 25706c3fb27SDimitry Andric // No multilibs selected so return a single default multilib. 25806c3fb27SDimitry Andric static const llvm::SmallVector<Multilib> Default = {Multilib()}; 25906c3fb27SDimitry Andric return llvm::reverse(Default); 260e8d8bef9SDimitry Andric } 261e8d8bef9SDimitry Andric 2620b57cec5SDimitry Andric void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs, 2630b57cec5SDimitry Andric ArgStringList &CC1Args) const { 2640b57cec5SDimitry Andric if (DriverArgs.hasArg(options::OPT_nostdinc)) 2650b57cec5SDimitry Andric return; 2660b57cec5SDimitry Andric 2670b57cec5SDimitry Andric if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { 2680b57cec5SDimitry Andric SmallString<128> Dir(getDriver().ResourceDir); 2690b57cec5SDimitry Andric llvm::sys::path::append(Dir, "include"); 2700b57cec5SDimitry Andric addSystemInclude(DriverArgs, CC1Args, Dir.str()); 2710b57cec5SDimitry Andric } 2720b57cec5SDimitry Andric 273*0fca6ea1SDimitry Andric if (DriverArgs.hasArg(options::OPT_nostdlibinc)) 274*0fca6ea1SDimitry Andric return; 275*0fca6ea1SDimitry Andric 276*0fca6ea1SDimitry Andric if (std::optional<std::string> Path = getStdlibIncludePath()) 277*0fca6ea1SDimitry Andric addSystemInclude(DriverArgs, CC1Args, *Path); 278*0fca6ea1SDimitry Andric 27906c3fb27SDimitry Andric const SmallString<128> SysRoot(computeSysRoot()); 28006c3fb27SDimitry Andric if (!SysRoot.empty()) { 28106c3fb27SDimitry Andric for (const Multilib &M : getOrderedMultilibs()) { 28206c3fb27SDimitry Andric SmallString<128> Dir(SysRoot); 28306c3fb27SDimitry Andric llvm::sys::path::append(Dir, M.includeSuffix()); 2840b57cec5SDimitry Andric llvm::sys::path::append(Dir, "include"); 2850b57cec5SDimitry Andric addSystemInclude(DriverArgs, CC1Args, Dir.str()); 2860b57cec5SDimitry Andric } 2870b57cec5SDimitry Andric } 288e8d8bef9SDimitry Andric } 2890b57cec5SDimitry Andric 2900b57cec5SDimitry Andric void BareMetal::addClangTargetOptions(const ArgList &DriverArgs, 2910b57cec5SDimitry Andric ArgStringList &CC1Args, 2920b57cec5SDimitry Andric Action::OffloadKind) const { 2930b57cec5SDimitry Andric CC1Args.push_back("-nostdsysteminc"); 2940b57cec5SDimitry Andric } 2950b57cec5SDimitry Andric 296bdd1243dSDimitry Andric void BareMetal::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, 297bdd1243dSDimitry Andric ArgStringList &CC1Args) const { 2981db9f3b2SDimitry Andric if (DriverArgs.hasArg(options::OPT_nostdinc, options::OPT_nostdlibinc, 2991db9f3b2SDimitry Andric options::OPT_nostdincxx)) 3000b57cec5SDimitry Andric return; 3010b57cec5SDimitry Andric 302bdd1243dSDimitry Andric const Driver &D = getDriver(); 303*0fca6ea1SDimitry Andric std::string Target = getTripleString(); 304*0fca6ea1SDimitry Andric 305*0fca6ea1SDimitry Andric auto AddCXXIncludePath = [&](StringRef Path) { 306*0fca6ea1SDimitry Andric std::string Version = detectLibcxxVersion(Path); 307*0fca6ea1SDimitry Andric if (Version.empty()) 308*0fca6ea1SDimitry Andric return; 309*0fca6ea1SDimitry Andric 310*0fca6ea1SDimitry Andric { 311*0fca6ea1SDimitry Andric // First the per-target include dir: include/<target>/c++/v1. 312*0fca6ea1SDimitry Andric SmallString<128> TargetDir(Path); 313*0fca6ea1SDimitry Andric llvm::sys::path::append(TargetDir, Target, "c++", Version); 314*0fca6ea1SDimitry Andric addSystemInclude(DriverArgs, CC1Args, TargetDir); 315*0fca6ea1SDimitry Andric } 316*0fca6ea1SDimitry Andric 317*0fca6ea1SDimitry Andric { 318*0fca6ea1SDimitry Andric // Then the generic dir: include/c++/v1. 319*0fca6ea1SDimitry Andric SmallString<128> Dir(Path); 320*0fca6ea1SDimitry Andric llvm::sys::path::append(Dir, "c++", Version); 321*0fca6ea1SDimitry Andric addSystemInclude(DriverArgs, CC1Args, Dir); 322*0fca6ea1SDimitry Andric } 323*0fca6ea1SDimitry Andric }; 324*0fca6ea1SDimitry Andric 325*0fca6ea1SDimitry Andric switch (GetCXXStdlibType(DriverArgs)) { 326*0fca6ea1SDimitry Andric case ToolChain::CST_Libcxx: { 327*0fca6ea1SDimitry Andric SmallString<128> P(D.Dir); 328*0fca6ea1SDimitry Andric llvm::sys::path::append(P, "..", "include"); 329*0fca6ea1SDimitry Andric AddCXXIncludePath(P); 330*0fca6ea1SDimitry Andric break; 331*0fca6ea1SDimitry Andric } 332*0fca6ea1SDimitry Andric case ToolChain::CST_Libstdcxx: 333*0fca6ea1SDimitry Andric // We only support libc++ toolchain installation. 334*0fca6ea1SDimitry Andric break; 335*0fca6ea1SDimitry Andric } 336*0fca6ea1SDimitry Andric 337e8d8bef9SDimitry Andric std::string SysRoot(computeSysRoot()); 3380b57cec5SDimitry Andric if (SysRoot.empty()) 3390b57cec5SDimitry Andric return; 3400b57cec5SDimitry Andric 34106c3fb27SDimitry Andric for (const Multilib &M : getOrderedMultilibs()) { 34206c3fb27SDimitry Andric SmallString<128> Dir(SysRoot); 34306c3fb27SDimitry Andric llvm::sys::path::append(Dir, M.gccSuffix()); 3440b57cec5SDimitry Andric switch (GetCXXStdlibType(DriverArgs)) { 3450b57cec5SDimitry Andric case ToolChain::CST_Libcxx: { 346bdd1243dSDimitry Andric // First check sysroot/usr/include/c++/v1 if it exists. 34706c3fb27SDimitry Andric SmallString<128> TargetDir(Dir); 348bdd1243dSDimitry Andric llvm::sys::path::append(TargetDir, "usr", "include", "c++", "v1"); 349bdd1243dSDimitry Andric if (D.getVFS().exists(TargetDir)) { 350bdd1243dSDimitry Andric addSystemInclude(DriverArgs, CC1Args, TargetDir.str()); 351bdd1243dSDimitry Andric break; 352bdd1243dSDimitry Andric } 353bdd1243dSDimitry Andric // Add generic path if nothing else succeeded so far. 3540b57cec5SDimitry Andric llvm::sys::path::append(Dir, "include", "c++", "v1"); 3550b57cec5SDimitry Andric addSystemInclude(DriverArgs, CC1Args, Dir.str()); 3560b57cec5SDimitry Andric break; 3570b57cec5SDimitry Andric } 3580b57cec5SDimitry Andric case ToolChain::CST_Libstdcxx: { 3590b57cec5SDimitry Andric llvm::sys::path::append(Dir, "include", "c++"); 3600b57cec5SDimitry Andric std::error_code EC; 3610b57cec5SDimitry Andric Generic_GCC::GCCVersion Version = {"", -1, -1, -1, "", "", ""}; 3620b57cec5SDimitry Andric // Walk the subdirs, and find the one with the newest gcc version: 36306c3fb27SDimitry Andric for (llvm::vfs::directory_iterator 36406c3fb27SDimitry Andric LI = D.getVFS().dir_begin(Dir.str(), EC), 3650b57cec5SDimitry Andric LE; 3660b57cec5SDimitry Andric !EC && LI != LE; LI = LI.increment(EC)) { 3670b57cec5SDimitry Andric StringRef VersionText = llvm::sys::path::filename(LI->path()); 3680b57cec5SDimitry Andric auto CandidateVersion = Generic_GCC::GCCVersion::Parse(VersionText); 3690b57cec5SDimitry Andric if (CandidateVersion.Major == -1) 3700b57cec5SDimitry Andric continue; 3710b57cec5SDimitry Andric if (CandidateVersion <= Version) 3720b57cec5SDimitry Andric continue; 3730b57cec5SDimitry Andric Version = CandidateVersion; 3740b57cec5SDimitry Andric } 37506c3fb27SDimitry Andric if (Version.Major != -1) { 3760b57cec5SDimitry Andric llvm::sys::path::append(Dir, Version.Text); 3770b57cec5SDimitry Andric addSystemInclude(DriverArgs, CC1Args, Dir.str()); 37806c3fb27SDimitry Andric } 3790b57cec5SDimitry Andric break; 3800b57cec5SDimitry Andric } 3810b57cec5SDimitry Andric } 3820b57cec5SDimitry Andric } 38306c3fb27SDimitry Andric } 3840b57cec5SDimitry Andric 3850b57cec5SDimitry Andric void BareMetal::AddCXXStdlibLibArgs(const ArgList &Args, 3860b57cec5SDimitry Andric ArgStringList &CmdArgs) const { 3870b57cec5SDimitry Andric switch (GetCXXStdlibType(Args)) { 3880b57cec5SDimitry Andric case ToolChain::CST_Libcxx: 3890b57cec5SDimitry Andric CmdArgs.push_back("-lc++"); 390fcaf7f86SDimitry Andric if (Args.hasArg(options::OPT_fexperimental_library)) 391fcaf7f86SDimitry Andric CmdArgs.push_back("-lc++experimental"); 3920b57cec5SDimitry Andric CmdArgs.push_back("-lc++abi"); 3930b57cec5SDimitry Andric break; 3940b57cec5SDimitry Andric case ToolChain::CST_Libstdcxx: 3950b57cec5SDimitry Andric CmdArgs.push_back("-lstdc++"); 3960b57cec5SDimitry Andric CmdArgs.push_back("-lsupc++"); 3970b57cec5SDimitry Andric break; 3980b57cec5SDimitry Andric } 3990b57cec5SDimitry Andric CmdArgs.push_back("-lunwind"); 4000b57cec5SDimitry Andric } 4010b57cec5SDimitry Andric 4020b57cec5SDimitry Andric void BareMetal::AddLinkRuntimeLib(const ArgList &Args, 4030b57cec5SDimitry Andric ArgStringList &CmdArgs) const { 404e8d8bef9SDimitry Andric ToolChain::RuntimeLibType RLT = GetRuntimeLibType(Args); 405e8d8bef9SDimitry Andric switch (RLT) { 406bdd1243dSDimitry Andric case ToolChain::RLT_CompilerRT: { 407*0fca6ea1SDimitry Andric CmdArgs.push_back(getCompilerRTArgString(Args, "builtins")); 408e8d8bef9SDimitry Andric return; 409bdd1243dSDimitry Andric } 410e8d8bef9SDimitry Andric case ToolChain::RLT_Libgcc: 411e8d8bef9SDimitry Andric CmdArgs.push_back("-lgcc"); 412e8d8bef9SDimitry Andric return; 413e8d8bef9SDimitry Andric } 414e8d8bef9SDimitry Andric llvm_unreachable("Unhandled RuntimeLibType."); 4150b57cec5SDimitry Andric } 4160b57cec5SDimitry Andric 41706c3fb27SDimitry Andric void baremetal::StaticLibTool::ConstructJob(Compilation &C, const JobAction &JA, 41806c3fb27SDimitry Andric const InputInfo &Output, 41906c3fb27SDimitry Andric const InputInfoList &Inputs, 42006c3fb27SDimitry Andric const ArgList &Args, 42106c3fb27SDimitry Andric const char *LinkingOutput) const { 42206c3fb27SDimitry Andric const Driver &D = getToolChain().getDriver(); 42306c3fb27SDimitry Andric 42406c3fb27SDimitry Andric // Silence warning for "clang -g foo.o -o foo" 42506c3fb27SDimitry Andric Args.ClaimAllArgs(options::OPT_g_Group); 42606c3fb27SDimitry Andric // and "clang -emit-llvm foo.o -o foo" 42706c3fb27SDimitry Andric Args.ClaimAllArgs(options::OPT_emit_llvm); 42806c3fb27SDimitry Andric // and for "clang -w foo.o -o foo". Other warning options are already 42906c3fb27SDimitry Andric // handled somewhere else. 43006c3fb27SDimitry Andric Args.ClaimAllArgs(options::OPT_w); 43106c3fb27SDimitry Andric // Silence warnings when linking C code with a C++ '-stdlib' argument. 43206c3fb27SDimitry Andric Args.ClaimAllArgs(options::OPT_stdlib_EQ); 43306c3fb27SDimitry Andric 43406c3fb27SDimitry Andric // ar tool command "llvm-ar <options> <output_file> <input_files>". 43506c3fb27SDimitry Andric ArgStringList CmdArgs; 43606c3fb27SDimitry Andric // Create and insert file members with a deterministic index. 43706c3fb27SDimitry Andric CmdArgs.push_back("rcsD"); 43806c3fb27SDimitry Andric CmdArgs.push_back(Output.getFilename()); 43906c3fb27SDimitry Andric 44006c3fb27SDimitry Andric for (const auto &II : Inputs) { 44106c3fb27SDimitry Andric if (II.isFilename()) { 44206c3fb27SDimitry Andric CmdArgs.push_back(II.getFilename()); 44306c3fb27SDimitry Andric } 44406c3fb27SDimitry Andric } 44506c3fb27SDimitry Andric 44606c3fb27SDimitry Andric // Delete old output archive file if it already exists before generating a new 44706c3fb27SDimitry Andric // archive file. 44806c3fb27SDimitry Andric const char *OutputFileName = Output.getFilename(); 44906c3fb27SDimitry Andric if (Output.isFilename() && llvm::sys::fs::exists(OutputFileName)) { 45006c3fb27SDimitry Andric if (std::error_code EC = llvm::sys::fs::remove(OutputFileName)) { 45106c3fb27SDimitry Andric D.Diag(diag::err_drv_unable_to_remove_file) << EC.message(); 45206c3fb27SDimitry Andric return; 45306c3fb27SDimitry Andric } 45406c3fb27SDimitry Andric } 45506c3fb27SDimitry Andric 45606c3fb27SDimitry Andric const char *Exec = Args.MakeArgString(getToolChain().GetStaticLibToolPath()); 45706c3fb27SDimitry Andric C.addCommand(std::make_unique<Command>(JA, *this, 45806c3fb27SDimitry Andric ResponseFileSupport::AtFileCurCP(), 45906c3fb27SDimitry Andric Exec, CmdArgs, Inputs, Output)); 46006c3fb27SDimitry Andric } 46106c3fb27SDimitry Andric 4620b57cec5SDimitry Andric void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA, 4630b57cec5SDimitry Andric const InputInfo &Output, 4640b57cec5SDimitry Andric const InputInfoList &Inputs, 4650b57cec5SDimitry Andric const ArgList &Args, 4660b57cec5SDimitry Andric const char *LinkingOutput) const { 4670b57cec5SDimitry Andric ArgStringList CmdArgs; 4680b57cec5SDimitry Andric 4690b57cec5SDimitry Andric auto &TC = static_cast<const toolchains::BareMetal &>(getToolChain()); 470*0fca6ea1SDimitry Andric const Driver &D = getToolChain().getDriver(); 47106c3fb27SDimitry Andric const llvm::Triple::ArchType Arch = TC.getArch(); 47206c3fb27SDimitry Andric const llvm::Triple &Triple = getToolChain().getEffectiveTriple(); 4730b57cec5SDimitry Andric 4740b57cec5SDimitry Andric AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA); 4750b57cec5SDimitry Andric 4760b57cec5SDimitry Andric CmdArgs.push_back("-Bstatic"); 4770b57cec5SDimitry Andric 478*0fca6ea1SDimitry Andric if (TC.getTriple().isRISCV() && Args.hasArg(options::OPT_mno_relax)) 479*0fca6ea1SDimitry Andric CmdArgs.push_back("--no-relax"); 480*0fca6ea1SDimitry Andric 48106c3fb27SDimitry Andric if (Triple.isARM() || Triple.isThumb()) { 48206c3fb27SDimitry Andric bool IsBigEndian = arm::isARMBigEndian(Triple, Args); 48306c3fb27SDimitry Andric if (IsBigEndian) 48406c3fb27SDimitry Andric arm::appendBE8LinkFlag(Args, CmdArgs, Triple); 48506c3fb27SDimitry Andric CmdArgs.push_back(IsBigEndian ? "-EB" : "-EL"); 48606c3fb27SDimitry Andric } else if (Triple.isAArch64()) { 48706c3fb27SDimitry Andric CmdArgs.push_back(Arch == llvm::Triple::aarch64_be ? "-EB" : "-EL"); 48806c3fb27SDimitry Andric } 48906c3fb27SDimitry Andric 4905f757f3fSDimitry Andric Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, 4915f757f3fSDimitry Andric options::OPT_s, options::OPT_t, options::OPT_r}); 4920b57cec5SDimitry Andric 493fe6060f1SDimitry Andric TC.AddFilePathLibArgs(Args, CmdArgs); 494fe6060f1SDimitry Andric 495bdd1243dSDimitry Andric for (const auto &LibPath : TC.getLibraryPaths()) 496bdd1243dSDimitry Andric CmdArgs.push_back(Args.MakeArgString(llvm::Twine("-L", LibPath))); 497bdd1243dSDimitry Andric 4980b57cec5SDimitry Andric if (TC.ShouldLinkCXXStdlib(Args)) 4990b57cec5SDimitry Andric TC.AddCXXStdlibLibArgs(Args, CmdArgs); 500bdd1243dSDimitry Andric 5010b57cec5SDimitry Andric if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { 5020b57cec5SDimitry Andric CmdArgs.push_back("-lc"); 5030b57cec5SDimitry Andric CmdArgs.push_back("-lm"); 5040b57cec5SDimitry Andric 5050b57cec5SDimitry Andric TC.AddLinkRuntimeLib(Args, CmdArgs); 5060b57cec5SDimitry Andric } 5070b57cec5SDimitry Andric 508*0fca6ea1SDimitry Andric if (D.isUsingLTO()) { 509*0fca6ea1SDimitry Andric assert(!Inputs.empty() && "Must have at least one input."); 510*0fca6ea1SDimitry Andric // Find the first filename InputInfo object. 511*0fca6ea1SDimitry Andric auto Input = llvm::find_if( 512*0fca6ea1SDimitry Andric Inputs, [](const InputInfo &II) -> bool { return II.isFilename(); }); 513*0fca6ea1SDimitry Andric if (Input == Inputs.end()) 514*0fca6ea1SDimitry Andric // For a very rare case, all of the inputs to the linker are 515*0fca6ea1SDimitry Andric // InputArg. If that happens, just use the first InputInfo. 516*0fca6ea1SDimitry Andric Input = Inputs.begin(); 517*0fca6ea1SDimitry Andric 518*0fca6ea1SDimitry Andric addLTOOptions(TC, Args, CmdArgs, Output, *Input, 519*0fca6ea1SDimitry Andric D.getLTOMode() == LTOK_Thin); 520*0fca6ea1SDimitry Andric } 52106c3fb27SDimitry Andric if (TC.getTriple().isRISCV()) 52206c3fb27SDimitry Andric CmdArgs.push_back("-X"); 52306c3fb27SDimitry Andric 52406c3fb27SDimitry Andric // The R_ARM_TARGET2 relocation must be treated as R_ARM_REL32 on arm*-*-elf 52506c3fb27SDimitry Andric // and arm*-*-eabi (the default is R_ARM_GOT_PREL, used on arm*-*-linux and 52606c3fb27SDimitry Andric // arm*-*-*bsd). 52706c3fb27SDimitry Andric if (isARMBareMetal(TC.getTriple())) 52806c3fb27SDimitry Andric CmdArgs.push_back("--target2=rel"); 52906c3fb27SDimitry Andric 5300b57cec5SDimitry Andric CmdArgs.push_back("-o"); 5310b57cec5SDimitry Andric CmdArgs.push_back(Output.getFilename()); 5320b57cec5SDimitry Andric 53306c3fb27SDimitry Andric C.addCommand(std::make_unique<Command>( 53406c3fb27SDimitry Andric JA, *this, ResponseFileSupport::AtFileCurCP(), 53506c3fb27SDimitry Andric Args.MakeArgString(TC.GetLinkerPath()), CmdArgs, Inputs, Output)); 5360b57cec5SDimitry Andric } 5375f757f3fSDimitry Andric 5385f757f3fSDimitry Andric // BareMetal toolchain allows all sanitizers where the compiler generates valid 5395f757f3fSDimitry Andric // code, ignoring all runtime library support issues on the assumption that 5405f757f3fSDimitry Andric // baremetal targets typically implement their own runtime support. 5415f757f3fSDimitry Andric SanitizerMask BareMetal::getSupportedSanitizers() const { 5425f757f3fSDimitry Andric const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64; 5435f757f3fSDimitry Andric const bool IsAArch64 = getTriple().getArch() == llvm::Triple::aarch64 || 5445f757f3fSDimitry Andric getTriple().getArch() == llvm::Triple::aarch64_be; 5455f757f3fSDimitry Andric const bool IsRISCV64 = getTriple().getArch() == llvm::Triple::riscv64; 5465f757f3fSDimitry Andric SanitizerMask Res = ToolChain::getSupportedSanitizers(); 5475f757f3fSDimitry Andric Res |= SanitizerKind::Address; 5485f757f3fSDimitry Andric Res |= SanitizerKind::KernelAddress; 5495f757f3fSDimitry Andric Res |= SanitizerKind::PointerCompare; 5505f757f3fSDimitry Andric Res |= SanitizerKind::PointerSubtract; 5515f757f3fSDimitry Andric Res |= SanitizerKind::Fuzzer; 5525f757f3fSDimitry Andric Res |= SanitizerKind::FuzzerNoLink; 5535f757f3fSDimitry Andric Res |= SanitizerKind::Vptr; 5545f757f3fSDimitry Andric Res |= SanitizerKind::SafeStack; 5555f757f3fSDimitry Andric Res |= SanitizerKind::Thread; 5565f757f3fSDimitry Andric Res |= SanitizerKind::Scudo; 5575f757f3fSDimitry Andric if (IsX86_64 || IsAArch64 || IsRISCV64) { 5585f757f3fSDimitry Andric Res |= SanitizerKind::HWAddress; 5595f757f3fSDimitry Andric Res |= SanitizerKind::KernelHWAddress; 5605f757f3fSDimitry Andric } 5615f757f3fSDimitry Andric return Res; 5625f757f3fSDimitry Andric } 563