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
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) {
64 std::string Arch = riscv::getRISCVArch(Args, TargetTriple);
65 StringRef Abi = tools::riscv::getRISCVABI(Args, TargetTriple);
66
67 if (TargetTriple.isRISCV64()) {
68 MultilibBuilder Imac =
69 MultilibBuilder().flag("-march=rv64imac").flag("-mabi=lp64");
70 MultilibBuilder Imafdc = MultilibBuilder("/rv64imafdc/lp64d")
71 .flag("-march=rv64imafdc")
72 .flag("-mabi=lp64d");
73
74 // Multilib reuse
75 bool UseImafdc =
76 (Arch == "rv64imafdc") || (Arch == "rv64gc"); // gc => imafdc
77
78 addMultilibFlag((Arch == "rv64imac"), "-march=rv64imac", Flags);
79 addMultilibFlag(UseImafdc, "-march=rv64imafdc", Flags);
80 addMultilibFlag(Abi == "lp64", "-mabi=lp64", Flags);
81 addMultilibFlag(Abi == "lp64d", "-mabi=lp64d", Flags);
82
83 Result.Multilibs =
85 return Result.Multilibs.select(D, Flags, Result.SelectedMultilibs);
86 }
87 if (TargetTriple.isRISCV32()) {
88 MultilibBuilder Imac =
89 MultilibBuilder().flag("-march=rv32imac").flag("-mabi=ilp32");
90 MultilibBuilder I = MultilibBuilder("/rv32i/ilp32")
91 .flag("-march=rv32i")
92 .flag("-mabi=ilp32");
93 MultilibBuilder Im = MultilibBuilder("/rv32im/ilp32")
94 .flag("-march=rv32im")
95 .flag("-mabi=ilp32");
96 MultilibBuilder Iac = MultilibBuilder("/rv32iac/ilp32")
97 .flag("-march=rv32iac")
98 .flag("-mabi=ilp32");
99 MultilibBuilder Imafc = MultilibBuilder("/rv32imafc/ilp32f")
100 .flag("-march=rv32imafc")
101 .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(UseI, "-march=rv32i", Flags);
110 addMultilibFlag(UseIm, "-march=rv32im", Flags);
111 addMultilibFlag((Arch == "rv32iac"), "-march=rv32iac", Flags);
112 addMultilibFlag((Arch == "rv32imac"), "-march=rv32imac", Flags);
113 addMultilibFlag(UseImafc, "-march=rv32imafc", Flags);
114 addMultilibFlag(Abi == "ilp32", "-mabi=ilp32", Flags);
115 addMultilibFlag(Abi == "ilp32f", "-mabi=ilp32f", Flags);
116
117 Result.Multilibs =
118 MultilibSetBuilder().Either(I, Im, Iac, Imac, 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(SysRootDir, "..", "lib", "clang-runtimes");
131
132 if (IncludeTriple)
133 llvm::sys::path::append(SysRootDir, 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(options::OPT_gcc_toolchain) ||
144 Args.getLastArg(clang::options::OPT_gcc_install_dir_EQ)) {
145 GCCInstallation.init(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(GCCDir, D.Dir, "..", D.getTargetTriple(),
158 "lib/crt0.o");
159 return llvm::sys::fs::exists(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(inferredSysRoot, GCCInstallation.getParentLibPath(),
187 "..", 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(inferredSysRoot, D.Dir, "..", D.getTargetTriple());
192 }
193 // If a valid sysroot was inferred and exists, use it
194 if (!inferredSysRoot.empty() && llvm::sys::fs::exists(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(getDriver())) {
204 SmallString<128> Path(D.ResourceDir);
205 llvm::sys::path::append(Path, "lib");
206 return std::string(Path.str());
207 }
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, 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(clang::diag::warn_drv_multilib_not_available_for_target);
232
233 Multilibs = GCCInstallation.getMultilibs();
234 SelectedMultilibs.assign({GCCInstallation.getMultilib()});
235
236 path_list &Paths = getFilePaths();
237 // Add toolchain/multilib specific file paths.
239 GCCInstallation.getInstallPath(), Paths);
240 // Adding filepath for locating crt{begin,end}.o files.
241 Paths.push_back(GCCInstallation.getInstallPath().str());
242 // Adding filepath for locating crt0.o file.
243 Paths.push_back(ComputedSysRoot + "/lib");
244
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(Twine(GCCInstallation.getParentLibPath() + "/../" +
249 GCCInstallation.getTriple().str() + "/bin")
250 .str());
251 PPaths.push_back((GCCInstallation.getParentLibPath() + "/../bin").str());
252 } else {
253 getProgramPaths().push_back(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(Dir, M.osSuffix(), "lib");
260 getFilePaths().push_back(std::string(Dir));
261 getLibraryPaths().push_back(std::string(Dir));
262 }
263 }
264 }
265}
266
267static void
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(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(clang::diag::warn_drv_missing_multilib) << llvm::join(Flags, " ");
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(Multilib.flags(), " ");
293 D.Diag(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(clang::diag::err_drv_multilib_custom_error)
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(options::OPT_multi_lib_config)) {
317 MultilibPath = ConfigFileArg->getValue();
318 if (!D.getVFS().exists(MultilibPath)) {
319 D.Diag(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(MultilibPath, MultilibFilename);
325 }
326 return MultilibPath;
327}
328
329void BareMetal::findMultilibs(const Driver &D, const llvm::Triple &Triple,
330 const ArgList &Args) {
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(*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(*this, D, *MultilibPath, Args, Result,
344 CustomFlagMacroDefines);
345 SelectedMultilibs = Result.SelectedMultilibs;
346 Multilibs = Result.Multilibs;
347 MultilibMacroDefines.append(CustomFlagMacroDefines.begin(),
348 CustomFlagMacroDefines.end());
349 } else if (isRISCVBareMetal(Triple) && !detectGCCToolchainAdjacent(D)) {
350 if (findRISCVMultilibs(D, 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) ||
360 isPPCBareMetal(Triple) || isX86BareMetal(Triple);
361}
362
364 return new tools::baremetal::Linker(*this);
365}
366
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(SelectedMultilibs);
375
376 // No multilibs selected so return a single default multilib.
378 return llvm::reverse(Default);
379}
380
382 if (getTriple().isRISCV() && IsGCCInstallationValid)
385}
386
388 if (getTriple().isRISCV() && IsGCCInstallationValid)
391}
392
393// TODO: Add a validity check for GCCInstallation.
394// If valid, use `UNW_Libgcc`; otherwise, use `UNW_None`.
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(options::OPT_nostdinc))
406 return;
407
408 if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
409 SmallString<128> Dir(getDriver().ResourceDir);
410 llvm::sys::path::append(Dir, "include");
411 addSystemInclude(DriverArgs, CC1Args, Dir.str());
412 }
413
414 if (DriverArgs.hasArg(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);
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(Dir, M.includeSuffix());
427 llvm::sys::path::append(Dir, "include");
428 addSystemInclude(DriverArgs, CC1Args, Dir.str());
429 }
430 SmallString<128> Dir(SysRootDir);
431 llvm::sys::path::append(Dir, getTripleString());
432 if (D.getVFS().exists(Dir)) {
433 llvm::sys::path::append(Dir, "include");
434 addSystemInclude(DriverArgs, CC1Args, Dir.str());
435 }
436 }
437}
438
439void BareMetal::addClangTargetOptions(const ArgList &DriverArgs,
440 ArgStringList &CC1Args,
441 Action::OffloadKind) const {
442 CC1Args.push_back("-nostdsysteminc");
443}
444
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(computeSysRoot() + "/include/c++/" + Version.Text,
454 TripleStr, Multilib.includeSuffix(), DriverArgs,
455 CC1Args);
456}
457
458void BareMetal::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
459 ArgStringList &CC1Args) const {
460 if (DriverArgs.hasArg(options::OPT_nostdinc, options::OPT_nostdlibinc,
461 options::OPT_nostdincxx))
462 return;
463
464 const Driver &D = getDriver();
465 std::string Target = getTripleString();
466
467 auto AddCXXIncludePath = [&](StringRef Path) {
468 std::string Version = detectLibcxxVersion(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(TargetDir, Target, "c++", Version);
476 addSystemInclude(DriverArgs, CC1Args, TargetDir);
477 }
478
479 {
480 // Then the generic dir: include/c++/v1.
481 SmallString<128> Dir(Path);
482 llvm::sys::path::append(Dir, "c++", Version);
483 addSystemInclude(DriverArgs, CC1Args, Dir);
484 }
485 };
486
487 switch (GetCXXStdlibType(DriverArgs)) {
489 SmallString<128> P(D.Dir);
490 llvm::sys::path::append(P, "..", "include");
491 AddCXXIncludePath(P);
492 break;
493 }
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(Dir, M.gccSuffix());
506 switch (GetCXXStdlibType(DriverArgs)) {
508 // First check sysroot/usr/include/c++/v1 if it exists.
509 SmallString<128> TargetDir(Dir);
510 llvm::sys::path::append(TargetDir, "usr", "include", "c++", "v1");
511 if (D.getVFS().exists(TargetDir)) {
512 addSystemInclude(DriverArgs, CC1Args, TargetDir.str());
513 break;
514 }
515 // Add generic paths if nothing else succeeded so far.
516 llvm::sys::path::append(Dir, "include", "c++", "v1");
517 addSystemInclude(DriverArgs, CC1Args, Dir.str());
518 break;
519 }
521 llvm::sys::path::append(Dir, "include", "c++");
522 std::error_code EC;
523 Generic_GCC::GCCVersion Version = {"", -1, -1, -1, "", "", ""};
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.str(), EC),
527 LE;
528 !EC && LI != LE; LI = LI.increment(EC)) {
529 StringRef VersionText = llvm::sys::path::filename(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(Dir, Version.Text);
539 addSystemInclude(DriverArgs, CC1Args, Dir.str());
540 }
541 break;
542 }
543 }
544 }
545 switch (GetCXXStdlibType(DriverArgs)) {
547 SmallString<128> Dir(SysRootDir);
548 llvm::sys::path::append(Dir, Target, "include", "c++", "v1");
549 if (D.getVFS().exists(Dir))
550 addSystemInclude(DriverArgs, CC1Args, Dir.str());
551 break;
552 }
554 break;
555 }
556}
557
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(options::OPT_g_Group);
567 // and "clang -emit-llvm foo.o -o foo"
568 Args.ClaimAllArgs(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(options::OPT_w);
572 // Silence warnings when linking C code with a C++ '-stdlib' argument.
573 Args.ClaimAllArgs(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("rcsD");
579 CmdArgs.push_back(Output.getFilename());
580
581 for (const auto &II : Inputs) {
582 if (II.isFilename()) {
583 CmdArgs.push_back(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(OutputFileName)) {
591 if (std::error_code EC = llvm::sys::fs::remove(OutputFileName)) {
592 D.Diag(diag::err_drv_unable_to_remove_file) << EC.message();
593 return;
594 }
595 }
596
597 const char *Exec = Args.MakeArgString(getToolChain().GetStaticLibToolPath());
598 C.addCommand(std::make_unique<Command>(JA, *this,
600 Exec, CmdArgs, Inputs, Output));
601}
602
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(Args.MakeArgString("--sysroot=" + D.SysRoot));
618
619 CmdArgs.push_back("-Bstatic");
620 if (IsStaticPIE) {
621 CmdArgs.push_back("-pie");
622 CmdArgs.push_back("--no-dynamic-linker");
623 CmdArgs.push_back("-z");
624 CmdArgs.push_back("text");
625 }
626
627 if (const char *LDMOption = getLDMOption(TC.getTriple(), Args)) {
628 CmdArgs.push_back("-m");
629 CmdArgs.push_back(LDMOption);
630 } else {
631 D.Diag(diag::err_target_unknown_triple) << Triple.str();
632 return;
633 }
634
635 if (Triple.isRISCV()) {
636 CmdArgs.push_back("-X");
637 if (Args.hasArg(options::OPT_mno_relax))
638 CmdArgs.push_back("--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(IsBigEndian ? "-EB" : "-EL");
646 } else if (Triple.isAArch64()) {
647 CmdArgs.push_back(Arch == llvm::Triple::aarch64_be ? "-EB" : "-EL");
648 }
649
650 bool NeedCRTs =
651 !Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles);
652
653 const char *CRTBegin, *CRTEnd;
654 if (NeedCRTs) {
655 if (!Args.hasArg(options::OPT_r)) {
656 const char *crt = "crt0.o";
657 if (IsStaticPIE)
658 crt = "rcrt1.o";
659 CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath(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 }
670 CRTBegin =
671 TC.getCompilerRTArgString(Args, "crtbegin", ToolChain::FT_Object);
672 CRTEnd =
673 TC.getCompilerRTArgString(Args, "crtend", ToolChain::FT_Object);
674 break;
675 }
676 }
677 CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath(CRTBegin)));
678 }
679 }
680
681 Args.addAllArgs(CmdArgs, {options::OPT_L});
682 TC.AddFilePathLibArgs(Args, CmdArgs);
683 Args.addAllArgs(CmdArgs, {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(Args.MakeArgString(llvm::Twine("-L", LibPath)));
688
689 if (D.isUsingLTO())
690 addLTOOptions(TC, Args, CmdArgs, Output, Inputs,
691 D.getLTOMode() == LTOK_Thin);
692
693 AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
694
695 if (TC.ShouldLinkCXXStdlib(Args)) {
696 bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) &&
697 !Args.hasArg(options::OPT_static);
698 if (OnlyLibstdcxxStatic)
699 CmdArgs.push_back("-Bstatic");
700 TC.AddCXXStdlibLibArgs(Args, CmdArgs);
701 if (OnlyLibstdcxxStatic)
702 CmdArgs.push_back("-Bdynamic");
703 CmdArgs.push_back("-lm");
704 }
705
706 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
707 CmdArgs.push_back("--start-group");
708 AddRunTimeLibs(TC, D, CmdArgs, Args);
709 if (!Args.hasArg(options::OPT_nolibc))
710 CmdArgs.push_back("-lc");
711 if (TC.hasValidGCCInstallation() || detectGCCToolchainAdjacent(D))
712 CmdArgs.push_back("-lgloss");
713 CmdArgs.push_back("--end-group");
714 }
715
716 if ((TC.hasValidGCCInstallation() || detectGCCToolchainAdjacent(D)) &&
717 NeedCRTs)
718 CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath(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(TC.getTriple()))
724 CmdArgs.push_back("--target2=rel");
725
726 CmdArgs.push_back("-o");
727 CmdArgs.push_back(Output.getFilename());
728
729 C.addCommand(std::make_unique<Command>(
731 Args.MakeArgString(TC.GetLinkerPath()), CmdArgs, Inputs, 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.
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();
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
761BareMetal::getMultilibMacroDefinesStr(llvm::opt::ArgList &Args) const {
762 return MultilibMacroDefines;
763}
static std::string computeClangRuntimesSysRoot(const Driver &D, bool IncludeTriple)
static bool isRISCVBareMetal(const llvm::Triple &Triple)
Definition BareMetal.cpp:35
static std::optional< llvm::SmallString< 128 > > getMultilibConfigPath(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
static constexpr llvm::StringLiteral MultilibFilename
static bool detectGCCToolchainAdjacent(const Driver &D)
static bool isPPCBareMetal(const llvm::Triple &Triple)
Is the triple powerpc[64][le]-*-none-eabi?
Definition BareMetal.cpp:49
static void findMultilibsFromYAML(const ToolChain &TC, const Driver &D, StringRef MultilibPath, const ArgList &Args, DetectedMultilibs &Result, SmallVector< StringRef > &CustomFlagsMacroDefines)
static bool findRISCVMultilibs(const Driver &D, const llvm::Triple &TargetTriple, const ArgList &Args, DetectedMultilibs &Result)
Definition BareMetal.cpp:60
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:55
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
llvm::vfs::FileSystem & getVFS() const
Definition Driver.h:421
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:740
std::string getTargetTriple() const
Definition Driver.h:438
LTOKind getLTOMode() const
Get the specific kind of LTO being performed.
Definition Driver.h:743
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
static llvm::ErrorOr< MultilibSet > parseYaml(llvm::MemoryBufferRef, llvm::SourceMgr::DiagHandlerTy=nullptr, void *DiagHandlerCtxt=nullptr)
Definition Multilib.cpp:479
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
const std::string & getErrorMessage() const
Definition Multilib.h:99
const flags_list & flags() const
Get the flags that indicate or contraindicate this multilib's use All elements begin with either '-' ...
Definition Multilib.h:82
std::vector< std::string > flags_list
Definition Multilib.h:37
const std::string & includeSuffix() const
Get the include directory suffix.
Definition Multilib.h:78
bool isError() const
Definition Multilib.h:97
ToolChain - Access to tools for a single platform.
Definition ToolChain.h:92
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:303
const Driver & getDriver() const
Definition ToolChain.h:261
virtual std::string detectLibcxxVersion(StringRef IncludePath) const
Multilib::flags_list getMultilibFlags(const llvm::opt::ArgList &) const
Get flags suitable for multilib selection, based on the provided clang command line arguments.
path_list & getProgramPaths()
Definition ToolChain.h:306
const llvm::Triple & getTriple() const
Definition ToolChain.h:263
virtual UnwindLibType GetUnwindLibType(const llvm::opt::ArgList &Args) const
virtual std::string getCompilerRTPath() const
std::optional< std::string > getStdlibIncludePath() const
std::string getTripleString() const
Definition ToolChain.h:286
virtual CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const
llvm::SmallVector< Multilib > SelectedMultilibs
Definition ToolChain.h:208
path_list & getLibraryPaths()
Definition ToolChain.h:300
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
SmallVector< std::string > getMultilibMacroDefinesStr(llvm::opt::ArgList &Args) 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:3345
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