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 if (Args.hasArg(options::OPT_fexperimental_library)) 280 CmdArgs.push_back("-lc++experimental"); 281 CmdArgs.push_back("-lc++abi"); 282 break; 283 case ToolChain::CST_Libstdcxx: 284 CmdArgs.push_back("-lstdc++"); 285 CmdArgs.push_back("-lsupc++"); 286 break; 287 } 288 CmdArgs.push_back("-lunwind"); 289 } 290 291 void BareMetal::AddLinkRuntimeLib(const ArgList &Args, 292 ArgStringList &CmdArgs) const { 293 ToolChain::RuntimeLibType RLT = GetRuntimeLibType(Args); 294 switch (RLT) { 295 case ToolChain::RLT_CompilerRT: 296 CmdArgs.push_back( 297 Args.MakeArgString("-lclang_rt.builtins-" + getTriple().getArchName())); 298 return; 299 case ToolChain::RLT_Libgcc: 300 CmdArgs.push_back("-lgcc"); 301 return; 302 } 303 llvm_unreachable("Unhandled RuntimeLibType."); 304 } 305 306 void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA, 307 const InputInfo &Output, 308 const InputInfoList &Inputs, 309 const ArgList &Args, 310 const char *LinkingOutput) const { 311 ArgStringList CmdArgs; 312 313 auto &TC = static_cast<const toolchains::BareMetal&>(getToolChain()); 314 315 AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA); 316 317 CmdArgs.push_back("-Bstatic"); 318 319 Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, 320 options::OPT_e, options::OPT_s, options::OPT_t, 321 options::OPT_Z_Flag, options::OPT_r}); 322 323 TC.AddFilePathLibArgs(Args, CmdArgs); 324 325 CmdArgs.push_back(Args.MakeArgString("-L" + TC.getRuntimesDir())); 326 327 if (TC.ShouldLinkCXXStdlib(Args)) 328 TC.AddCXXStdlibLibArgs(Args, CmdArgs); 329 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { 330 CmdArgs.push_back("-lc"); 331 CmdArgs.push_back("-lm"); 332 333 TC.AddLinkRuntimeLib(Args, CmdArgs); 334 } 335 336 CmdArgs.push_back("-o"); 337 CmdArgs.push_back(Output.getFilename()); 338 339 C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), 340 Args.MakeArgString(TC.GetLinkerPath()), 341 CmdArgs, Inputs, Output)); 342 } 343