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 "CommonArgs.h"
12#include "Gnu.h"
13#include "clang/Driver/InputInfo.h"
14
15#include "Arch/ARM.h"
16#include "Arch/RISCV.h"
17#include "clang/Driver/Compilation.h"
18#include "clang/Driver/Driver.h"
19#include "clang/Driver/DriverDiagnostic.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#include "llvm/Support/raw_ostream.h"
27
28#include <sstream>
29
30using namespace llvm::opt;
31using namespace clang;
32using namespace clang::driver;
33using namespace clang::driver::tools;
34using namespace clang::driver::toolchains;
35
36static bool findRISCVMultilibs(const Driver &D,
37 const llvm::Triple &TargetTriple,
38 const ArgList &Args, DetectedMultilibs &Result) {
39 Multilib::flags_list Flags;
40 std::string Arch = riscv::getRISCVArch(Args, Triple: TargetTriple);
41 StringRef Abi = tools::riscv::getRISCVABI(Args, Triple: TargetTriple);
42
43 if (TargetTriple.isRISCV64()) {
44 MultilibBuilder Imac =
45 MultilibBuilder().flag(Flag: "-march=rv64imac").flag(Flag: "-mabi=lp64");
46 MultilibBuilder Imafdc = MultilibBuilder("/rv64imafdc/lp64d")
47 .flag(Flag: "-march=rv64imafdc")
48 .flag(Flag: "-mabi=lp64d");
49
50 // Multilib reuse
51 bool UseImafdc =
52 (Arch == "rv64imafdc") || (Arch == "rv64gc"); // gc => imafdc
53
54 addMultilibFlag(Enabled: (Arch == "rv64imac"), Flag: "-march=rv64imac", Flags);
55 addMultilibFlag(Enabled: UseImafdc, Flag: "-march=rv64imafdc", Flags);
56 addMultilibFlag(Enabled: Abi == "lp64", Flag: "-mabi=lp64", Flags);
57 addMultilibFlag(Enabled: Abi == "lp64d", Flag: "-mabi=lp64d", Flags);
58
59 Result.Multilibs =
60 MultilibSetBuilder().Either(M1: Imac, M2: Imafdc).makeMultilibSet();
61 return Result.Multilibs.select(Flags, Result.SelectedMultilibs);
62 }
63 if (TargetTriple.isRISCV32()) {
64 MultilibBuilder Imac =
65 MultilibBuilder().flag(Flag: "-march=rv32imac").flag(Flag: "-mabi=ilp32");
66 MultilibBuilder I = MultilibBuilder("/rv32i/ilp32")
67 .flag(Flag: "-march=rv32i")
68 .flag(Flag: "-mabi=ilp32");
69 MultilibBuilder Im = MultilibBuilder("/rv32im/ilp32")
70 .flag(Flag: "-march=rv32im")
71 .flag(Flag: "-mabi=ilp32");
72 MultilibBuilder Iac = MultilibBuilder("/rv32iac/ilp32")
73 .flag(Flag: "-march=rv32iac")
74 .flag(Flag: "-mabi=ilp32");
75 MultilibBuilder Imafc = MultilibBuilder("/rv32imafc/ilp32f")
76 .flag(Flag: "-march=rv32imafc")
77 .flag(Flag: "-mabi=ilp32f");
78
79 // Multilib reuse
80 bool UseI = (Arch == "rv32i") || (Arch == "rv32ic"); // ic => i
81 bool UseIm = (Arch == "rv32im") || (Arch == "rv32imc"); // imc => im
82 bool UseImafc = (Arch == "rv32imafc") || (Arch == "rv32imafdc") ||
83 (Arch == "rv32gc"); // imafdc,gc => imafc
84
85 addMultilibFlag(Enabled: UseI, Flag: "-march=rv32i", Flags);
86 addMultilibFlag(Enabled: UseIm, Flag: "-march=rv32im", Flags);
87 addMultilibFlag(Enabled: (Arch == "rv32iac"), Flag: "-march=rv32iac", Flags);
88 addMultilibFlag(Enabled: (Arch == "rv32imac"), Flag: "-march=rv32imac", Flags);
89 addMultilibFlag(Enabled: UseImafc, Flag: "-march=rv32imafc", Flags);
90 addMultilibFlag(Enabled: Abi == "ilp32", Flag: "-mabi=ilp32", Flags);
91 addMultilibFlag(Enabled: Abi == "ilp32f", Flag: "-mabi=ilp32f", Flags);
92
93 Result.Multilibs =
94 MultilibSetBuilder().Either(M1: I, M2: Im, M3: Iac, M4: Imac, M5: Imafc).makeMultilibSet();
95 return Result.Multilibs.select(Flags, Result.SelectedMultilibs);
96 }
97 return false;
98}
99
100BareMetal::BareMetal(const Driver &D, const llvm::Triple &Triple,
101 const ArgList &Args)
102 : ToolChain(D, Triple, Args) {
103 getProgramPaths().push_back(Elt: getDriver().Dir);
104
105 findMultilibs(D, Triple, Args);
106 SmallString<128> SysRoot(computeSysRoot());
107 if (!SysRoot.empty()) {
108 for (const Multilib &M : getOrderedMultilibs()) {
109 SmallString<128> Dir(SysRoot);
110 llvm::sys::path::append(path&: Dir, a: M.osSuffix(), b: "lib");
111 getFilePaths().push_back(Elt: std::string(Dir));
112 getLibraryPaths().push_back(Elt: std::string(Dir));
113 }
114 }
115}
116
117/// Is the triple {arm,armeb,thumb,thumbeb}-none-none-{eabi,eabihf} ?
118static bool isARMBareMetal(const llvm::Triple &Triple) {
119 if (Triple.getArch() != llvm::Triple::arm &&
120 Triple.getArch() != llvm::Triple::thumb &&
121 Triple.getArch() != llvm::Triple::armeb &&
122 Triple.getArch() != llvm::Triple::thumbeb)
123 return false;
124
125 if (Triple.getVendor() != llvm::Triple::UnknownVendor)
126 return false;
127
128 if (Triple.getOS() != llvm::Triple::UnknownOS)
129 return false;
130
131 if (Triple.getEnvironment() != llvm::Triple::EABI &&
132 Triple.getEnvironment() != llvm::Triple::EABIHF)
133 return false;
134
135 return true;
136}
137
138/// Is the triple {aarch64.aarch64_be}-none-elf?
139static bool isAArch64BareMetal(const llvm::Triple &Triple) {
140 if (Triple.getArch() != llvm::Triple::aarch64 &&
141 Triple.getArch() != llvm::Triple::aarch64_be)
142 return false;
143
144 if (Triple.getVendor() != llvm::Triple::UnknownVendor)
145 return false;
146
147 if (Triple.getOS() != llvm::Triple::UnknownOS)
148 return false;
149
150 return Triple.getEnvironmentName() == "elf";
151}
152
153static bool isRISCVBareMetal(const llvm::Triple &Triple) {
154 if (!Triple.isRISCV())
155 return false;
156
157 if (Triple.getVendor() != llvm::Triple::UnknownVendor)
158 return false;
159
160 if (Triple.getOS() != llvm::Triple::UnknownOS)
161 return false;
162
163 return Triple.getEnvironmentName() == "elf";
164}
165
166/// Is the triple powerpc[64][le]-*-none-eabi?
167static bool isPPCBareMetal(const llvm::Triple &Triple) {
168 return Triple.isPPC() && Triple.getOS() == llvm::Triple::UnknownOS &&
169 Triple.getEnvironment() == llvm::Triple::EABI;
170}
171
172static void findMultilibsFromYAML(const ToolChain &TC, const Driver &D,
173 StringRef MultilibPath, const ArgList &Args,
174 DetectedMultilibs &Result) {
175 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> MB =
176 D.getVFS().getBufferForFile(Name: MultilibPath);
177 if (!MB)
178 return;
179 Multilib::flags_list Flags = TC.getMultilibFlags(Args);
180 llvm::ErrorOr<MultilibSet> ErrorOrMultilibSet =
181 MultilibSet::parseYaml(*MB.get());
182 if (ErrorOrMultilibSet.getError())
183 return;
184 Result.Multilibs = ErrorOrMultilibSet.get();
185 if (Result.Multilibs.select(Flags, Result.SelectedMultilibs))
186 return;
187 D.Diag(DiagID: clang::diag::warn_drv_missing_multilib) << llvm::join(R&: Flags, Separator: " ");
188 std::stringstream ss;
189 for (const Multilib &Multilib : Result.Multilibs)
190 ss << "\n" << llvm::join(R: Multilib.flags(), Separator: " ");
191 D.Diag(DiagID: clang::diag::note_drv_available_multilibs) << ss.str();
192}
193
194static constexpr llvm::StringLiteral MultilibFilename = "multilib.yaml";
195
196// Get the sysroot, before multilib takes effect.
197static std::string computeBaseSysRoot(const Driver &D,
198 const llvm::Triple &Triple) {
199 if (!D.SysRoot.empty())
200 return D.SysRoot;
201
202 SmallString<128> SysRootDir(D.Dir);
203 llvm::sys::path::append(path&: SysRootDir, a: "..", b: "lib", c: "clang-runtimes");
204
205 SmallString<128> MultilibPath(SysRootDir);
206 llvm::sys::path::append(path&: MultilibPath, a: MultilibFilename);
207
208 // New behaviour: if multilib.yaml is found then use clang-runtimes as the
209 // sysroot.
210 if (D.getVFS().exists(Path: MultilibPath))
211 return std::string(SysRootDir);
212
213 // Otherwise fall back to the old behaviour of appending the target triple.
214 llvm::sys::path::append(path&: SysRootDir, a: D.getTargetTriple());
215 return std::string(SysRootDir);
216}
217
218void BareMetal::findMultilibs(const Driver &D, const llvm::Triple &Triple,
219 const ArgList &Args) {
220 DetectedMultilibs Result;
221 if (isRISCVBareMetal(Triple)) {
222 if (findRISCVMultilibs(D, TargetTriple: Triple, Args, Result)) {
223 SelectedMultilibs = Result.SelectedMultilibs;
224 Multilibs = Result.Multilibs;
225 }
226 } else {
227 llvm::SmallString<128> MultilibPath(computeBaseSysRoot(D, Triple));
228 llvm::sys::path::append(path&: MultilibPath, a: MultilibFilename);
229 findMultilibsFromYAML(TC: *this, D, MultilibPath, Args, Result);
230 SelectedMultilibs = Result.SelectedMultilibs;
231 Multilibs = Result.Multilibs;
232 }
233}
234
235bool BareMetal::handlesTarget(const llvm::Triple &Triple) {
236 return isARMBareMetal(Triple) || isAArch64BareMetal(Triple) ||
237 isRISCVBareMetal(Triple) || isPPCBareMetal(Triple);
238}
239
240Tool *BareMetal::buildLinker() const {
241 return new tools::baremetal::Linker(*this);
242}
243
244Tool *BareMetal::buildStaticLibTool() const {
245 return new tools::baremetal::StaticLibTool(*this);
246}
247
248std::string BareMetal::computeSysRoot() const {
249 return computeBaseSysRoot(D: getDriver(), Triple: getTriple());
250}
251
252BareMetal::OrderedMultilibs BareMetal::getOrderedMultilibs() const {
253 // Get multilibs in reverse order because they're ordered most-specific last.
254 if (!SelectedMultilibs.empty())
255 return llvm::reverse(C: SelectedMultilibs);
256
257 // No multilibs selected so return a single default multilib.
258 static const llvm::SmallVector<Multilib> Default = {Multilib()};
259 return llvm::reverse(C: Default);
260}
261
262void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
263 ArgStringList &CC1Args) const {
264 if (DriverArgs.hasArg(Ids: options::OPT_nostdinc))
265 return;
266
267 if (!DriverArgs.hasArg(Ids: options::OPT_nobuiltininc)) {
268 SmallString<128> Dir(getDriver().ResourceDir);
269 llvm::sys::path::append(path&: Dir, a: "include");
270 addSystemInclude(DriverArgs, CC1Args, Path: Dir.str());
271 }
272
273 if (DriverArgs.hasArg(Ids: options::OPT_nostdlibinc))
274 return;
275
276 if (std::optional<std::string> Path = getStdlibIncludePath())
277 addSystemInclude(DriverArgs, CC1Args, Path: *Path);
278
279 const SmallString<128> SysRoot(computeSysRoot());
280 if (!SysRoot.empty()) {
281 for (const Multilib &M : getOrderedMultilibs()) {
282 SmallString<128> Dir(SysRoot);
283 llvm::sys::path::append(path&: Dir, a: M.includeSuffix());
284 llvm::sys::path::append(path&: Dir, a: "include");
285 addSystemInclude(DriverArgs, CC1Args, Path: Dir.str());
286 }
287 }
288}
289
290void BareMetal::addClangTargetOptions(const ArgList &DriverArgs,
291 ArgStringList &CC1Args,
292 Action::OffloadKind) const {
293 CC1Args.push_back(Elt: "-nostdsysteminc");
294}
295
296void BareMetal::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
297 ArgStringList &CC1Args) const {
298 if (DriverArgs.hasArg(Ids: options::OPT_nostdinc, Ids: options::OPT_nostdlibinc,
299 Ids: options::OPT_nostdincxx))
300 return;
301
302 const Driver &D = getDriver();
303 std::string Target = getTripleString();
304
305 auto AddCXXIncludePath = [&](StringRef Path) {
306 std::string Version = detectLibcxxVersion(IncludePath: Path);
307 if (Version.empty())
308 return;
309
310 {
311 // First the per-target include dir: include/<target>/c++/v1.
312 SmallString<128> TargetDir(Path);
313 llvm::sys::path::append(path&: TargetDir, a: Target, b: "c++", c: Version);
314 addSystemInclude(DriverArgs, CC1Args, Path: TargetDir);
315 }
316
317 {
318 // Then the generic dir: include/c++/v1.
319 SmallString<128> Dir(Path);
320 llvm::sys::path::append(path&: Dir, a: "c++", b: Version);
321 addSystemInclude(DriverArgs, CC1Args, Path: Dir);
322 }
323 };
324
325 switch (GetCXXStdlibType(Args: DriverArgs)) {
326 case ToolChain::CST_Libcxx: {
327 SmallString<128> P(D.Dir);
328 llvm::sys::path::append(path&: P, a: "..", b: "include");
329 AddCXXIncludePath(P);
330 break;
331 }
332 case ToolChain::CST_Libstdcxx:
333 // We only support libc++ toolchain installation.
334 break;
335 }
336
337 std::string SysRoot(computeSysRoot());
338 if (SysRoot.empty())
339 return;
340
341 for (const Multilib &M : getOrderedMultilibs()) {
342 SmallString<128> Dir(SysRoot);
343 llvm::sys::path::append(path&: Dir, a: M.gccSuffix());
344 switch (GetCXXStdlibType(Args: DriverArgs)) {
345 case ToolChain::CST_Libcxx: {
346 // First check sysroot/usr/include/c++/v1 if it exists.
347 SmallString<128> TargetDir(Dir);
348 llvm::sys::path::append(path&: TargetDir, a: "usr", b: "include", c: "c++", d: "v1");
349 if (D.getVFS().exists(Path: TargetDir)) {
350 addSystemInclude(DriverArgs, CC1Args, Path: TargetDir.str());
351 break;
352 }
353 // Add generic path if nothing else succeeded so far.
354 llvm::sys::path::append(path&: Dir, a: "include", b: "c++", c: "v1");
355 addSystemInclude(DriverArgs, CC1Args, Path: Dir.str());
356 break;
357 }
358 case ToolChain::CST_Libstdcxx: {
359 llvm::sys::path::append(path&: Dir, a: "include", b: "c++");
360 std::error_code EC;
361 Generic_GCC::GCCVersion Version = {.Text: "", .Major: -1, .Minor: -1, .Patch: -1, .MajorStr: "", .MinorStr: "", .PatchSuffix: ""};
362 // Walk the subdirs, and find the one with the newest gcc version:
363 for (llvm::vfs::directory_iterator
364 LI = D.getVFS().dir_begin(Dir: Dir.str(), EC),
365 LE;
366 !EC && LI != LE; LI = LI.increment(EC)) {
367 StringRef VersionText = llvm::sys::path::filename(path: LI->path());
368 auto CandidateVersion = Generic_GCC::GCCVersion::Parse(VersionText);
369 if (CandidateVersion.Major == -1)
370 continue;
371 if (CandidateVersion <= Version)
372 continue;
373 Version = CandidateVersion;
374 }
375 if (Version.Major != -1) {
376 llvm::sys::path::append(path&: Dir, a: Version.Text);
377 addSystemInclude(DriverArgs, CC1Args, Path: Dir.str());
378 }
379 break;
380 }
381 }
382 }
383}
384
385void BareMetal::AddCXXStdlibLibArgs(const ArgList &Args,
386 ArgStringList &CmdArgs) const {
387 switch (GetCXXStdlibType(Args)) {
388 case ToolChain::CST_Libcxx:
389 CmdArgs.push_back(Elt: "-lc++");
390 if (Args.hasArg(Ids: options::OPT_fexperimental_library))
391 CmdArgs.push_back(Elt: "-lc++experimental");
392 CmdArgs.push_back(Elt: "-lc++abi");
393 break;
394 case ToolChain::CST_Libstdcxx:
395 CmdArgs.push_back(Elt: "-lstdc++");
396 CmdArgs.push_back(Elt: "-lsupc++");
397 break;
398 }
399 CmdArgs.push_back(Elt: "-lunwind");
400}
401
402void BareMetal::AddLinkRuntimeLib(const ArgList &Args,
403 ArgStringList &CmdArgs) const {
404 ToolChain::RuntimeLibType RLT = GetRuntimeLibType(Args);
405 switch (RLT) {
406 case ToolChain::RLT_CompilerRT: {
407 CmdArgs.push_back(Elt: getCompilerRTArgString(Args, Component: "builtins"));
408 return;
409 }
410 case ToolChain::RLT_Libgcc:
411 CmdArgs.push_back(Elt: "-lgcc");
412 return;
413 }
414 llvm_unreachable("Unhandled RuntimeLibType.");
415}
416
417void baremetal::StaticLibTool::ConstructJob(Compilation &C, const JobAction &JA,
418 const InputInfo &Output,
419 const InputInfoList &Inputs,
420 const ArgList &Args,
421 const char *LinkingOutput) const {
422 const Driver &D = getToolChain().getDriver();
423
424 // Silence warning for "clang -g foo.o -o foo"
425 Args.ClaimAllArgs(Id0: options::OPT_g_Group);
426 // and "clang -emit-llvm foo.o -o foo"
427 Args.ClaimAllArgs(Id0: options::OPT_emit_llvm);
428 // and for "clang -w foo.o -o foo". Other warning options are already
429 // handled somewhere else.
430 Args.ClaimAllArgs(Id0: options::OPT_w);
431 // Silence warnings when linking C code with a C++ '-stdlib' argument.
432 Args.ClaimAllArgs(Id0: options::OPT_stdlib_EQ);
433
434 // ar tool command "llvm-ar <options> <output_file> <input_files>".
435 ArgStringList CmdArgs;
436 // Create and insert file members with a deterministic index.
437 CmdArgs.push_back(Elt: "rcsD");
438 CmdArgs.push_back(Elt: Output.getFilename());
439
440 for (const auto &II : Inputs) {
441 if (II.isFilename()) {
442 CmdArgs.push_back(Elt: II.getFilename());
443 }
444 }
445
446 // Delete old output archive file if it already exists before generating a new
447 // archive file.
448 const char *OutputFileName = Output.getFilename();
449 if (Output.isFilename() && llvm::sys::fs::exists(Path: OutputFileName)) {
450 if (std::error_code EC = llvm::sys::fs::remove(path: OutputFileName)) {
451 D.Diag(DiagID: diag::err_drv_unable_to_remove_file) << EC.message();
452 return;
453 }
454 }
455
456 const char *Exec = Args.MakeArgString(Str: getToolChain().GetStaticLibToolPath());
457 C.addCommand(C: std::make_unique<Command>(args: JA, args: *this,
458 args: ResponseFileSupport::AtFileCurCP(),
459 args&: Exec, args&: CmdArgs, args: Inputs, args: Output));
460}
461
462void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA,
463 const InputInfo &Output,
464 const InputInfoList &Inputs,
465 const ArgList &Args,
466 const char *LinkingOutput) const {
467 ArgStringList CmdArgs;
468
469 auto &TC = static_cast<const toolchains::BareMetal &>(getToolChain());
470 const Driver &D = getToolChain().getDriver();
471 const llvm::Triple::ArchType Arch = TC.getArch();
472 const llvm::Triple &Triple = getToolChain().getEffectiveTriple();
473
474 AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
475
476 CmdArgs.push_back(Elt: "-Bstatic");
477
478 if (TC.getTriple().isRISCV() && Args.hasArg(Ids: options::OPT_mno_relax))
479 CmdArgs.push_back(Elt: "--no-relax");
480
481 if (Triple.isARM() || Triple.isThumb()) {
482 bool IsBigEndian = arm::isARMBigEndian(Triple, Args);
483 if (IsBigEndian)
484 arm::appendBE8LinkFlag(Args, CmdArgs, Triple);
485 CmdArgs.push_back(Elt: IsBigEndian ? "-EB" : "-EL");
486 } else if (Triple.isAArch64()) {
487 CmdArgs.push_back(Elt: Arch == llvm::Triple::aarch64_be ? "-EB" : "-EL");
488 }
489
490 Args.addAllArgs(Output&: CmdArgs, Ids: {options::OPT_L, options::OPT_T_Group,
491 options::OPT_s, options::OPT_t, options::OPT_r});
492
493 TC.AddFilePathLibArgs(Args, CmdArgs);
494
495 for (const auto &LibPath : TC.getLibraryPaths())
496 CmdArgs.push_back(Elt: Args.MakeArgString(Str: llvm::Twine("-L", LibPath)));
497
498 if (TC.ShouldLinkCXXStdlib(Args))
499 TC.AddCXXStdlibLibArgs(Args, CmdArgs);
500
501 if (!Args.hasArg(Ids: options::OPT_nostdlib, Ids: options::OPT_nodefaultlibs)) {
502 CmdArgs.push_back(Elt: "-lc");
503 CmdArgs.push_back(Elt: "-lm");
504
505 TC.AddLinkRuntimeLib(Args, CmdArgs);
506 }
507
508 if (D.isUsingLTO()) {
509 assert(!Inputs.empty() && "Must have at least one input.");
510 // Find the first filename InputInfo object.
511 auto Input = llvm::find_if(
512 Range: Inputs, P: [](const InputInfo &II) -> bool { return II.isFilename(); });
513 if (Input == Inputs.end())
514 // For a very rare case, all of the inputs to the linker are
515 // InputArg. If that happens, just use the first InputInfo.
516 Input = Inputs.begin();
517
518 addLTOOptions(ToolChain: TC, Args, CmdArgs, Output, Input: *Input,
519 IsThinLTO: D.getLTOMode() == LTOK_Thin);
520 }
521 if (TC.getTriple().isRISCV())
522 CmdArgs.push_back(Elt: "-X");
523
524 // The R_ARM_TARGET2 relocation must be treated as R_ARM_REL32 on arm*-*-elf
525 // and arm*-*-eabi (the default is R_ARM_GOT_PREL, used on arm*-*-linux and
526 // arm*-*-*bsd).
527 if (isARMBareMetal(Triple: TC.getTriple()))
528 CmdArgs.push_back(Elt: "--target2=rel");
529
530 CmdArgs.push_back(Elt: "-o");
531 CmdArgs.push_back(Elt: Output.getFilename());
532
533 C.addCommand(C: std::make_unique<Command>(
534 args: JA, args: *this, args: ResponseFileSupport::AtFileCurCP(),
535 args: Args.MakeArgString(Str: TC.GetLinkerPath()), args&: CmdArgs, args: Inputs, args: Output));
536}
537
538// BareMetal toolchain allows all sanitizers where the compiler generates valid
539// code, ignoring all runtime library support issues on the assumption that
540// baremetal targets typically implement their own runtime support.
541SanitizerMask BareMetal::getSupportedSanitizers() const {
542 const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64;
543 const bool IsAArch64 = getTriple().getArch() == llvm::Triple::aarch64 ||
544 getTriple().getArch() == llvm::Triple::aarch64_be;
545 const bool IsRISCV64 = getTriple().getArch() == llvm::Triple::riscv64;
546 SanitizerMask Res = ToolChain::getSupportedSanitizers();
547 Res |= SanitizerKind::Address;
548 Res |= SanitizerKind::KernelAddress;
549 Res |= SanitizerKind::PointerCompare;
550 Res |= SanitizerKind::PointerSubtract;
551 Res |= SanitizerKind::Fuzzer;
552 Res |= SanitizerKind::FuzzerNoLink;
553 Res |= SanitizerKind::Vptr;
554 Res |= SanitizerKind::SafeStack;
555 Res |= SanitizerKind::Thread;
556 Res |= SanitizerKind::Scudo;
557 if (IsX86_64 || IsAArch64 || IsRISCV64) {
558 Res |= SanitizerKind::HWAddress;
559 Res |= SanitizerKind::KernelHWAddress;
560 }
561 return Res;
562}
563