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