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
29using namespace llvm::opt;
30using namespace clang;
31using namespace clang::driver;
32using namespace clang::driver::tools;
33using namespace clang::driver::toolchains;
34
35static bool isRISCVBareMetal(const llvm::Triple &Triple) {
36 if (!Triple.isRISCV())
37 return false;
38
39 if (Triple.getVendor() != llvm::Triple::UnknownVendor)
40 return false;
41
42 if (Triple.getOS() != llvm::Triple::UnknownOS)
43 return false;
44
45 return Triple.getEnvironmentName() == "elf";
46}
47
48/// Is the triple powerpc[64][le]-*-none-eabi?
49static bool isPPCBareMetal(const llvm::Triple &Triple) {
50 return Triple.isPPC() && Triple.getOS() == llvm::Triple::UnknownOS &&
51 Triple.getEnvironment() == llvm::Triple::EABI;
52}
53
54static bool findRISCVMultilibs(const Driver &D,
55 const llvm::Triple &TargetTriple,
56 const ArgList &Args, DetectedMultilibs &Result) {
57 Multilib::flags_list Flags;
58 std::string Arch = riscv::getRISCVArch(Args, Triple: TargetTriple);
59 StringRef Abi = tools::riscv::getRISCVABI(Args, Triple: TargetTriple);
60
61 if (TargetTriple.isRISCV64()) {
62 MultilibBuilder Imac =
63 MultilibBuilder().flag(Flag: "-march=rv64imac").flag(Flag: "-mabi=lp64");
64 MultilibBuilder Imafdc = MultilibBuilder("/rv64imafdc/lp64d")
65 .flag(Flag: "-march=rv64imafdc")
66 .flag(Flag: "-mabi=lp64d");
67
68 // Multilib reuse
69 bool UseImafdc =
70 (Arch == "rv64imafdc") || (Arch == "rv64gc"); // gc => imafdc
71
72 addMultilibFlag(Enabled: (Arch == "rv64imac"), Flag: "-march=rv64imac", Flags);
73 addMultilibFlag(Enabled: UseImafdc, Flag: "-march=rv64imafdc", Flags);
74 addMultilibFlag(Enabled: Abi == "lp64", Flag: "-mabi=lp64", Flags);
75 addMultilibFlag(Enabled: Abi == "lp64d", Flag: "-mabi=lp64d", Flags);
76
77 Result.Multilibs =
78 MultilibSetBuilder().Either(M1: Imac, M2: Imafdc).makeMultilibSet();
79 return Result.Multilibs.select(D, Flags, Result.SelectedMultilibs);
80 }
81 if (TargetTriple.isRISCV32()) {
82 MultilibBuilder Imac =
83 MultilibBuilder().flag(Flag: "-march=rv32imac").flag(Flag: "-mabi=ilp32");
84 MultilibBuilder I = MultilibBuilder("/rv32i/ilp32")
85 .flag(Flag: "-march=rv32i")
86 .flag(Flag: "-mabi=ilp32");
87 MultilibBuilder Im = MultilibBuilder("/rv32im/ilp32")
88 .flag(Flag: "-march=rv32im")
89 .flag(Flag: "-mabi=ilp32");
90 MultilibBuilder Iac = MultilibBuilder("/rv32iac/ilp32")
91 .flag(Flag: "-march=rv32iac")
92 .flag(Flag: "-mabi=ilp32");
93 MultilibBuilder Imafc = MultilibBuilder("/rv32imafc/ilp32f")
94 .flag(Flag: "-march=rv32imafc")
95 .flag(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(Enabled: UseI, Flag: "-march=rv32i", Flags);
104 addMultilibFlag(Enabled: UseIm, Flag: "-march=rv32im", Flags);
105 addMultilibFlag(Enabled: (Arch == "rv32iac"), Flag: "-march=rv32iac", Flags);
106 addMultilibFlag(Enabled: (Arch == "rv32imac"), Flag: "-march=rv32imac", Flags);
107 addMultilibFlag(Enabled: UseImafc, Flag: "-march=rv32imafc", Flags);
108 addMultilibFlag(Enabled: Abi == "ilp32", Flag: "-mabi=ilp32", Flags);
109 addMultilibFlag(Enabled: Abi == "ilp32f", Flag: "-mabi=ilp32f", Flags);
110
111 Result.Multilibs =
112 MultilibSetBuilder().Either(M1: I, M2: Im, M3: Iac, M4: Imac, M5: Imafc).makeMultilibSet();
113 return Result.Multilibs.select(D, Flags, Result.SelectedMultilibs);
114 }
115 return false;
116}
117
118static std::string computeClangRuntimesSysRoot(const Driver &D,
119 bool IncludeTriple) {
120 if (!D.SysRoot.empty())
121 return D.SysRoot;
122
123 SmallString<128> SysRootDir(D.Dir);
124 llvm::sys::path::append(path&: SysRootDir, a: "..", b: "lib", c: "clang-runtimes");
125
126 if (IncludeTriple)
127 llvm::sys::path::append(path&: SysRootDir, a: 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.
135bool BareMetal::initGCCInstallation(const llvm::Triple &Triple,
136 const llvm::opt::ArgList &Args) {
137 if (Args.getLastArg(Ids: options::OPT_gcc_toolchain) ||
138 Args.getLastArg(Ids: clang::driver::options::OPT_gcc_install_dir_EQ)) {
139 GCCInstallation.init(TargetTriple: 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.
149static bool detectGCCToolchainAdjacent(const Driver &D) {
150 SmallString<128> GCCDir;
151 llvm::sys::path::append(path&: GCCDir, a: D.Dir, b: "..", c: D.getTargetTriple(),
152 d: "lib/crt0.o");
153 return llvm::sys::fs::exists(Path: 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.
165std::string BareMetal::computeSysRoot() const {
166 // Use Baremetal::sysroot if it has already been set.
167 if (!SysRoot.empty())
168 return SysRoot;
169
170 // Use the sysroot specified via the `--sysroot` command-line flag, 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(path&: inferredSysRoot, a: GCCInstallation.getParentLibPath(),
181 b: "..", c: 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(path&: inferredSysRoot, a: D.Dir, b: "..", c: D.getTargetTriple());
186 }
187 // If a valid sysroot was inferred and exists, use it
188 if (!inferredSysRoot.empty() && llvm::sys::fs::exists(Path: inferredSysRoot))
189 return std::string(inferredSysRoot);
190
191 // Use the clang-runtimes path.
192 return computeClangRuntimesSysRoot(D, /*IncludeTriple*/ true);
193}
194
195std::string BareMetal::getCompilerRTPath() const {
196 const Driver &D = getDriver();
197 if (IsGCCInstallationValid || detectGCCToolchainAdjacent(D: getDriver())) {
198 SmallString<128> Path(D.ResourceDir);
199 llvm::sys::path::append(path&: Path, a: "lib");
200 return std::string(Path.str());
201 }
202 return ToolChain::getCompilerRTPath();
203}
204
205static void addMultilibsFilePaths(const Driver &D, const MultilibSet &Multilibs,
206 const Multilib &Multilib,
207 StringRef InstallPath,
208 ToolChain::path_list &Paths) {
209 if (const auto &PathsCallback = Multilibs.filePathsCallback())
210 for (const auto &Path : PathsCallback(Multilib))
211 addPathIfExists(D, Path: 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.
218BareMetal::BareMetal(const Driver &D, const llvm::Triple &Triple,
219 const ArgList &Args)
220 : Generic_ELF(D, Triple, Args) {
221 IsGCCInstallationValid = initGCCInstallation(Triple, Args);
222 std::string ComputedSysRoot = computeSysRoot();
223 if (IsGCCInstallationValid) {
224 if (!isRISCVBareMetal(Triple))
225 D.Diag(DiagID: clang::diag::warn_drv_multilib_not_available_for_target);
226
227 Multilibs = GCCInstallation.getMultilibs();
228 SelectedMultilibs.assign(IL: {GCCInstallation.getMultilib()});
229
230 path_list &Paths = getFilePaths();
231 // Add toolchain/multilib specific file paths.
232 addMultilibsFilePaths(D, Multilibs, Multilib: SelectedMultilibs.back(),
233 InstallPath: GCCInstallation.getInstallPath(), Paths);
234 // Adding filepath for locating crt{begin,end}.o files.
235 Paths.push_back(Elt: GCCInstallation.getInstallPath().str());
236 // Adding filepath for locating crt0.o file.
237 Paths.push_back(Elt: 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(Elt: Twine(GCCInstallation.getParentLibPath() + "/../" +
243 GCCInstallation.getTriple().str() + "/bin")
244 .str());
245 PPaths.push_back(Elt: (GCCInstallation.getParentLibPath() + "/../bin").str());
246 } else {
247 getProgramPaths().push_back(Elt: 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(path&: Dir, a: M.osSuffix(), b: "lib");
254 getFilePaths().push_back(Elt: std::string(Dir));
255 getLibraryPaths().push_back(Elt: std::string(Dir));
256 }
257 }
258 }
259}
260
261static void
262findMultilibsFromYAML(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(Name: 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(DiagID: clang::diag::warn_drv_missing_multilib) << llvm::join(R&: Flags, Separator: " ");
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(R: Multilib.flags(), Separator: " ");
287 D.Diag(DiagID: 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(DiagID: 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
304static constexpr llvm::StringLiteral MultilibFilename = "multilib.yaml";
305
306static std::optional<llvm::SmallString<128>>
307getMultilibConfigPath(const Driver &D, const llvm::Triple &Triple,
308 const ArgList &Args) {
309 llvm::SmallString<128> MultilibPath;
310 if (Arg *ConfigFileArg = Args.getLastArg(Ids: options::OPT_multi_lib_config)) {
311 MultilibPath = ConfigFileArg->getValue();
312 if (!D.getVFS().exists(Path: MultilibPath)) {
313 D.Diag(DiagID: 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(path&: MultilibPath, a: MultilibFilename);
319 }
320 return MultilibPath;
321}
322
323void BareMetal::findMultilibs(const Driver &D, const llvm::Triple &Triple,
324 const ArgList &Args) {
325 DetectedMultilibs Result;
326 // Look for a multilib.yaml before trying target-specific hardwired logic.
327 // If it exists, always do what it specifies.
328 std::optional<llvm::SmallString<128>> MultilibPath =
329 getMultilibConfigPath(D, Triple, Args);
330 if (!MultilibPath)
331 return;
332 if (D.getVFS().exists(Path: *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(TC: *this, D, MultilibPath: *MultilibPath, Args, Result,
338 CustomFlagsMacroDefines&: CustomFlagMacroDefines);
339 SelectedMultilibs = Result.SelectedMultilibs;
340 Multilibs = Result.Multilibs;
341 MultilibMacroDefines.append(in_start: CustomFlagMacroDefines.begin(),
342 in_end: CustomFlagMacroDefines.end());
343 } else if (isRISCVBareMetal(Triple) && !detectGCCToolchainAdjacent(D)) {
344 if (findRISCVMultilibs(D, TargetTriple: Triple, Args, Result)) {
345 SelectedMultilibs = Result.SelectedMultilibs;
346 Multilibs = Result.Multilibs;
347 }
348 }
349}
350
351bool BareMetal::handlesTarget(const llvm::Triple &Triple) {
352 return arm::isARMEABIBareMetal(Triple) ||
353 aarch64::isAArch64BareMetal(Triple) || isRISCVBareMetal(Triple) ||
354 isPPCBareMetal(Triple);
355}
356
357Tool *BareMetal::buildLinker() const {
358 return new tools::baremetal::Linker(*this);
359}
360
361Tool *BareMetal::buildStaticLibTool() const {
362 return new tools::baremetal::StaticLibTool(*this);
363}
364
365BareMetal::OrderedMultilibs BareMetal::getOrderedMultilibs() const {
366 // Get multilibs in reverse order because they're ordered most-specific last.
367 if (!SelectedMultilibs.empty())
368 return llvm::reverse(C: SelectedMultilibs);
369
370 // No multilibs selected so return a single default multilib.
371 static const llvm::SmallVector<Multilib> Default = {Multilib()};
372 return llvm::reverse(C: Default);
373}
374
375ToolChain::CXXStdlibType BareMetal::GetDefaultCXXStdlibType() const {
376 if (getTriple().isRISCV() && IsGCCInstallationValid)
377 return ToolChain::CST_Libstdcxx;
378 return ToolChain::CST_Libcxx;
379}
380
381ToolChain::RuntimeLibType BareMetal::GetDefaultRuntimeLibType() const {
382 if (getTriple().isRISCV() && IsGCCInstallationValid)
383 return ToolChain::RLT_Libgcc;
384 return ToolChain::RLT_CompilerRT;
385}
386
387// TODO: Add a validity check for GCCInstallation.
388// If valid, use `UNW_Libgcc`; otherwise, use `UNW_None`.
389ToolChain::UnwindLibType
390BareMetal::GetUnwindLibType(const llvm::opt::ArgList &Args) const {
391 if (getTriple().isRISCV())
392 return ToolChain::UNW_None;
393
394 return ToolChain::GetUnwindLibType(Args);
395}
396
397void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
398 ArgStringList &CC1Args) const {
399 if (DriverArgs.hasArg(Ids: options::OPT_nostdinc))
400 return;
401
402 if (!DriverArgs.hasArg(Ids: options::OPT_nobuiltininc)) {
403 SmallString<128> Dir(getDriver().ResourceDir);
404 llvm::sys::path::append(path&: Dir, a: "include");
405 addSystemInclude(DriverArgs, CC1Args, Path: Dir.str());
406 }
407
408 if (DriverArgs.hasArg(Ids: options::OPT_nostdlibinc))
409 return;
410
411 if (std::optional<std::string> Path = getStdlibIncludePath())
412 addSystemInclude(DriverArgs, CC1Args, Path: *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(path&: Dir, a: M.includeSuffix());
419 llvm::sys::path::append(path&: Dir, a: "include");
420 addSystemInclude(DriverArgs, CC1Args, Path: Dir.str());
421 }
422 }
423}
424
425void BareMetal::addClangTargetOptions(const ArgList &DriverArgs,
426 ArgStringList &CC1Args,
427 Action::OffloadKind) const {
428 CC1Args.push_back(Elt: "-nostdsysteminc");
429}
430
431void BareMetal::addLibStdCxxIncludePaths(
432 const llvm::opt::ArgList &DriverArgs,
433 llvm::opt::ArgStringList &CC1Args) const {
434 if (!IsGCCInstallationValid)
435 return;
436 const GCCVersion &Version = GCCInstallation.getVersion();
437 StringRef TripleStr = GCCInstallation.getTriple().str();
438 const Multilib &Multilib = GCCInstallation.getMultilib();
439 addLibStdCXXIncludePaths(IncludeDir: computeSysRoot() + "/include/c++/" + Version.Text,
440 Triple: TripleStr, IncludeSuffix: Multilib.includeSuffix(), DriverArgs,
441 CC1Args);
442}
443
444void BareMetal::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
445 ArgStringList &CC1Args) const {
446 if (DriverArgs.hasArg(Ids: options::OPT_nostdinc, Ids: options::OPT_nostdlibinc,
447 Ids: 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(IncludePath: 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(path&: TargetDir, a: Target, b: "c++", c: Version);
462 addSystemInclude(DriverArgs, CC1Args, Path: TargetDir);
463 }
464
465 {
466 // Then the generic dir: include/c++/v1.
467 SmallString<128> Dir(Path);
468 llvm::sys::path::append(path&: Dir, a: "c++", b: Version);
469 addSystemInclude(DriverArgs, CC1Args, Path: Dir);
470 }
471 };
472
473 switch (GetCXXStdlibType(Args: DriverArgs)) {
474 case ToolChain::CST_Libcxx: {
475 SmallString<128> P(D.Dir);
476 llvm::sys::path::append(path&: P, a: "..", b: "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(path&: Dir, a: M.gccSuffix());
492 switch (GetCXXStdlibType(Args: 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(path&: TargetDir, a: "usr", b: "include", c: "c++", d: "v1");
497 if (D.getVFS().exists(Path: TargetDir)) {
498 addSystemInclude(DriverArgs, CC1Args, Path: TargetDir.str());
499 break;
500 }
501 // Add generic path if nothing else succeeded so far.
502 llvm::sys::path::append(path&: Dir, a: "include", b: "c++", c: "v1");
503 addSystemInclude(DriverArgs, CC1Args, Path: Dir.str());
504 break;
505 }
506 case ToolChain::CST_Libstdcxx: {
507 llvm::sys::path::append(path&: Dir, a: "include", b: "c++");
508 std::error_code EC;
509 Generic_GCC::GCCVersion Version = {.Text: "", .Major: -1, .Minor: -1, .Patch: -1, .MajorStr: "", .MinorStr: "", .PatchSuffix: ""};
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: Dir.str(), EC),
513 LE;
514 !EC && LI != LE; LI = LI.increment(EC)) {
515 StringRef VersionText = llvm::sys::path::filename(path: 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(path&: Dir, a: Version.Text);
525 addSystemInclude(DriverArgs, CC1Args, Path: Dir.str());
526 }
527 break;
528 }
529 }
530 }
531}
532
533void baremetal::StaticLibTool::ConstructJob(Compilation &C, const JobAction &JA,
534 const InputInfo &Output,
535 const InputInfoList &Inputs,
536 const ArgList &Args,
537 const char *LinkingOutput) const {
538 const Driver &D = getToolChain().getDriver();
539
540 // Silence warning for "clang -g foo.o -o foo"
541 Args.ClaimAllArgs(Id0: options::OPT_g_Group);
542 // and "clang -emit-llvm foo.o -o foo"
543 Args.ClaimAllArgs(Id0: 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(Id0: options::OPT_w);
547 // Silence warnings when linking C code with a C++ '-stdlib' argument.
548 Args.ClaimAllArgs(Id0: 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(Elt: "rcsD");
554 CmdArgs.push_back(Elt: Output.getFilename());
555
556 for (const auto &II : Inputs) {
557 if (II.isFilename()) {
558 CmdArgs.push_back(Elt: 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(Path: OutputFileName)) {
566 if (std::error_code EC = llvm::sys::fs::remove(path: OutputFileName)) {
567 D.Diag(DiagID: diag::err_drv_unable_to_remove_file) << EC.message();
568 return;
569 }
570 }
571
572 const char *Exec = Args.MakeArgString(Str: getToolChain().GetStaticLibToolPath());
573 C.addCommand(C: std::make_unique<Command>(args: JA, args: *this,
574 args: ResponseFileSupport::AtFileCurCP(),
575 args&: Exec, args&: CmdArgs, args: Inputs, args: Output));
576}
577
578void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA,
579 const InputInfo &Output,
580 const InputInfoList &Inputs,
581 const ArgList &Args,
582 const char *LinkingOutput) const {
583 ArgStringList CmdArgs;
584
585 auto &TC = static_cast<const toolchains::BareMetal &>(getToolChain());
586 const Driver &D = getToolChain().getDriver();
587 const llvm::Triple::ArchType Arch = TC.getArch();
588 const llvm::Triple &Triple = getToolChain().getEffectiveTriple();
589
590 if (!D.SysRoot.empty())
591 CmdArgs.push_back(Elt: Args.MakeArgString(Str: "--sysroot=" + D.SysRoot));
592
593 CmdArgs.push_back(Elt: "-Bstatic");
594
595 if (const char *LDMOption = getLDMOption(T: TC.getTriple(), Args)) {
596 CmdArgs.push_back(Elt: "-m");
597 CmdArgs.push_back(Elt: LDMOption);
598 } else {
599 D.Diag(DiagID: diag::err_target_unknown_triple) << Triple.str();
600 return;
601 }
602
603 if (Triple.isRISCV()) {
604 CmdArgs.push_back(Elt: "-X");
605 if (Args.hasArg(Ids: options::OPT_mno_relax))
606 CmdArgs.push_back(Elt: "--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(Elt: IsBigEndian ? "-EB" : "-EL");
614 } else if (Triple.isAArch64()) {
615 CmdArgs.push_back(Elt: Arch == llvm::Triple::aarch64_be ? "-EB" : "-EL");
616 }
617
618 bool NeedCRTs =
619 !Args.hasArg(Ids: options::OPT_nostdlib, Ids: options::OPT_nostartfiles);
620
621 const char *CRTBegin, *CRTEnd;
622 if (NeedCRTs) {
623 if (!Args.hasArg(Ids: options::OPT_r))
624 CmdArgs.push_back(Elt: Args.MakeArgString(Str: TC.GetFilePath(Name: "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, Component: "crtbegin", Type: ToolChain::FT_Object);
636 CRTEnd =
637 TC.getCompilerRTArgString(Args, Component: "crtend", Type: ToolChain::FT_Object);
638 break;
639 }
640 }
641 CmdArgs.push_back(Elt: Args.MakeArgString(Str: TC.GetFilePath(Name: CRTBegin)));
642 }
643 }
644
645 Args.addAllArgs(Output&: CmdArgs,
646 Ids: {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(Elt: Args.MakeArgString(Str: llvm::Twine("-L", LibPath)));
653
654 if (D.isUsingLTO())
655 addLTOOptions(ToolChain: TC, Args, CmdArgs, Output, Inputs,
656 IsThinLTO: D.getLTOMode() == LTOK_Thin);
657
658 AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
659
660 if (TC.ShouldLinkCXXStdlib(Args)) {
661 bool OnlyLibstdcxxStatic = Args.hasArg(Ids: options::OPT_static_libstdcxx) &&
662 !Args.hasArg(Ids: options::OPT_static);
663 if (OnlyLibstdcxxStatic)
664 CmdArgs.push_back(Elt: "-Bstatic");
665 TC.AddCXXStdlibLibArgs(Args, CmdArgs);
666 if (OnlyLibstdcxxStatic)
667 CmdArgs.push_back(Elt: "-Bdynamic");
668 CmdArgs.push_back(Elt: "-lm");
669 }
670
671 if (!Args.hasArg(Ids: options::OPT_nostdlib, Ids: options::OPT_nodefaultlibs)) {
672 CmdArgs.push_back(Elt: "--start-group");
673 AddRunTimeLibs(TC, D, CmdArgs, Args);
674 CmdArgs.push_back(Elt: "-lc");
675 if (TC.hasValidGCCInstallation() || detectGCCToolchainAdjacent(D))
676 CmdArgs.push_back(Elt: "-lgloss");
677 CmdArgs.push_back(Elt: "--end-group");
678 }
679
680 if ((TC.hasValidGCCInstallation() || detectGCCToolchainAdjacent(D)) &&
681 NeedCRTs)
682 CmdArgs.push_back(Elt: Args.MakeArgString(Str: TC.GetFilePath(Name: 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(Triple: TC.getTriple()))
688 CmdArgs.push_back(Elt: "--target2=rel");
689
690 CmdArgs.push_back(Elt: "-o");
691 CmdArgs.push_back(Elt: Output.getFilename());
692
693 C.addCommand(C: std::make_unique<Command>(
694 args: JA, args: *this, args: ResponseFileSupport::AtFileCurCP(),
695 args: Args.MakeArgString(Str: TC.GetLinkerPath()), args&: CmdArgs, args: Inputs, args: 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.
701SanitizerMask 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
724SmallVector<std::string>
725BareMetal::getMultilibMacroDefinesStr(llvm::opt::ArgList &Args) const {
726 return MultilibMacroDefines;
727}
728

source code of clang/lib/Driver/ToolChains/BareMetal.cpp