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/RISCV.h" 16 #include "clang/Driver/Compilation.h" 17 #include "clang/Driver/Driver.h" 18 #include "clang/Driver/DriverDiagnostic.h" 19 #include "clang/Driver/Options.h" 20 #include "llvm/Option/ArgList.h" 21 #include "llvm/Support/Path.h" 22 #include "llvm/Support/VirtualFileSystem.h" 23 #include "llvm/Support/raw_ostream.h" 24 25 using namespace llvm::opt; 26 using namespace clang; 27 using namespace clang::driver; 28 using namespace clang::driver::tools; 29 using namespace clang::driver::toolchains; 30 31 static Multilib makeMultilib(StringRef commonSuffix) { 32 return Multilib(commonSuffix, commonSuffix, commonSuffix); 33 } 34 35 static bool findRISCVMultilibs(const Driver &D, 36 const llvm::Triple &TargetTriple, 37 const ArgList &Args, DetectedMultilibs &Result) { 38 Multilib::flags_list Flags; 39 StringRef Arch = riscv::getRISCVArch(Args, TargetTriple); 40 StringRef Abi = tools::riscv::getRISCVABI(Args, TargetTriple); 41 42 if (TargetTriple.isRISCV64()) { 43 Multilib Imac = makeMultilib("").flag("+march=rv64imac").flag("+mabi=lp64"); 44 Multilib Imafdc = makeMultilib("/rv64imafdc/lp64d") 45 .flag("+march=rv64imafdc") 46 .flag("+mabi=lp64d"); 47 48 // Multilib reuse 49 bool UseImafdc = 50 (Arch == "rv64imafdc") || (Arch == "rv64gc"); // gc => imafdc 51 52 addMultilibFlag((Arch == "rv64imac"), "march=rv64imac", Flags); 53 addMultilibFlag(UseImafdc, "march=rv64imafdc", Flags); 54 addMultilibFlag(Abi == "lp64", "mabi=lp64", Flags); 55 addMultilibFlag(Abi == "lp64d", "mabi=lp64d", Flags); 56 57 Result.Multilibs = MultilibSet().Either(Imac, Imafdc); 58 return Result.Multilibs.select(Flags, Result.SelectedMultilib); 59 } 60 if (TargetTriple.isRISCV32()) { 61 Multilib Imac = 62 makeMultilib("").flag("+march=rv32imac").flag("+mabi=ilp32"); 63 Multilib I = 64 makeMultilib("/rv32i/ilp32").flag("+march=rv32i").flag("+mabi=ilp32"); 65 Multilib Im = 66 makeMultilib("/rv32im/ilp32").flag("+march=rv32im").flag("+mabi=ilp32"); 67 Multilib Iac = makeMultilib("/rv32iac/ilp32") 68 .flag("+march=rv32iac") 69 .flag("+mabi=ilp32"); 70 Multilib Imafc = makeMultilib("/rv32imafc/ilp32f") 71 .flag("+march=rv32imafc") 72 .flag("+mabi=ilp32f"); 73 74 // Multilib reuse 75 bool UseI = (Arch == "rv32i") || (Arch == "rv32ic"); // ic => i 76 bool UseIm = (Arch == "rv32im") || (Arch == "rv32imc"); // imc => im 77 bool UseImafc = (Arch == "rv32imafc") || (Arch == "rv32imafdc") || 78 (Arch == "rv32gc"); // imafdc,gc => imafc 79 80 addMultilibFlag(UseI, "march=rv32i", Flags); 81 addMultilibFlag(UseIm, "march=rv32im", Flags); 82 addMultilibFlag((Arch == "rv32iac"), "march=rv32iac", Flags); 83 addMultilibFlag((Arch == "rv32imac"), "march=rv32imac", Flags); 84 addMultilibFlag(UseImafc, "march=rv32imafc", Flags); 85 addMultilibFlag(Abi == "ilp32", "mabi=ilp32", Flags); 86 addMultilibFlag(Abi == "ilp32f", "mabi=ilp32f", Flags); 87 88 Result.Multilibs = MultilibSet().Either(I, Im, Iac, Imac, Imafc); 89 return Result.Multilibs.select(Flags, Result.SelectedMultilib); 90 } 91 return false; 92 } 93 94 BareMetal::BareMetal(const Driver &D, const llvm::Triple &Triple, 95 const ArgList &Args) 96 : ToolChain(D, Triple, Args) { 97 getProgramPaths().push_back(getDriver().getInstalledDir()); 98 if (getDriver().getInstalledDir() != getDriver().Dir) 99 getProgramPaths().push_back(getDriver().Dir); 100 101 findMultilibs(D, Triple, Args); 102 SmallString<128> SysRoot(computeSysRoot()); 103 if (!SysRoot.empty()) { 104 llvm::sys::path::append(SysRoot, "lib"); 105 getFilePaths().push_back(std::string(SysRoot)); 106 getLibraryPaths().push_back(std::string(SysRoot)); 107 } 108 } 109 110 /// Is the triple {arm,thumb}-none-none-{eabi,eabihf} ? 111 static bool isARMBareMetal(const llvm::Triple &Triple) { 112 if (Triple.getArch() != llvm::Triple::arm && 113 Triple.getArch() != llvm::Triple::thumb) 114 return false; 115 116 if (Triple.getVendor() != llvm::Triple::UnknownVendor) 117 return false; 118 119 if (Triple.getOS() != llvm::Triple::UnknownOS) 120 return false; 121 122 if (Triple.getEnvironment() != llvm::Triple::EABI && 123 Triple.getEnvironment() != llvm::Triple::EABIHF) 124 return false; 125 126 return true; 127 } 128 129 /// Is the triple aarch64-none-elf? 130 static bool isAArch64BareMetal(const llvm::Triple &Triple) { 131 if (Triple.getArch() != llvm::Triple::aarch64) 132 return false; 133 134 if (Triple.getVendor() != llvm::Triple::UnknownVendor) 135 return false; 136 137 if (Triple.getOS() != llvm::Triple::UnknownOS) 138 return false; 139 140 return Triple.getEnvironmentName() == "elf"; 141 } 142 143 static bool isRISCVBareMetal(const llvm::Triple &Triple) { 144 if (!Triple.isRISCV()) 145 return false; 146 147 if (Triple.getVendor() != llvm::Triple::UnknownVendor) 148 return false; 149 150 if (Triple.getOS() != llvm::Triple::UnknownOS) 151 return false; 152 153 return Triple.getEnvironmentName() == "elf"; 154 } 155 156 void BareMetal::findMultilibs(const Driver &D, const llvm::Triple &Triple, 157 const ArgList &Args) { 158 DetectedMultilibs Result; 159 if (isRISCVBareMetal(Triple)) { 160 if (findRISCVMultilibs(D, Triple, Args, Result)) { 161 SelectedMultilib = Result.SelectedMultilib; 162 Multilibs = Result.Multilibs; 163 } 164 } 165 } 166 167 bool BareMetal::handlesTarget(const llvm::Triple &Triple) { 168 return isARMBareMetal(Triple) || isAArch64BareMetal(Triple) || 169 isRISCVBareMetal(Triple); 170 } 171 172 Tool *BareMetal::buildLinker() const { 173 return new tools::baremetal::Linker(*this); 174 } 175 176 std::string BareMetal::computeSysRoot() const { 177 if (!getDriver().SysRoot.empty()) 178 return getDriver().SysRoot + SelectedMultilib.osSuffix(); 179 180 SmallString<128> SysRootDir; 181 llvm::sys::path::append(SysRootDir, getDriver().Dir, "../lib/clang-runtimes", 182 getDriver().getTargetTriple()); 183 184 SysRootDir += SelectedMultilib.osSuffix(); 185 return std::string(SysRootDir); 186 } 187 188 void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs, 189 ArgStringList &CC1Args) const { 190 if (DriverArgs.hasArg(options::OPT_nostdinc)) 191 return; 192 193 if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { 194 SmallString<128> Dir(getDriver().ResourceDir); 195 llvm::sys::path::append(Dir, "include"); 196 addSystemInclude(DriverArgs, CC1Args, Dir.str()); 197 } 198 199 if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) { 200 SmallString<128> Dir(computeSysRoot()); 201 if (!Dir.empty()) { 202 llvm::sys::path::append(Dir, "include"); 203 addSystemInclude(DriverArgs, CC1Args, Dir.str()); 204 } 205 } 206 } 207 208 void BareMetal::addClangTargetOptions(const ArgList &DriverArgs, 209 ArgStringList &CC1Args, 210 Action::OffloadKind) const { 211 CC1Args.push_back("-nostdsysteminc"); 212 } 213 214 void BareMetal::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, 215 ArgStringList &CC1Args) const { 216 if (DriverArgs.hasArg(options::OPT_nostdinc) || 217 DriverArgs.hasArg(options::OPT_nostdlibinc) || 218 DriverArgs.hasArg(options::OPT_nostdincxx)) 219 return; 220 221 const Driver &D = getDriver(); 222 std::string SysRoot(computeSysRoot()); 223 if (SysRoot.empty()) 224 return; 225 226 switch (GetCXXStdlibType(DriverArgs)) { 227 case ToolChain::CST_Libcxx: { 228 // First check sysroot/usr/include/c++/v1 if it exists. 229 SmallString<128> TargetDir(SysRoot); 230 llvm::sys::path::append(TargetDir, "usr", "include", "c++", "v1"); 231 if (D.getVFS().exists(TargetDir)) { 232 addSystemInclude(DriverArgs, CC1Args, TargetDir.str()); 233 break; 234 } 235 // Add generic path if nothing else succeeded so far. 236 SmallString<128> Dir(SysRoot); 237 llvm::sys::path::append(Dir, "include", "c++", "v1"); 238 addSystemInclude(DriverArgs, CC1Args, Dir.str()); 239 break; 240 } 241 case ToolChain::CST_Libstdcxx: { 242 SmallString<128> Dir(SysRoot); 243 llvm::sys::path::append(Dir, "include", "c++"); 244 std::error_code EC; 245 Generic_GCC::GCCVersion Version = {"", -1, -1, -1, "", "", ""}; 246 // Walk the subdirs, and find the one with the newest gcc version: 247 for (llvm::vfs::directory_iterator LI = D.getVFS().dir_begin(Dir.str(), EC), 248 LE; 249 !EC && LI != LE; LI = LI.increment(EC)) { 250 StringRef VersionText = llvm::sys::path::filename(LI->path()); 251 auto CandidateVersion = Generic_GCC::GCCVersion::Parse(VersionText); 252 if (CandidateVersion.Major == -1) 253 continue; 254 if (CandidateVersion <= Version) 255 continue; 256 Version = CandidateVersion; 257 } 258 if (Version.Major == -1) 259 return; 260 llvm::sys::path::append(Dir, Version.Text); 261 addSystemInclude(DriverArgs, CC1Args, Dir.str()); 262 break; 263 } 264 } 265 } 266 267 void BareMetal::AddCXXStdlibLibArgs(const ArgList &Args, 268 ArgStringList &CmdArgs) const { 269 switch (GetCXXStdlibType(Args)) { 270 case ToolChain::CST_Libcxx: 271 CmdArgs.push_back("-lc++"); 272 if (Args.hasArg(options::OPT_fexperimental_library)) 273 CmdArgs.push_back("-lc++experimental"); 274 CmdArgs.push_back("-lc++abi"); 275 break; 276 case ToolChain::CST_Libstdcxx: 277 CmdArgs.push_back("-lstdc++"); 278 CmdArgs.push_back("-lsupc++"); 279 break; 280 } 281 CmdArgs.push_back("-lunwind"); 282 } 283 284 void BareMetal::AddLinkRuntimeLib(const ArgList &Args, 285 ArgStringList &CmdArgs) const { 286 ToolChain::RuntimeLibType RLT = GetRuntimeLibType(Args); 287 switch (RLT) { 288 case ToolChain::RLT_CompilerRT: { 289 const std::string FileName = getCompilerRT(Args, "builtins"); 290 llvm::StringRef BaseName = llvm::sys::path::filename(FileName); 291 BaseName.consume_front("lib"); 292 BaseName.consume_back(".a"); 293 CmdArgs.push_back(Args.MakeArgString("-l" + BaseName)); 294 return; 295 } 296 case ToolChain::RLT_Libgcc: 297 CmdArgs.push_back("-lgcc"); 298 return; 299 } 300 llvm_unreachable("Unhandled RuntimeLibType."); 301 } 302 303 void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA, 304 const InputInfo &Output, 305 const InputInfoList &Inputs, 306 const ArgList &Args, 307 const char *LinkingOutput) const { 308 ArgStringList CmdArgs; 309 310 auto &TC = static_cast<const toolchains::BareMetal &>(getToolChain()); 311 312 AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA); 313 314 CmdArgs.push_back("-Bstatic"); 315 316 Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, 317 options::OPT_e, options::OPT_s, options::OPT_t, 318 options::OPT_Z_Flag, options::OPT_r}); 319 320 TC.AddFilePathLibArgs(Args, CmdArgs); 321 322 for (const auto &LibPath : TC.getLibraryPaths()) 323 CmdArgs.push_back(Args.MakeArgString(llvm::Twine("-L", LibPath))); 324 325 const std::string FileName = TC.getCompilerRT(Args, "builtins"); 326 llvm::SmallString<128> PathBuf{FileName}; 327 llvm::sys::path::remove_filename(PathBuf); 328 CmdArgs.push_back(Args.MakeArgString("-L" + PathBuf)); 329 330 if (TC.ShouldLinkCXXStdlib(Args)) 331 TC.AddCXXStdlibLibArgs(Args, CmdArgs); 332 333 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { 334 CmdArgs.push_back("-lc"); 335 CmdArgs.push_back("-lm"); 336 337 TC.AddLinkRuntimeLib(Args, CmdArgs); 338 } 339 340 CmdArgs.push_back("-o"); 341 CmdArgs.push_back(Output.getFilename()); 342 343 C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), 344 Args.MakeArgString(TC.GetLinkerPath()), 345 CmdArgs, Inputs, Output)); 346 } 347