xref: /freebsd/contrib/llvm-project/clang/lib/Driver/ToolChains/BareMetal.cpp (revision e64bea71c21eb42e97aa615188ba91f6cce0d36d)
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-exception
6 //
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/Driver/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 
29 using namespace llvm::opt;
30 using namespace clang;
31 using namespace clang::driver;
32 using namespace clang::driver::tools;
33 using namespace clang::driver::toolchains;
34 
isRISCVBareMetal(const llvm::Triple & Triple)35 static 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?
isPPCBareMetal(const llvm::Triple & Triple)49 static bool isPPCBareMetal(const llvm::Triple &Triple) {
50   return Triple.isPPC() && Triple.getOS() == llvm::Triple::UnknownOS &&
51          Triple.getEnvironment() == llvm::Triple::EABI;
52 }
53 
findRISCVMultilibs(const Driver & D,const llvm::Triple & TargetTriple,const ArgList & Args,DetectedMultilibs & Result)54 static 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 reuse
69     bool UseImafdc =
70         (Arch == "rv64imafdc") || (Arch == "rv64gc"); // gc => imafdc
71 
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 reuse
98     bool UseI = (Arch == "rv32i") || (Arch == "rv32ic");    // ic => i
99     bool UseIm = (Arch == "rv32im") || (Arch == "rv32imc"); // imc => im
100     bool UseImafc = (Arch == "rv32imafc") || (Arch == "rv32imafdc") ||
101                     (Arch == "rv32gc"); // imafdc,gc => imafc
102 
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 
computeClangRuntimesSysRoot(const Driver & D,bool IncludeTriple)118 static 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 the
133 // `--gcc-toolchain` and `--gcc-install-dir` flags. The function below returns
134 // whether the GCC toolchain was initialized successfully.
initGCCInstallation(const llvm::Triple & Triple,const llvm::opt::ArgList & Args)135 bool BareMetal::initGCCInstallation(const llvm::Triple &Triple,
136                                     const llvm::opt::ArgList &Args) {
137   if (Args.getLastArg(options::OPT_gcc_toolchain) ||
138       Args.getLastArg(clang::driver::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 effort
146 // to merge RISCVToolChain into the Baremetal toolchain. It infers the presence
147 // of a valid GCC toolchain by checking whether the `crt0.o` file exists in the
148 // `bin/../<target-triple>/lib` directory.
detectGCCToolchainAdjacent(const Driver & D)149 static 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 the
157 // values of `--gcc-install-dir` or `--gcc-toolchain`, which specify the
158 // 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.
computeSysRoot() const165 std::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, if
171   // 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 triple
184     // 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 it
188   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 
getCompilerRTPath() const195 std::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 
addMultilibsFilePaths(const Driver & D,const MultilibSet & Multilibs,const Multilib & Multilib,StringRef InstallPath,ToolChain::path_list & Paths)205 static 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 multlib
215 // structure encoded into GCCInstallation. Baremetal toolchain supports ARM,
216 // AArch64, RISCV and PPC and of these only RISCV have GCC multilibs hardcoded
217 // in GCCInstallation.
BareMetal(const Driver & D,const llvm::Triple & Triple,const ArgList & Args)218 BareMetal::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-prefixed
241     // 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 
261 static void
findMultilibsFromYAML(const ToolChain & TC,const Driver & D,StringRef MultilibPath,const ArgList & Args,DetectedMultilibs & Result,SmallVector<StringRef> & CustomFlagsMacroDefines)262 findMultilibsFromYAML(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 list
283   // 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 do
290   // this after displaying the list of available multilibs, because
291   // that list is probably large, and (in interactive use) risks
292   // scrolling the useful error message off the top of the user's
293   // 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, in
300   // case it contains partial data.
301   Result.SelectedMultilibs.clear();
302 }
303 
304 static constexpr llvm::StringLiteral MultilibFilename = "multilib.yaml";
305 
306 static std::optional<llvm::SmallString<128>>
getMultilibConfigPath(const Driver & D,const llvm::Triple & Triple,const ArgList & Args)307 getMultilibConfigPath(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 
findMultilibs(const Driver & D,const llvm::Triple & Triple,const ArgList & Args)323 void 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 target
334     // specific suffix
335     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 
handlesTarget(const llvm::Triple & Triple)351 bool BareMetal::handlesTarget(const llvm::Triple &Triple) {
352   return arm::isARMEABIBareMetal(Triple) ||
353          aarch64::isAArch64BareMetal(Triple) || isRISCVBareMetal(Triple) ||
354          isPPCBareMetal(Triple);
355 }
356 
buildLinker() const357 Tool *BareMetal::buildLinker() const {
358   return new tools::baremetal::Linker(*this);
359 }
360 
buildStaticLibTool() const361 Tool *BareMetal::buildStaticLibTool() const {
362   return new tools::baremetal::StaticLibTool(*this);
363 }
364 
getOrderedMultilibs() const365 BareMetal::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 
GetDefaultCXXStdlibType() const375 ToolChain::CXXStdlibType BareMetal::GetDefaultCXXStdlibType() const {
376   if (getTriple().isRISCV() && IsGCCInstallationValid)
377     return ToolChain::CST_Libstdcxx;
378   return ToolChain::CST_Libcxx;
379 }
380 
GetDefaultRuntimeLibType() const381 ToolChain::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`.
389 ToolChain::UnwindLibType
GetUnwindLibType(const llvm::opt::ArgList & Args) const390 BareMetal::GetUnwindLibType(const llvm::opt::ArgList &Args) const {
391   if (getTriple().isRISCV())
392     return ToolChain::UNW_None;
393 
394   return ToolChain::GetUnwindLibType(Args);
395 }
396 
AddClangSystemIncludeArgs(const ArgList & DriverArgs,ArgStringList & CC1Args) const397 void 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 
addClangTargetOptions(const ArgList & DriverArgs,ArgStringList & CC1Args,Action::OffloadKind) const425 void BareMetal::addClangTargetOptions(const ArgList &DriverArgs,
426                                       ArgStringList &CC1Args,
427                                       Action::OffloadKind) const {
428   CC1Args.push_back("-nostdsysteminc");
429 }
430 
addLibStdCxxIncludePaths(const llvm::opt::ArgList & DriverArgs,llvm::opt::ArgStringList & CC1Args) const431 void 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 
AddClangCXXStdlibIncludeArgs(const ArgList & DriverArgs,ArgStringList & CC1Args) const444 void 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_iterator
512                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 
ConstructJob(Compilation & C,const JobAction & JA,const InputInfo & Output,const InputInfoList & Inputs,const ArgList & Args,const char * LinkingOutput) const533 void 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 already
545   // 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 new
563   // 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 
ConstructJob(Compilation & C,const JobAction & JA,const InputInfo & Output,const InputInfoList & Inputs,const ArgList & Args,const char * LinkingOutput) const578 void 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 
590   if (!D.SysRoot.empty())
591     CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
592 
593   CmdArgs.push_back("-Bstatic");
594 
595   if (const char *LDMOption = getLDMOption(TC.getTriple(), Args)) {
596     CmdArgs.push_back("-m");
597     CmdArgs.push_back(LDMOption);
598   } else {
599     D.Diag(diag::err_target_unknown_triple) << Triple.str();
600     return;
601   }
602 
603   if (Triple.isRISCV()) {
604     CmdArgs.push_back("-X");
605     if (Args.hasArg(options::OPT_mno_relax))
606       CmdArgs.push_back("--no-relax");
607   }
608 
609   if (Triple.isARM() || Triple.isThumb()) {
610     bool IsBigEndian = arm::isARMBigEndian(Triple, Args);
611     if (IsBigEndian)
612       arm::appendBE8LinkFlag(Args, CmdArgs, Triple);
613     CmdArgs.push_back(IsBigEndian ? "-EB" : "-EL");
614   } else if (Triple.isAArch64()) {
615     CmdArgs.push_back(Arch == llvm::Triple::aarch64_be ? "-EB" : "-EL");
616   }
617 
618   bool NeedCRTs =
619       !Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles);
620 
621   const char *CRTBegin, *CRTEnd;
622   if (NeedCRTs) {
623     if (!Args.hasArg(options::OPT_r))
624       CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crt0.o")));
625     if (TC.hasValidGCCInstallation() || detectGCCToolchainAdjacent(D)) {
626       auto RuntimeLib = TC.GetRuntimeLibType(Args);
627       switch (RuntimeLib) {
628       case (ToolChain::RLT_Libgcc): {
629         CRTBegin = "crtbegin.o";
630         CRTEnd = "crtend.o";
631         break;
632       }
633       case (ToolChain::RLT_CompilerRT): {
634         CRTBegin =
635             TC.getCompilerRTArgString(Args, "crtbegin", ToolChain::FT_Object);
636         CRTEnd =
637             TC.getCompilerRTArgString(Args, "crtend", ToolChain::FT_Object);
638         break;
639       }
640       }
641       CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath(CRTBegin)));
642     }
643   }
644 
645   Args.addAllArgs(CmdArgs,
646                   {options::OPT_L, options::OPT_u, options::OPT_T_Group,
647                    options::OPT_s, options::OPT_t, options::OPT_r});
648 
649   TC.AddFilePathLibArgs(Args, CmdArgs);
650 
651   for (const auto &LibPath : TC.getLibraryPaths())
652     CmdArgs.push_back(Args.MakeArgString(llvm::Twine("-L", LibPath)));
653 
654   if (D.isUsingLTO())
655     addLTOOptions(TC, Args, CmdArgs, Output, Inputs,
656                   D.getLTOMode() == LTOK_Thin);
657 
658   AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
659 
660   if (TC.ShouldLinkCXXStdlib(Args)) {
661     bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) &&
662                                !Args.hasArg(options::OPT_static);
663     if (OnlyLibstdcxxStatic)
664       CmdArgs.push_back("-Bstatic");
665     TC.AddCXXStdlibLibArgs(Args, CmdArgs);
666     if (OnlyLibstdcxxStatic)
667       CmdArgs.push_back("-Bdynamic");
668     CmdArgs.push_back("-lm");
669   }
670 
671   if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
672     CmdArgs.push_back("--start-group");
673     AddRunTimeLibs(TC, D, CmdArgs, Args);
674     CmdArgs.push_back("-lc");
675     if (TC.hasValidGCCInstallation() || detectGCCToolchainAdjacent(D))
676       CmdArgs.push_back("-lgloss");
677     CmdArgs.push_back("--end-group");
678   }
679 
680   if ((TC.hasValidGCCInstallation() || detectGCCToolchainAdjacent(D)) &&
681       NeedCRTs)
682     CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath(CRTEnd)));
683 
684   // The R_ARM_TARGET2 relocation must be treated as R_ARM_REL32 on arm*-*-elf
685   // and arm*-*-eabi (the default is R_ARM_GOT_PREL, used on arm*-*-linux and
686   // arm*-*-*bsd).
687   if (arm::isARMEABIBareMetal(TC.getTriple()))
688     CmdArgs.push_back("--target2=rel");
689 
690   CmdArgs.push_back("-o");
691   CmdArgs.push_back(Output.getFilename());
692 
693   C.addCommand(std::make_unique<Command>(
694       JA, *this, ResponseFileSupport::AtFileCurCP(),
695       Args.MakeArgString(TC.GetLinkerPath()), CmdArgs, Inputs, Output));
696 }
697 
698 // BareMetal toolchain allows all sanitizers where the compiler generates valid
699 // code, ignoring all runtime library support issues on the assumption that
700 // baremetal targets typically implement their own runtime support.
getSupportedSanitizers() const701 SanitizerMask BareMetal::getSupportedSanitizers() const {
702   const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64;
703   const bool IsAArch64 = getTriple().getArch() == llvm::Triple::aarch64 ||
704                          getTriple().getArch() == llvm::Triple::aarch64_be;
705   const bool IsRISCV64 = getTriple().getArch() == llvm::Triple::riscv64;
706   SanitizerMask Res = ToolChain::getSupportedSanitizers();
707   Res |= SanitizerKind::Address;
708   Res |= SanitizerKind::KernelAddress;
709   Res |= SanitizerKind::PointerCompare;
710   Res |= SanitizerKind::PointerSubtract;
711   Res |= SanitizerKind::Fuzzer;
712   Res |= SanitizerKind::FuzzerNoLink;
713   Res |= SanitizerKind::Vptr;
714   Res |= SanitizerKind::SafeStack;
715   Res |= SanitizerKind::Thread;
716   Res |= SanitizerKind::Scudo;
717   if (IsX86_64 || IsAArch64 || IsRISCV64) {
718     Res |= SanitizerKind::HWAddress;
719     Res |= SanitizerKind::KernelHWAddress;
720   }
721   return Res;
722 }
723 
724 SmallVector<std::string>
getMultilibMacroDefinesStr(llvm::opt::ArgList & Args) const725 BareMetal::getMultilibMacroDefinesStr(llvm::opt::ArgList &Args) const {
726   return MultilibMacroDefines;
727 }
728