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