clang 23.0.0git
BareMetal.cpp
Go to the documentation of this file.
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"
14
15#include "Arch/AArch64.h"
16#include "Arch/ARM.h"
17#include "Arch/RISCV.h"
19#include "clang/Driver/Driver.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
27using namespace llvm::opt;
28using namespace clang;
29using namespace clang::driver;
30using namespace clang::driver::tools;
31using namespace clang::driver::toolchains;
32
33static bool isRISCVBareMetal(const llvm::Triple &Triple) {
34 if (!Triple.isRISCV())
35 return false;
36
37 if (Triple.getVendor() != llvm::Triple::UnknownVendor)
38 return false;
39
40 if (Triple.getOS() != llvm::Triple::UnknownOS)
41 return false;
42
43 return Triple.getEnvironmentName() == "elf";
44}
45
46/// Is the triple powerpc[64][le]-*-none-eabi?
47static bool isPPCBareMetal(const llvm::Triple &Triple) {
48 return Triple.isPPC() && Triple.getOS() == llvm::Triple::UnknownOS &&
49 Triple.getEnvironment() == llvm::Triple::EABI;
50}
51
52/// Is the triple {ix86,x86_64}-*-none-elf?
53static bool isX86BareMetal(const llvm::Triple &Triple) {
54 return Triple.isX86() && Triple.getOS() == llvm::Triple::UnknownOS &&
55 Triple.getEnvironmentName() == "elf";
56}
57
58static bool findRISCVMultilibs(const Driver &D,
59 const llvm::Triple &TargetTriple,
60 const ArgList &Args, DetectedMultilibs &Result) {
62 std::string Arch = riscv::getRISCVArch(Args, TargetTriple);
63 StringRef Abi = tools::riscv::getRISCVABI(Args, TargetTriple);
64
65 if (TargetTriple.isRISCV64()) {
66 MultilibBuilder Imac =
67 MultilibBuilder().flag("-march=rv64imac").flag("-mabi=lp64");
68 MultilibBuilder Imafdc = MultilibBuilder("/rv64imafdc/lp64d")
69 .flag("-march=rv64imafdc")
70 .flag("-mabi=lp64d");
71
72 // Multilib reuse
73 bool UseImafdc =
74 (Arch == "rv64imafdc") || (Arch == "rv64gc"); // gc => imafdc
75
76 addMultilibFlag((Arch == "rv64imac"), "-march=rv64imac", Flags);
77 addMultilibFlag(UseImafdc, "-march=rv64imafdc", Flags);
78 addMultilibFlag(Abi == "lp64", "-mabi=lp64", Flags);
79 addMultilibFlag(Abi == "lp64d", "-mabi=lp64d", Flags);
80
81 Result.Multilibs =
83 return Result.Multilibs.select(D, Flags, Result.SelectedMultilibs);
84 }
85 if (TargetTriple.isRISCV32()) {
86 MultilibBuilder Imac =
87 MultilibBuilder().flag("-march=rv32imac").flag("-mabi=ilp32");
88 MultilibBuilder I = MultilibBuilder("/rv32i/ilp32")
89 .flag("-march=rv32i")
90 .flag("-mabi=ilp32");
91 MultilibBuilder Im = MultilibBuilder("/rv32im/ilp32")
92 .flag("-march=rv32im")
93 .flag("-mabi=ilp32");
94 MultilibBuilder Iac = MultilibBuilder("/rv32iac/ilp32")
95 .flag("-march=rv32iac")
96 .flag("-mabi=ilp32");
97 MultilibBuilder Imafc = MultilibBuilder("/rv32imafc/ilp32f")
98 .flag("-march=rv32imafc")
99 .flag("-mabi=ilp32f");
100
101 // Multilib reuse
102 bool UseI = (Arch == "rv32i") || (Arch == "rv32ic"); // ic => i
103 bool UseIm = (Arch == "rv32im") || (Arch == "rv32imc"); // imc => im
104 bool UseImafc = (Arch == "rv32imafc") || (Arch == "rv32imafdc") ||
105 (Arch == "rv32gc"); // imafdc,gc => imafc
106
107 addMultilibFlag(UseI, "-march=rv32i", Flags);
108 addMultilibFlag(UseIm, "-march=rv32im", Flags);
109 addMultilibFlag((Arch == "rv32iac"), "-march=rv32iac", Flags);
110 addMultilibFlag((Arch == "rv32imac"), "-march=rv32imac", Flags);
111 addMultilibFlag(UseImafc, "-march=rv32imafc", Flags);
112 addMultilibFlag(Abi == "ilp32", "-mabi=ilp32", Flags);
113 addMultilibFlag(Abi == "ilp32f", "-mabi=ilp32f", Flags);
114
115 Result.Multilibs =
116 MultilibSetBuilder().Either(I, Im, Iac, Imac, Imafc).makeMultilibSet();
117 return Result.Multilibs.select(D, Flags, Result.SelectedMultilibs);
118 }
119 return false;
120}
121
122static std::string computeClangRuntimesSysRoot(const Driver &D,
123 bool IncludeTriple) {
124 if (!D.SysRoot.empty())
125 return D.SysRoot;
126
127 SmallString<128> SysRootDir(D.Dir);
128 llvm::sys::path::append(SysRootDir, "..", "lib", "clang-runtimes");
129
130 if (IncludeTriple)
131 llvm::sys::path::append(SysRootDir, D.getTargetTriple());
132
133 return std::string(SysRootDir);
134}
135
136// Only consider the GCC toolchain based on the values provided through the
137// `--gcc-toolchain` and `--gcc-install-dir` flags. The function below returns
138// whether the GCC toolchain was initialized successfully.
139bool BareMetal::initGCCInstallation(const llvm::Triple &Triple,
140 const llvm::opt::ArgList &Args) {
141 if (Args.getLastArg(options::OPT_gcc_toolchain) ||
142 Args.getLastArg(clang::options::OPT_gcc_install_dir_EQ)) {
143 GCCInstallation.init(Triple, Args);
144 return GCCInstallation.isValid();
145 }
146 return false;
147}
148
149// This logic is adapted from RISCVToolChain.cpp as part of the ongoing effort
150// to merge RISCVToolChain into the Baremetal toolchain. It infers the presence
151// of a valid GCC toolchain by checking whether the `crt0.o` file exists in the
152// `bin/../<target-triple>/lib` directory.
153static bool detectGCCToolchainAdjacent(const Driver &D) {
154 SmallString<128> GCCDir;
155 llvm::sys::path::append(GCCDir, D.Dir, "..", D.getTargetTriple(),
156 "lib/crt0.o");
157 return llvm::sys::fs::exists(GCCDir);
158}
159
160// If no sysroot is provided the driver will first attempt to infer it from the
161// values of `--gcc-install-dir` or `--gcc-toolchain`, which specify the
162// location of a GCC toolchain.
163// If neither flag is used, the sysroot defaults to either:
164//    - `bin/../<target-triple>`
165//    - `bin/../lib/clang-runtimes/<target-triple>`
166//
167// To use the `clang-runtimes` path, ensure that `../<target-triple>/lib/crt0.o`
168// does not exist relative to the driver.
169std::string BareMetal::computeSysRoot() const {
170 // Use Baremetal::sysroot if it has already been set.
171 if (!SysRoot.empty())
172 return SysRoot;
173
174 // Use the sysroot specified via the `--sysroot` command-line flag, if
175 // provided.
176 const Driver &D = getDriver();
177 if (!D.SysRoot.empty())
178 return D.SysRoot;
179
180 // Attempt to infer sysroot from a valid GCC installation.
181 // If no valid GCC installation, check for a GCC toolchain alongside Clang.
182 SmallString<128> inferredSysRoot;
183 if (IsGCCInstallationValid) {
184 llvm::sys::path::append(inferredSysRoot, GCCInstallation.getParentLibPath(),
185 "..", GCCInstallation.getTriple().str());
186 } else if (detectGCCToolchainAdjacent(D)) {
187 // Use the triple as provided to the driver. Unlike the parsed triple
188 // this has not been normalized to always contain every field.
189 llvm::sys::path::append(inferredSysRoot, D.Dir, "..", D.getTargetTriple());
190 }
191 // If a valid sysroot was inferred and exists, use it
192 if (!inferredSysRoot.empty() && llvm::sys::fs::exists(inferredSysRoot))
193 return std::string(inferredSysRoot);
194
195 // Use the clang-runtimes path.
196 return computeClangRuntimesSysRoot(D, /*IncludeTriple*/ true);
197}
198
199std::string BareMetal::getCompilerRTPath() const {
200 const Driver &D = getDriver();
201 if (IsGCCInstallationValid || detectGCCToolchainAdjacent(getDriver())) {
202 SmallString<128> Path(D.ResourceDir);
203 llvm::sys::path::append(Path, "lib");
204 return std::string(Path.str());
205 }
207}
208
209static void addMultilibsFilePaths(const Driver &D, const MultilibSet &Multilibs,
210 const Multilib &Multilib,
211 StringRef InstallPath,
212 ToolChain::path_list &Paths) {
213 if (const auto &PathsCallback = Multilibs.filePathsCallback())
214 for (const auto &Path : PathsCallback(Multilib))
215 addPathIfExists(D, InstallPath + Path, Paths);
216}
217
218// GCC mutltilibs will only work for those targets that have their multlib
219// structure encoded into GCCInstallation. Baremetal toolchain supports ARM,
220// AArch64, RISCV and PPC and of these only RISCV have GCC multilibs hardcoded
221// in GCCInstallation.
222BareMetal::BareMetal(const Driver &D, const llvm::Triple &Triple,
223 const ArgList &Args)
224 : Generic_ELF(D, Triple, Args) {
225 IsGCCInstallationValid = initGCCInstallation(Triple, Args);
226 std::string ComputedSysRoot = computeSysRoot();
227 if (IsGCCInstallationValid) {
228 if (!isRISCVBareMetal(Triple))
229 D.Diag(clang::diag::warn_drv_multilib_not_available_for_target);
230
231 Multilibs = GCCInstallation.getMultilibs();
232 SelectedMultilibs.assign({GCCInstallation.getMultilib()});
233
234 path_list &Paths = getFilePaths();
235 // Add toolchain/multilib specific file paths.
237 GCCInstallation.getInstallPath(), Paths);
238 // Adding filepath for locating crt{begin,end}.o files.
239 Paths.push_back(GCCInstallation.getInstallPath().str());
240 // Adding filepath for locating crt0.o file.
241 Paths.push_back(ComputedSysRoot + "/lib");
242
244 // Multilib cross-compiler GCC installations put ld in a triple-prefixed
245 // directory off of the parent of the GCC installation.
246 PPaths.push_back(Twine(GCCInstallation.getParentLibPath() + "/../" +
247 GCCInstallation.getTriple().str() + "/bin")
248 .str());
249 PPaths.push_back((GCCInstallation.getParentLibPath() + "/../bin").str());
250 } else {
251 getProgramPaths().push_back(getDriver().Dir);
252 findMultilibs(D, Triple, Args);
253 const SmallString<128> SysRootDir(computeSysRoot());
254 if (!SysRootDir.empty()) {
255 for (const Multilib &M : getOrderedMultilibs()) {
256 SmallString<128> Dir(SysRootDir);
257 llvm::sys::path::append(Dir, M.osSuffix(), "lib");
258 getFilePaths().push_back(std::string(Dir));
259 getLibraryPaths().push_back(std::string(Dir));
260 }
261 }
262 }
263}
264
265void BareMetal::findMultilibs(const Driver &D, const llvm::Triple &Triple,
266 const ArgList &Args) {
267 // Look for a multilib.yaml before trying target-specific hardwired logic.
268 std::string FallbackDir =
269 computeClangRuntimesSysRoot(D, /*IncludeTriple=*/false);
270 if (loadMultilibsFromYAML(Args, D, FallbackDir)) {
271 SysRoot = FallbackDir;
272 } else if (isRISCVBareMetal(Triple) && !detectGCCToolchainAdjacent(D)) {
274 if (findRISCVMultilibs(D, Triple, Args, Result)) {
275 SelectedMultilibs = Result.SelectedMultilibs;
276 Multilibs = Result.Multilibs;
277 }
278 }
279}
280
281bool BareMetal::handlesTarget(const llvm::Triple &Triple) {
282 return arm::isARMEABIBareMetal(Triple) ||
284 isPPCBareMetal(Triple) || isX86BareMetal(Triple);
285}
286
288 return new tools::baremetal::Linker(*this);
289}
290
294
296 if (getTriple().isRISCV() && IsGCCInstallationValid)
299}
300
302 if (getTriple().isRISCV() && IsGCCInstallationValid)
305}
306
307// TODO: Add a validity check for GCCInstallation.
308// If valid, use `UNW_Libgcc`; otherwise, use `UNW_None`.
310BareMetal::GetUnwindLibType(const llvm::opt::ArgList &Args) const {
311 if (getTriple().isRISCV())
312 return ToolChain::UNW_None;
313
314 return ToolChain::GetUnwindLibType(Args);
315}
316
317void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
318 ArgStringList &CC1Args) const {
319 if (DriverArgs.hasArg(options::OPT_nostdinc))
320 return;
321
322 if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
323 SmallString<128> Dir(getDriver().ResourceDir);
324 llvm::sys::path::append(Dir, "include");
325 addSystemInclude(DriverArgs, CC1Args, Dir.str());
326 }
327
328 if (DriverArgs.hasArg(options::OPT_nostdlibinc))
329 return;
330
331 const Driver &D = getDriver();
332
333 if (std::optional<std::string> Path = getStdlibIncludePath())
334 addSystemInclude(DriverArgs, CC1Args, *Path);
335
336 const SmallString<128> SysRootDir(computeSysRoot());
337 if (!SysRootDir.empty()) {
338 for (const Multilib &M : getOrderedMultilibs()) {
339 SmallString<128> Dir(SysRootDir);
340 llvm::sys::path::append(Dir, M.includeSuffix());
341 llvm::sys::path::append(Dir, "include");
342 addSystemInclude(DriverArgs, CC1Args, Dir.str());
343 }
344 SmallString<128> Dir(SysRootDir);
345 llvm::sys::path::append(Dir, getTripleString());
346 if (D.getVFS().exists(Dir)) {
347 llvm::sys::path::append(Dir, "include");
348 addSystemInclude(DriverArgs, CC1Args, Dir.str());
349 }
350 }
351}
352
353void BareMetal::addClangTargetOptions(const ArgList &DriverArgs,
354 ArgStringList &CC1Args,
355 Action::OffloadKind) const {
356 CC1Args.push_back("-nostdsysteminc");
357}
358
360 const llvm::opt::ArgList &DriverArgs,
361 llvm::opt::ArgStringList &CC1Args) const {
362 if (!IsGCCInstallationValid)
363 return;
364 const GCCVersion &Version = GCCInstallation.getVersion();
365 StringRef TripleStr = GCCInstallation.getTriple().str();
366 const Multilib &Multilib = GCCInstallation.getMultilib();
367 addLibStdCXXIncludePaths(computeSysRoot() + "/include/c++/" + Version.Text,
368 TripleStr, Multilib.includeSuffix(), DriverArgs,
369 CC1Args);
370}
371
372void BareMetal::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
373 ArgStringList &CC1Args) const {
374 if (DriverArgs.hasArg(options::OPT_nostdinc, options::OPT_nostdlibinc,
375 options::OPT_nostdincxx))
376 return;
377
378 const Driver &D = getDriver();
379 StringRef Target = getTripleString();
380
381 auto AddCXXIncludePath = [&](StringRef Path) {
382 std::string Version = detectLibcxxVersion(Path);
383 if (Version.empty())
384 return;
385
386 {
387 // First the per-target include dir: include/<target>/c++/v1.
388 SmallString<128> TargetDir(Path);
389 llvm::sys::path::append(TargetDir, Target, "c++", Version);
390 addSystemInclude(DriverArgs, CC1Args, TargetDir);
391 }
392
393 {
394 // Then the generic dir: include/c++/v1.
395 SmallString<128> Dir(Path);
396 llvm::sys::path::append(Dir, "c++", Version);
397 addSystemInclude(DriverArgs, CC1Args, Dir);
398 }
399 };
400
401 switch (GetCXXStdlibType(DriverArgs)) {
403 SmallString<128> P(D.Dir);
404 llvm::sys::path::append(P, "..", "include");
405 AddCXXIncludePath(P);
406 break;
407 }
409 addLibStdCxxIncludePaths(DriverArgs, CC1Args);
410 break;
411 }
412
413 std::string SysRootDir(computeSysRoot());
414 if (SysRootDir.empty())
415 return;
416
417 for (const Multilib &M : getOrderedMultilibs()) {
418 SmallString<128> Dir(SysRootDir);
419 llvm::sys::path::append(Dir, M.gccSuffix());
420 switch (GetCXXStdlibType(DriverArgs)) {
422 // First check sysroot/usr/include/c++/v1 if it exists.
423 SmallString<128> TargetDir(Dir);
424 llvm::sys::path::append(TargetDir, "usr", "include", "c++", "v1");
425 if (D.getVFS().exists(TargetDir)) {
426 addSystemInclude(DriverArgs, CC1Args, TargetDir.str());
427 break;
428 }
429 // Add generic paths if nothing else succeeded so far.
430 llvm::sys::path::append(Dir, "include", "c++", "v1");
431 addSystemInclude(DriverArgs, CC1Args, Dir.str());
432 break;
433 }
435 llvm::sys::path::append(Dir, "include", "c++");
436 std::error_code EC;
437 Generic_GCC::GCCVersion Version = {"", -1, -1, -1, "", "", ""};
438 // Walk the subdirs, and find the one with the newest gcc version:
439 for (llvm::vfs::directory_iterator
440 LI = D.getVFS().dir_begin(Dir.str(), EC),
441 LE;
442 !EC && LI != LE; LI = LI.increment(EC)) {
443 StringRef VersionText = llvm::sys::path::filename(LI->path());
444 auto CandidateVersion = Generic_GCC::GCCVersion::Parse(VersionText);
445 if (CandidateVersion.Major == -1)
446 continue;
447 if (CandidateVersion <= Version)
448 continue;
449 Version = CandidateVersion;
450 }
451 if (Version.Major != -1) {
452 llvm::sys::path::append(Dir, Version.Text);
453 addSystemInclude(DriverArgs, CC1Args, Dir.str());
454 }
455 break;
456 }
457 }
458 }
459 switch (GetCXXStdlibType(DriverArgs)) {
461 SmallString<128> Dir(SysRootDir);
462 llvm::sys::path::append(Dir, Target, "include", "c++", "v1");
463 if (D.getVFS().exists(Dir))
464 addSystemInclude(DriverArgs, CC1Args, Dir.str());
465 break;
466 }
468 break;
469 }
470}
471
473 const InputInfo &Output,
474 const InputInfoList &Inputs,
475 const ArgList &Args,
476 const char *LinkingOutput) const {
477 const Driver &D = getToolChain().getDriver();
478
479 // Silence warning for "clang -g foo.o -o foo"
480 Args.ClaimAllArgs(options::OPT_g_Group);
481 // and "clang -emit-llvm foo.o -o foo"
482 Args.ClaimAllArgs(options::OPT_emit_llvm);
483 // and for "clang -w foo.o -o foo". Other warning options are already
484 // handled somewhere else.
485 Args.ClaimAllArgs(options::OPT_w);
486 // Silence warnings when linking C code with a C++ '-stdlib' argument.
487 Args.ClaimAllArgs(options::OPT_stdlib_EQ);
488
489 // ar tool command "llvm-ar <options> <output_file> <input_files>".
490 ArgStringList CmdArgs;
491 // Create and insert file members with a deterministic index.
492 CmdArgs.push_back("rcsD");
493 CmdArgs.push_back(Output.getFilename());
494
495 for (const auto &II : Inputs) {
496 if (II.isFilename()) {
497 CmdArgs.push_back(II.getFilename());
498 }
499 }
500
501 // Delete old output archive file if it already exists before generating a new
502 // archive file.
503 const char *OutputFileName = Output.getFilename();
504 if (Output.isFilename() && llvm::sys::fs::exists(OutputFileName)) {
505 if (std::error_code EC = llvm::sys::fs::remove(OutputFileName)) {
506 D.Diag(diag::err_drv_unable_to_remove_file) << EC.message();
507 return;
508 }
509 }
510
511 const char *Exec = Args.MakeArgString(getToolChain().GetStaticLibToolPath());
512 C.addCommand(std::make_unique<Command>(JA, *this,
514 Exec, CmdArgs, Inputs, Output));
515}
516
518 const InputInfo &Output,
519 const InputInfoList &Inputs,
520 const ArgList &Args,
521 const char *LinkingOutput) const {
522 ArgStringList CmdArgs;
523
524 auto &TC = static_cast<const toolchains::BareMetal &>(getToolChain());
525 const Driver &D = getToolChain().getDriver();
526 const llvm::Triple::ArchType Arch = TC.getArch();
527 const llvm::Triple &Triple = getToolChain().getEffectiveTriple();
528 const bool IsStaticPIE = getStaticPIE(Args, TC);
529
530 if (!D.SysRoot.empty())
531 CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
532
533 CmdArgs.push_back("-Bstatic");
534 if (IsStaticPIE) {
535 CmdArgs.push_back("-pie");
536 CmdArgs.push_back("--no-dynamic-linker");
537 CmdArgs.push_back("-z");
538 CmdArgs.push_back("text");
539 }
540
541 if (const char *LDMOption = getLDMOption(TC.getTriple(), Args)) {
542 CmdArgs.push_back("-m");
543 CmdArgs.push_back(LDMOption);
544 } else {
545 D.Diag(diag::err_target_unknown_triple) << Triple.str();
546 return;
547 }
548
549 if (Triple.isRISCV()) {
550 CmdArgs.push_back("-X");
551 if (Args.hasArg(options::OPT_mno_relax))
552 CmdArgs.push_back("--no-relax");
553 }
554
555 if (Triple.isARM() || Triple.isThumb()) {
556 bool IsBigEndian = arm::isARMBigEndian(Triple, Args);
557 if (IsBigEndian)
558 arm::appendBE8LinkFlag(Args, CmdArgs, Triple);
559 CmdArgs.push_back(IsBigEndian ? "-EB" : "-EL");
560 } else if (Triple.isAArch64()) {
561 CmdArgs.push_back(Arch == llvm::Triple::aarch64_be ? "-EB" : "-EL");
562 }
563
564 bool NeedCRTs =
565 !Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles);
566
567 const char *CRTBegin, *CRTEnd;
568 if (NeedCRTs) {
569 if (!Args.hasArg(options::OPT_r)) {
570 const char *crt = "crt0.o";
571 if (IsStaticPIE)
572 crt = "rcrt1.o";
573 CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath(crt)));
574 }
575 if (TC.hasValidGCCInstallation() || detectGCCToolchainAdjacent(D)) {
576 auto RuntimeLib = TC.GetRuntimeLibType(Args);
577 switch (RuntimeLib) {
578 case (ToolChain::RLT_Libgcc): {
579 CRTBegin = IsStaticPIE ? "crtbeginS.o" : "crtbegin.o";
580 CRTEnd = IsStaticPIE ? "crtendS.o" : "crtend.o";
581 break;
582 }
584 CRTBegin =
585 TC.getCompilerRTArgString(Args, "crtbegin", ToolChain::FT_Object);
586 CRTEnd =
587 TC.getCompilerRTArgString(Args, "crtend", ToolChain::FT_Object);
588 break;
589 }
590 }
591 CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath(CRTBegin)));
592 }
593 }
594
595 Args.addAllArgs(CmdArgs, {options::OPT_L});
596 TC.AddFilePathLibArgs(Args, CmdArgs);
597 Args.addAllArgs(CmdArgs, {options::OPT_u, options::OPT_T_Group,
598 options::OPT_s, options::OPT_t, options::OPT_r});
599
600 for (const auto &LibPath : TC.getLibraryPaths())
601 CmdArgs.push_back(Args.MakeArgString(llvm::Twine("-L", LibPath)));
602
603 if (D.isUsingLTO())
604 addLTOOptions(TC, Args, CmdArgs, Output, Inputs,
605 D.getLTOMode() == LTOK_Thin);
606
607 AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
608
609 if (TC.ShouldLinkCXXStdlib(Args)) {
610 bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) &&
611 !Args.hasArg(options::OPT_static);
612 if (OnlyLibstdcxxStatic)
613 CmdArgs.push_back("-Bstatic");
614 TC.AddCXXStdlibLibArgs(Args, CmdArgs);
615 if (OnlyLibstdcxxStatic)
616 CmdArgs.push_back("-Bdynamic");
617 CmdArgs.push_back("-lm");
618 }
619
620 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
621 CmdArgs.push_back("--start-group");
622 AddRunTimeLibs(TC, D, CmdArgs, Args);
623 if (!Args.hasArg(options::OPT_nolibc))
624 CmdArgs.push_back("-lc");
625 if (TC.hasValidGCCInstallation() || detectGCCToolchainAdjacent(D))
626 CmdArgs.push_back("-lgloss");
627 CmdArgs.push_back("--end-group");
628 }
629
630 if ((TC.hasValidGCCInstallation() || detectGCCToolchainAdjacent(D)) &&
631 NeedCRTs)
632 CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath(CRTEnd)));
633
634 // The R_ARM_TARGET2 relocation must be treated as R_ARM_REL32 on arm*-*-elf
635 // and arm*-*-eabi (the default is R_ARM_GOT_PREL, used on arm*-*-linux and
636 // arm*-*-*bsd).
637 if (arm::isARMEABIBareMetal(TC.getTriple()))
638 CmdArgs.push_back("--target2=rel");
639
640 CmdArgs.push_back("-o");
641 CmdArgs.push_back(Output.getFilename());
642
643 C.addCommand(std::make_unique<Command>(
645 Args.MakeArgString(TC.GetLinkerPath()), CmdArgs, Inputs, Output));
646}
647
648// BareMetal toolchain allows all sanitizers where the compiler generates valid
649// code, ignoring all runtime library support issues on the assumption that
650// baremetal targets typically implement their own runtime support.
652 const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64;
653 const bool IsAArch64 = getTriple().getArch() == llvm::Triple::aarch64 ||
654 getTriple().getArch() == llvm::Triple::aarch64_be;
655 const bool IsRISCV64 = getTriple().isRISCV64();
657 Res |= SanitizerKind::Address;
658 Res |= SanitizerKind::KernelAddress;
659 Res |= SanitizerKind::PointerCompare;
660 Res |= SanitizerKind::PointerSubtract;
661 Res |= SanitizerKind::Fuzzer;
662 Res |= SanitizerKind::FuzzerNoLink;
663 Res |= SanitizerKind::Vptr;
664 Res |= SanitizerKind::SafeStack;
665 Res |= SanitizerKind::Thread;
666 Res |= SanitizerKind::Scudo;
667 if (IsX86_64 || IsAArch64 || IsRISCV64) {
668 Res |= SanitizerKind::HWAddress;
669 Res |= SanitizerKind::KernelHWAddress;
670 }
671 return Res;
672}
static std::string computeClangRuntimesSysRoot(const Driver &D, bool IncludeTriple)
static bool isRISCVBareMetal(const llvm::Triple &Triple)
Definition BareMetal.cpp:33
static bool detectGCCToolchainAdjacent(const Driver &D)
static bool isPPCBareMetal(const llvm::Triple &Triple)
Is the triple powerpc[64][le]-*-none-eabi?
Definition BareMetal.cpp:47
static bool findRISCVMultilibs(const Driver &D, const llvm::Triple &TargetTriple, const ArgList &Args, DetectedMultilibs &Result)
Definition BareMetal.cpp:58
static void addMultilibsFilePaths(const Driver &D, const MultilibSet &Multilibs, const Multilib &Multilib, StringRef InstallPath, ToolChain::path_list &Paths)
static bool isX86BareMetal(const llvm::Triple &Triple)
Is the triple {ix86,x86_64}-*-none-elf?
Definition BareMetal.cpp:53
Compilation - A set of tasks to perform for a single driver invocation.
Definition Compilation.h:45
Driver - Encapsulate logic for constructing compilation processes from a set of gcc-driver-like comma...
Definition Driver.h:99
std::string SysRoot
sysroot, if present
Definition Driver.h:205
DiagnosticBuilder Diag(unsigned DiagID) const
Definition Driver.h:169
std::string Dir
The path the driver executable was in, as invoked from the command line.
Definition Driver.h:180
bool isUsingLTO() const
Returns true if we are performing any kind of LTO.
Definition Driver.h:744
std::string getTargetTriple() const
Definition Driver.h:438
LTOKind getLTOMode() const
Get the specific kind of LTO being performed.
Definition Driver.h:747
InputInfo - Wrapper for information about an input source.
Definition InputInfo.h:22
const char * getFilename() const
Definition InputInfo.h:83
bool isFilename() const
Definition InputInfo.h:75
This corresponds to a single GCC multilib, or a segment of one controlled by a command line flag.
MultilibBuilder & flag(StringRef Flag, bool Disallow=false)
Add a flag to the flags list Flag must be a flag accepted by the driver.
This class can be used to create a MultilibSet, and contains helper functions to add combinations of ...
MultilibSetBuilder & Either(const MultilibBuilder &M1, const MultilibBuilder &M2)
Add a set of mutually incompatible Multilib segments.
See also MultilibSetBuilder for combining multilibs into a set.
Definition Multilib.h:129
const IncludeDirsFunc & filePathsCallback() const
Definition Multilib.h:206
This corresponds to a single GCC Multilib, or a segment of one controlled by a command line flag.
Definition Multilib.h:35
std::vector< std::string > flags_list
Definition Multilib.h:37
const std::string & includeSuffix() const
Get the include directory suffix.
Definition Multilib.h:78
static void addSystemInclude(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, const Twine &Path)
Utility function to add a system include directory to CC1 arguments.
path_list & getFilePaths()
Definition ToolChain.h:317
const Driver & getDriver() const
Definition ToolChain.h:277
virtual std::string detectLibcxxVersion(StringRef IncludePath) const
bool loadMultilibsFromYAML(const llvm::opt::ArgList &Args, const Driver &D, StringRef Fallback={})
Discover and load a multilib.yaml configuration.
path_list & getProgramPaths()
Definition ToolChain.h:320
const llvm::Triple & getTriple() const
Definition ToolChain.h:279
virtual UnwindLibType GetUnwindLibType(const llvm::opt::ArgList &Args) const
OrderedMultilibs getOrderedMultilibs() const
Get selected multilibs in priority order with default fallback.
StringRef getTripleString() const
Definition ToolChain.h:302
virtual std::string getCompilerRTPath() const
std::optional< std::string > getStdlibIncludePath() const
virtual CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const
llvm::SmallVector< Multilib > SelectedMultilibs
Definition ToolChain.h:208
path_list & getLibraryPaths()
Definition ToolChain.h:314
virtual SanitizerMask getSupportedSanitizers() const
Return sanitizers which are available in this toolchain.
SmallVector< std::string, 16 > path_list
Definition ToolChain.h:94
Tool - Information on a specific compilation tool.
Definition Tool.h:32
const ToolChain & getToolChain() const
Definition Tool.h:52
std::string computeSysRoot() const override
Return the sysroot, possibly searching for a default sysroot using target-specific logic.
void addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override
BareMetal(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args)
SanitizerMask getSupportedSanitizers() const override
Return sanitizers which are available in this toolchain.
void AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override
AddClangCXXStdlibIncludeArgs - Add the clang -cc1 level arguments to set the include paths to use for...
static bool handlesTarget(const llvm::Triple &Triple)
UnwindLibType GetUnwindLibType(const llvm::opt::ArgList &Args) const override
void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override
Add the clang cc1 arguments for system include paths.
std::string getCompilerRTPath() const override
void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, Action::OffloadKind DeviceOffloadKind) const override
Add options that need to be passed to cc1 for this target.
Tool * buildStaticLibTool() const override
void findMultilibs(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args)
CXXStdlibType GetDefaultCXXStdlibType() const override
RuntimeLibType GetDefaultRuntimeLibType() const override
GetDefaultRuntimeLibType - Get the default runtime library variant to use.
bool initGCCInstallation(const llvm::Triple &Triple, const llvm::opt::ArgList &Args)
Tool * buildLinker() const override
Generic_ELF(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args)
Definition Gnu.h:439
GCCInstallationDetector GCCInstallation
Definition Gnu.h:357
bool addLibStdCXXIncludePaths(Twine IncludeDir, StringRef Triple, Twine IncludeSuffix, const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, bool DetectDebian=false) const
Definition Gnu.cpp:3344
void ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const override
ConstructJob - Construct jobs to perform the action JA, writing to Output and with Inputs,...
void ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const override
ConstructJob - Construct jobs to perform the action JA, writing to Output and with Inputs,...
bool isAArch64BareMetal(const llvm::Triple &Triple)
Is the triple {aarch64.aarch64_be}-none-elf?
Definition AArch64.cpp:531
void appendBE8LinkFlag(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs, const llvm::Triple &Triple)
bool isARMEABIBareMetal(const llvm::Triple &Triple)
Is the triple {arm,armeb,thumb,thumbeb}-none-none-{eabi,eabihf} ?
Definition ARM.cpp:55
bool isARMBigEndian(const llvm::Triple &Triple, const llvm::opt::ArgList &Args)
std::string getRISCVArch(const llvm::opt::ArgList &Args, const llvm::Triple &Triple)
Definition RISCV.cpp:239
StringRef getRISCVABI(const llvm::opt::ArgList &Args, const llvm::Triple &Triple)
bool getStaticPIE(const llvm::opt::ArgList &Args, const ToolChain &TC)
void addLTOOptions(const ToolChain &ToolChain, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs, const InputInfo &Output, const InputInfoList &Inputs, bool IsThinLTO)
void addMultilibFlag(bool Enabled, const StringRef Flag, Multilib::flags_list &Flags)
Flag must be a flag accepted by the driver.
void AddRunTimeLibs(const ToolChain &TC, const Driver &D, llvm::opt::ArgStringList &CmdArgs, const llvm::opt::ArgList &Args)
void addPathIfExists(const Driver &D, const Twine &Path, ToolChain::path_list &Paths)
void AddLinkerInputs(const ToolChain &TC, const InputInfoList &Inputs, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs, const JobAction &JA)
const char * getLDMOption(const llvm::Triple &T, const llvm::opt::ArgList &Args)
SmallVector< InputInfo, 4 > InputInfoList
Definition Driver.h:50
The JSON file list parser is used to communicate input to InstallAPI.
@ Result
The result type of a method or function.
Definition TypeBase.h:905
static constexpr ResponseFileSupport AtFileCurCP()
Definition Job.h:92
Struct to store and manipulate GCC versions.
Definition Gnu.h:163
int Major
The parsed major, minor, and patch numbers.
Definition Gnu.h:168
std::string Text
The unparsed text of the version.
Definition Gnu.h:165
static GCCVersion Parse(StringRef VersionText)
Parse a GCCVersion object out of a string of text.
Definition Gnu.cpp:1990