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.getArch() == llvm::Triple::riscv64) { 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.getArch() == llvm::Triple::riscv32) { 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 } 107 } 108 109 /// Is the triple {arm,thumb}-none-none-{eabi,eabihf} ? 110 static bool isARMBareMetal(const llvm::Triple &Triple) { 111 if (Triple.getArch() != llvm::Triple::arm && 112 Triple.getArch() != llvm::Triple::thumb) 113 return false; 114 115 if (Triple.getVendor() != llvm::Triple::UnknownVendor) 116 return false; 117 118 if (Triple.getOS() != llvm::Triple::UnknownOS) 119 return false; 120 121 if (Triple.getEnvironment() != llvm::Triple::EABI && 122 Triple.getEnvironment() != llvm::Triple::EABIHF) 123 return false; 124 125 return true; 126 } 127 128 /// Is the triple aarch64-none-elf? 129 static bool isAArch64BareMetal(const llvm::Triple &Triple) { 130 if (Triple.getArch() != llvm::Triple::aarch64) 131 return false; 132 133 if (Triple.getVendor() != llvm::Triple::UnknownVendor) 134 return false; 135 136 if (Triple.getOS() != llvm::Triple::UnknownOS) 137 return false; 138 139 return Triple.getEnvironmentName() == "elf"; 140 } 141 142 static bool isRISCVBareMetal(const llvm::Triple &Triple) { 143 if (Triple.getArch() != llvm::Triple::riscv32 && 144 Triple.getArch() != llvm::Triple::riscv64) 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::getCompilerRTPath() const { return getRuntimesDir(); } 177 178 std::string BareMetal::buildCompilerRTBasename(const llvm::opt::ArgList &, 179 StringRef, FileType, 180 bool) const { 181 return ("libclang_rt.builtins-" + getTriple().getArchName() + ".a").str(); 182 } 183 184 std::string BareMetal::getRuntimesDir() const { 185 SmallString<128> Dir(getDriver().ResourceDir); 186 llvm::sys::path::append(Dir, "lib", "baremetal"); 187 Dir += SelectedMultilib.gccSuffix(); 188 return std::string(Dir.str()); 189 } 190 191 std::string BareMetal::computeSysRoot() const { 192 if (!getDriver().SysRoot.empty()) 193 return getDriver().SysRoot + SelectedMultilib.osSuffix(); 194 195 SmallString<128> SysRootDir; 196 llvm::sys::path::append(SysRootDir, getDriver().Dir, "../lib/clang-runtimes", 197 getDriver().getTargetTriple()); 198 199 SysRootDir += SelectedMultilib.osSuffix(); 200 return std::string(SysRootDir); 201 } 202 203 void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs, 204 ArgStringList &CC1Args) const { 205 if (DriverArgs.hasArg(options::OPT_nostdinc)) 206 return; 207 208 if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { 209 SmallString<128> Dir(getDriver().ResourceDir); 210 llvm::sys::path::append(Dir, "include"); 211 addSystemInclude(DriverArgs, CC1Args, Dir.str()); 212 } 213 214 if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) { 215 SmallString<128> Dir(computeSysRoot()); 216 if (!Dir.empty()) { 217 llvm::sys::path::append(Dir, "include"); 218 addSystemInclude(DriverArgs, CC1Args, Dir.str()); 219 } 220 } 221 } 222 223 void BareMetal::addClangTargetOptions(const ArgList &DriverArgs, 224 ArgStringList &CC1Args, 225 Action::OffloadKind) const { 226 CC1Args.push_back("-nostdsysteminc"); 227 } 228 229 void BareMetal::AddClangCXXStdlibIncludeArgs( 230 const ArgList &DriverArgs, ArgStringList &CC1Args) const { 231 if (DriverArgs.hasArg(options::OPT_nostdinc) || 232 DriverArgs.hasArg(options::OPT_nostdlibinc) || 233 DriverArgs.hasArg(options::OPT_nostdincxx)) 234 return; 235 236 std::string SysRoot(computeSysRoot()); 237 if (SysRoot.empty()) 238 return; 239 240 switch (GetCXXStdlibType(DriverArgs)) { 241 case ToolChain::CST_Libcxx: { 242 SmallString<128> Dir(SysRoot); 243 llvm::sys::path::append(Dir, "include", "c++", "v1"); 244 addSystemInclude(DriverArgs, CC1Args, Dir.str()); 245 break; 246 } 247 case ToolChain::CST_Libstdcxx: { 248 SmallString<128> Dir(SysRoot); 249 llvm::sys::path::append(Dir, "include", "c++"); 250 std::error_code EC; 251 Generic_GCC::GCCVersion Version = {"", -1, -1, -1, "", "", ""}; 252 // Walk the subdirs, and find the one with the newest gcc version: 253 for (llvm::vfs::directory_iterator 254 LI = getDriver().getVFS().dir_begin(Dir.str(), EC), 255 LE; 256 !EC && LI != LE; LI = LI.increment(EC)) { 257 StringRef VersionText = llvm::sys::path::filename(LI->path()); 258 auto CandidateVersion = Generic_GCC::GCCVersion::Parse(VersionText); 259 if (CandidateVersion.Major == -1) 260 continue; 261 if (CandidateVersion <= Version) 262 continue; 263 Version = CandidateVersion; 264 } 265 if (Version.Major == -1) 266 return; 267 llvm::sys::path::append(Dir, Version.Text); 268 addSystemInclude(DriverArgs, CC1Args, Dir.str()); 269 break; 270 } 271 } 272 } 273 274 void BareMetal::AddCXXStdlibLibArgs(const ArgList &Args, 275 ArgStringList &CmdArgs) const { 276 switch (GetCXXStdlibType(Args)) { 277 case ToolChain::CST_Libcxx: 278 CmdArgs.push_back("-lc++"); 279 CmdArgs.push_back("-lc++abi"); 280 break; 281 case ToolChain::CST_Libstdcxx: 282 CmdArgs.push_back("-lstdc++"); 283 CmdArgs.push_back("-lsupc++"); 284 break; 285 } 286 CmdArgs.push_back("-lunwind"); 287 } 288 289 void BareMetal::AddLinkRuntimeLib(const ArgList &Args, 290 ArgStringList &CmdArgs) const { 291 ToolChain::RuntimeLibType RLT = GetRuntimeLibType(Args); 292 switch (RLT) { 293 case ToolChain::RLT_CompilerRT: 294 CmdArgs.push_back( 295 Args.MakeArgString("-lclang_rt.builtins-" + getTriple().getArchName())); 296 return; 297 case ToolChain::RLT_Libgcc: 298 CmdArgs.push_back("-lgcc"); 299 return; 300 } 301 llvm_unreachable("Unhandled RuntimeLibType."); 302 } 303 304 void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA, 305 const InputInfo &Output, 306 const InputInfoList &Inputs, 307 const ArgList &Args, 308 const char *LinkingOutput) const { 309 ArgStringList CmdArgs; 310 311 auto &TC = static_cast<const toolchains::BareMetal&>(getToolChain()); 312 313 AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA); 314 315 CmdArgs.push_back("-Bstatic"); 316 317 Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, 318 options::OPT_e, options::OPT_s, options::OPT_t, 319 options::OPT_Z_Flag, options::OPT_r}); 320 321 TC.AddFilePathLibArgs(Args, CmdArgs); 322 323 CmdArgs.push_back(Args.MakeArgString("-L" + TC.getRuntimesDir())); 324 325 if (TC.ShouldLinkCXXStdlib(Args)) 326 TC.AddCXXStdlibLibArgs(Args, CmdArgs); 327 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { 328 CmdArgs.push_back("-lc"); 329 CmdArgs.push_back("-lm"); 330 331 TC.AddLinkRuntimeLib(Args, CmdArgs); 332 } 333 334 CmdArgs.push_back("-o"); 335 CmdArgs.push_back(Output.getFilename()); 336 337 C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), 338 Args.MakeArgString(TC.GetLinkerPath()), 339 CmdArgs, Inputs, Output)); 340 } 341