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 StringRef 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(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(Flags, Result.SelectedMultilibs); 96 } 97 return false; 98 } 99 100 BareMetal::BareMetal(const Driver &D, const llvm::Triple &Triple, 101 const ArgList &Args) 102 : ToolChain(D, Triple, Args) { 103 getProgramPaths().push_back(getDriver().getInstalledDir()); 104 if (getDriver().getInstalledDir() != getDriver().Dir) 105 getProgramPaths().push_back(getDriver().Dir); 106 107 findMultilibs(D, Triple, Args); 108 SmallString<128> SysRoot(computeSysRoot()); 109 if (!SysRoot.empty()) { 110 for (const Multilib &M : getOrderedMultilibs()) { 111 SmallString<128> Dir(SysRoot); 112 llvm::sys::path::append(Dir, M.osSuffix(), "lib"); 113 getFilePaths().push_back(std::string(Dir)); 114 getLibraryPaths().push_back(std::string(Dir)); 115 } 116 } 117 } 118 119 /// Is the triple {arm,armeb,thumb,thumbeb}-none-none-{eabi,eabihf} ? 120 static bool isARMBareMetal(const llvm::Triple &Triple) { 121 if (Triple.getArch() != llvm::Triple::arm && 122 Triple.getArch() != llvm::Triple::thumb && 123 Triple.getArch() != llvm::Triple::armeb && 124 Triple.getArch() != llvm::Triple::thumbeb) 125 return false; 126 127 if (Triple.getVendor() != llvm::Triple::UnknownVendor) 128 return false; 129 130 if (Triple.getOS() != llvm::Triple::UnknownOS) 131 return false; 132 133 if (Triple.getEnvironment() != llvm::Triple::EABI && 134 Triple.getEnvironment() != llvm::Triple::EABIHF) 135 return false; 136 137 return true; 138 } 139 140 /// Is the triple {aarch64.aarch64_be}-none-elf? 141 static bool isAArch64BareMetal(const llvm::Triple &Triple) { 142 if (Triple.getArch() != llvm::Triple::aarch64 && 143 Triple.getArch() != llvm::Triple::aarch64_be) 144 return false; 145 146 if (Triple.getVendor() != llvm::Triple::UnknownVendor) 147 return false; 148 149 if (Triple.getOS() != llvm::Triple::UnknownOS) 150 return false; 151 152 return Triple.getEnvironmentName() == "elf"; 153 } 154 155 static bool isRISCVBareMetal(const llvm::Triple &Triple) { 156 if (!Triple.isRISCV()) 157 return false; 158 159 if (Triple.getVendor() != llvm::Triple::UnknownVendor) 160 return false; 161 162 if (Triple.getOS() != llvm::Triple::UnknownOS) 163 return false; 164 165 return Triple.getEnvironmentName() == "elf"; 166 } 167 168 /// Is the triple powerpc[64][le]-*-none-eabi? 169 static bool isPPCBareMetal(const llvm::Triple &Triple) { 170 return Triple.isPPC() && Triple.getOS() == llvm::Triple::UnknownOS && 171 Triple.getEnvironment() == llvm::Triple::EABI; 172 } 173 174 static void findMultilibsFromYAML(const ToolChain &TC, const Driver &D, 175 StringRef MultilibPath, const ArgList &Args, 176 DetectedMultilibs &Result) { 177 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> MB = 178 D.getVFS().getBufferForFile(MultilibPath); 179 if (!MB) 180 return; 181 Multilib::flags_list Flags = TC.getMultilibFlags(Args); 182 llvm::ErrorOr<MultilibSet> ErrorOrMultilibSet = 183 MultilibSet::parseYaml(*MB.get()); 184 if (ErrorOrMultilibSet.getError()) 185 return; 186 Result.Multilibs = ErrorOrMultilibSet.get(); 187 if (Result.Multilibs.select(Flags, Result.SelectedMultilibs)) 188 return; 189 D.Diag(clang::diag::warn_drv_missing_multilib) << llvm::join(Flags, " "); 190 std::stringstream ss; 191 for (const Multilib &Multilib : Result.Multilibs) 192 ss << "\n" << llvm::join(Multilib.flags(), " "); 193 D.Diag(clang::diag::note_drv_available_multilibs) << ss.str(); 194 } 195 196 static constexpr llvm::StringLiteral MultilibFilename = "multilib.yaml"; 197 198 // Get the sysroot, before multilib takes effect. 199 static std::string computeBaseSysRoot(const Driver &D, 200 const llvm::Triple &Triple) { 201 if (!D.SysRoot.empty()) 202 return D.SysRoot; 203 204 SmallString<128> SysRootDir(D.Dir); 205 llvm::sys::path::append(SysRootDir, "..", "lib", "clang-runtimes"); 206 207 SmallString<128> MultilibPath(SysRootDir); 208 llvm::sys::path::append(MultilibPath, MultilibFilename); 209 210 // New behaviour: if multilib.yaml is found then use clang-runtimes as the 211 // sysroot. 212 if (D.getVFS().exists(MultilibPath)) 213 return std::string(SysRootDir); 214 215 // Otherwise fall back to the old behaviour of appending the target triple. 216 llvm::sys::path::append(SysRootDir, D.getTargetTriple()); 217 return std::string(SysRootDir); 218 } 219 220 void BareMetal::findMultilibs(const Driver &D, const llvm::Triple &Triple, 221 const ArgList &Args) { 222 DetectedMultilibs Result; 223 if (isRISCVBareMetal(Triple)) { 224 if (findRISCVMultilibs(D, Triple, Args, Result)) { 225 SelectedMultilibs = Result.SelectedMultilibs; 226 Multilibs = Result.Multilibs; 227 } 228 } else { 229 llvm::SmallString<128> MultilibPath(computeBaseSysRoot(D, Triple)); 230 llvm::sys::path::append(MultilibPath, MultilibFilename); 231 findMultilibsFromYAML(*this, D, MultilibPath, Args, Result); 232 SelectedMultilibs = Result.SelectedMultilibs; 233 Multilibs = Result.Multilibs; 234 } 235 } 236 237 bool BareMetal::handlesTarget(const llvm::Triple &Triple) { 238 return isARMBareMetal(Triple) || isAArch64BareMetal(Triple) || 239 isRISCVBareMetal(Triple) || isPPCBareMetal(Triple); 240 } 241 242 Tool *BareMetal::buildLinker() const { 243 return new tools::baremetal::Linker(*this); 244 } 245 246 Tool *BareMetal::buildStaticLibTool() const { 247 return new tools::baremetal::StaticLibTool(*this); 248 } 249 250 std::string BareMetal::computeSysRoot() const { 251 return computeBaseSysRoot(getDriver(), getTriple()); 252 } 253 254 BareMetal::OrderedMultilibs BareMetal::getOrderedMultilibs() const { 255 // Get multilibs in reverse order because they're ordered most-specific last. 256 if (!SelectedMultilibs.empty()) 257 return llvm::reverse(SelectedMultilibs); 258 259 // No multilibs selected so return a single default multilib. 260 static const llvm::SmallVector<Multilib> Default = {Multilib()}; 261 return llvm::reverse(Default); 262 } 263 264 void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs, 265 ArgStringList &CC1Args) const { 266 if (DriverArgs.hasArg(options::OPT_nostdinc)) 267 return; 268 269 if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { 270 SmallString<128> Dir(getDriver().ResourceDir); 271 llvm::sys::path::append(Dir, "include"); 272 addSystemInclude(DriverArgs, CC1Args, Dir.str()); 273 } 274 275 if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) { 276 const SmallString<128> SysRoot(computeSysRoot()); 277 if (!SysRoot.empty()) { 278 for (const Multilib &M : getOrderedMultilibs()) { 279 SmallString<128> Dir(SysRoot); 280 llvm::sys::path::append(Dir, M.includeSuffix()); 281 llvm::sys::path::append(Dir, "include"); 282 addSystemInclude(DriverArgs, CC1Args, Dir.str()); 283 } 284 } 285 } 286 } 287 288 void BareMetal::addClangTargetOptions(const ArgList &DriverArgs, 289 ArgStringList &CC1Args, 290 Action::OffloadKind) const { 291 CC1Args.push_back("-nostdsysteminc"); 292 } 293 294 void BareMetal::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, 295 ArgStringList &CC1Args) const { 296 if (DriverArgs.hasArg(options::OPT_nostdinc) || 297 DriverArgs.hasArg(options::OPT_nostdlibinc) || 298 DriverArgs.hasArg(options::OPT_nostdincxx)) 299 return; 300 301 const Driver &D = getDriver(); 302 std::string SysRoot(computeSysRoot()); 303 if (SysRoot.empty()) 304 return; 305 306 for (const Multilib &M : getOrderedMultilibs()) { 307 SmallString<128> Dir(SysRoot); 308 llvm::sys::path::append(Dir, M.gccSuffix()); 309 switch (GetCXXStdlibType(DriverArgs)) { 310 case ToolChain::CST_Libcxx: { 311 // First check sysroot/usr/include/c++/v1 if it exists. 312 SmallString<128> TargetDir(Dir); 313 llvm::sys::path::append(TargetDir, "usr", "include", "c++", "v1"); 314 if (D.getVFS().exists(TargetDir)) { 315 addSystemInclude(DriverArgs, CC1Args, TargetDir.str()); 316 break; 317 } 318 // Add generic path if nothing else succeeded so far. 319 llvm::sys::path::append(Dir, "include", "c++", "v1"); 320 addSystemInclude(DriverArgs, CC1Args, Dir.str()); 321 break; 322 } 323 case ToolChain::CST_Libstdcxx: { 324 llvm::sys::path::append(Dir, "include", "c++"); 325 std::error_code EC; 326 Generic_GCC::GCCVersion Version = {"", -1, -1, -1, "", "", ""}; 327 // Walk the subdirs, and find the one with the newest gcc version: 328 for (llvm::vfs::directory_iterator 329 LI = D.getVFS().dir_begin(Dir.str(), EC), 330 LE; 331 !EC && LI != LE; LI = LI.increment(EC)) { 332 StringRef VersionText = llvm::sys::path::filename(LI->path()); 333 auto CandidateVersion = Generic_GCC::GCCVersion::Parse(VersionText); 334 if (CandidateVersion.Major == -1) 335 continue; 336 if (CandidateVersion <= Version) 337 continue; 338 Version = CandidateVersion; 339 } 340 if (Version.Major != -1) { 341 llvm::sys::path::append(Dir, Version.Text); 342 addSystemInclude(DriverArgs, CC1Args, Dir.str()); 343 } 344 break; 345 } 346 } 347 } 348 } 349 350 void BareMetal::AddCXXStdlibLibArgs(const ArgList &Args, 351 ArgStringList &CmdArgs) const { 352 switch (GetCXXStdlibType(Args)) { 353 case ToolChain::CST_Libcxx: 354 CmdArgs.push_back("-lc++"); 355 if (Args.hasArg(options::OPT_fexperimental_library)) 356 CmdArgs.push_back("-lc++experimental"); 357 CmdArgs.push_back("-lc++abi"); 358 break; 359 case ToolChain::CST_Libstdcxx: 360 CmdArgs.push_back("-lstdc++"); 361 CmdArgs.push_back("-lsupc++"); 362 break; 363 } 364 CmdArgs.push_back("-lunwind"); 365 } 366 367 void BareMetal::AddLinkRuntimeLib(const ArgList &Args, 368 ArgStringList &CmdArgs) const { 369 ToolChain::RuntimeLibType RLT = GetRuntimeLibType(Args); 370 switch (RLT) { 371 case ToolChain::RLT_CompilerRT: { 372 const std::string FileName = getCompilerRT(Args, "builtins"); 373 llvm::StringRef BaseName = llvm::sys::path::filename(FileName); 374 BaseName.consume_front("lib"); 375 BaseName.consume_back(".a"); 376 CmdArgs.push_back(Args.MakeArgString("-l" + BaseName)); 377 return; 378 } 379 case ToolChain::RLT_Libgcc: 380 CmdArgs.push_back("-lgcc"); 381 return; 382 } 383 llvm_unreachable("Unhandled RuntimeLibType."); 384 } 385 386 void baremetal::StaticLibTool::ConstructJob(Compilation &C, const JobAction &JA, 387 const InputInfo &Output, 388 const InputInfoList &Inputs, 389 const ArgList &Args, 390 const char *LinkingOutput) const { 391 const Driver &D = getToolChain().getDriver(); 392 393 // Silence warning for "clang -g foo.o -o foo" 394 Args.ClaimAllArgs(options::OPT_g_Group); 395 // and "clang -emit-llvm foo.o -o foo" 396 Args.ClaimAllArgs(options::OPT_emit_llvm); 397 // and for "clang -w foo.o -o foo". Other warning options are already 398 // handled somewhere else. 399 Args.ClaimAllArgs(options::OPT_w); 400 // Silence warnings when linking C code with a C++ '-stdlib' argument. 401 Args.ClaimAllArgs(options::OPT_stdlib_EQ); 402 403 // ar tool command "llvm-ar <options> <output_file> <input_files>". 404 ArgStringList CmdArgs; 405 // Create and insert file members with a deterministic index. 406 CmdArgs.push_back("rcsD"); 407 CmdArgs.push_back(Output.getFilename()); 408 409 for (const auto &II : Inputs) { 410 if (II.isFilename()) { 411 CmdArgs.push_back(II.getFilename()); 412 } 413 } 414 415 // Delete old output archive file if it already exists before generating a new 416 // archive file. 417 const char *OutputFileName = Output.getFilename(); 418 if (Output.isFilename() && llvm::sys::fs::exists(OutputFileName)) { 419 if (std::error_code EC = llvm::sys::fs::remove(OutputFileName)) { 420 D.Diag(diag::err_drv_unable_to_remove_file) << EC.message(); 421 return; 422 } 423 } 424 425 const char *Exec = Args.MakeArgString(getToolChain().GetStaticLibToolPath()); 426 C.addCommand(std::make_unique<Command>(JA, *this, 427 ResponseFileSupport::AtFileCurCP(), 428 Exec, CmdArgs, Inputs, Output)); 429 } 430 431 void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA, 432 const InputInfo &Output, 433 const InputInfoList &Inputs, 434 const ArgList &Args, 435 const char *LinkingOutput) const { 436 ArgStringList CmdArgs; 437 438 auto &TC = static_cast<const toolchains::BareMetal &>(getToolChain()); 439 const llvm::Triple::ArchType Arch = TC.getArch(); 440 const llvm::Triple &Triple = getToolChain().getEffectiveTriple(); 441 442 AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA); 443 444 CmdArgs.push_back("-Bstatic"); 445 446 if (Triple.isARM() || Triple.isThumb()) { 447 bool IsBigEndian = arm::isARMBigEndian(Triple, Args); 448 if (IsBigEndian) 449 arm::appendBE8LinkFlag(Args, CmdArgs, Triple); 450 CmdArgs.push_back(IsBigEndian ? "-EB" : "-EL"); 451 } else if (Triple.isAArch64()) { 452 CmdArgs.push_back(Arch == llvm::Triple::aarch64_be ? "-EB" : "-EL"); 453 } 454 455 Args.AddAllArgs(CmdArgs, 456 {options::OPT_L, options::OPT_T_Group, options::OPT_s, 457 options::OPT_t, options::OPT_Z_Flag, options::OPT_r}); 458 459 TC.AddFilePathLibArgs(Args, CmdArgs); 460 461 for (const auto &LibPath : TC.getLibraryPaths()) 462 CmdArgs.push_back(Args.MakeArgString(llvm::Twine("-L", LibPath))); 463 464 const std::string FileName = TC.getCompilerRT(Args, "builtins"); 465 llvm::SmallString<128> PathBuf{FileName}; 466 llvm::sys::path::remove_filename(PathBuf); 467 CmdArgs.push_back(Args.MakeArgString("-L" + PathBuf)); 468 469 if (TC.ShouldLinkCXXStdlib(Args)) 470 TC.AddCXXStdlibLibArgs(Args, CmdArgs); 471 472 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { 473 CmdArgs.push_back("-lc"); 474 CmdArgs.push_back("-lm"); 475 476 TC.AddLinkRuntimeLib(Args, CmdArgs); 477 } 478 479 if (TC.getTriple().isRISCV()) 480 CmdArgs.push_back("-X"); 481 482 // The R_ARM_TARGET2 relocation must be treated as R_ARM_REL32 on arm*-*-elf 483 // and arm*-*-eabi (the default is R_ARM_GOT_PREL, used on arm*-*-linux and 484 // arm*-*-*bsd). 485 if (isARMBareMetal(TC.getTriple())) 486 CmdArgs.push_back("--target2=rel"); 487 488 CmdArgs.push_back("-o"); 489 CmdArgs.push_back(Output.getFilename()); 490 491 C.addCommand(std::make_unique<Command>( 492 JA, *this, ResponseFileSupport::AtFileCurCP(), 493 Args.MakeArgString(TC.GetLinkerPath()), CmdArgs, Inputs, Output)); 494 } 495