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 "InputInfo.h" 13 #include "Gnu.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 static bool isRISCVBareMetal(const llvm::Triple &Triple) { 129 if (Triple.getArch() != llvm::Triple::riscv32 && 130 Triple.getArch() != llvm::Triple::riscv64) 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 void BareMetal::findMultilibs(const Driver &D, const llvm::Triple &Triple, 143 const ArgList &Args) { 144 DetectedMultilibs Result; 145 if (isRISCVBareMetal(Triple)) { 146 if (findRISCVMultilibs(D, Triple, Args, Result)) { 147 SelectedMultilib = Result.SelectedMultilib; 148 Multilibs = Result.Multilibs; 149 } 150 } 151 } 152 153 bool BareMetal::handlesTarget(const llvm::Triple &Triple) { 154 return isARMBareMetal(Triple) || isRISCVBareMetal(Triple); 155 } 156 157 Tool *BareMetal::buildLinker() const { 158 return new tools::baremetal::Linker(*this); 159 } 160 161 std::string BareMetal::getCompilerRTPath() const { return getRuntimesDir(); } 162 163 std::string BareMetal::getCompilerRTBasename(const llvm::opt::ArgList &, 164 StringRef, FileType, bool) const { 165 return ("libclang_rt.builtins-" + getTriple().getArchName() + ".a").str(); 166 } 167 168 std::string BareMetal::getRuntimesDir() const { 169 SmallString<128> Dir(getDriver().ResourceDir); 170 llvm::sys::path::append(Dir, "lib", "baremetal"); 171 Dir += SelectedMultilib.gccSuffix(); 172 return std::string(Dir.str()); 173 } 174 175 std::string BareMetal::computeSysRoot() const { 176 if (!getDriver().SysRoot.empty()) 177 return getDriver().SysRoot + SelectedMultilib.osSuffix(); 178 179 SmallString<128> SysRootDir; 180 llvm::sys::path::append(SysRootDir, getDriver().Dir, "../lib/clang-runtimes", 181 getDriver().getTargetTriple()); 182 183 SysRootDir += SelectedMultilib.osSuffix(); 184 return std::string(SysRootDir); 185 } 186 187 void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs, 188 ArgStringList &CC1Args) const { 189 if (DriverArgs.hasArg(options::OPT_nostdinc)) 190 return; 191 192 if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { 193 SmallString<128> Dir(getDriver().ResourceDir); 194 llvm::sys::path::append(Dir, "include"); 195 addSystemInclude(DriverArgs, CC1Args, Dir.str()); 196 } 197 198 if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) { 199 SmallString<128> Dir(computeSysRoot()); 200 if (!Dir.empty()) { 201 llvm::sys::path::append(Dir, "include"); 202 addSystemInclude(DriverArgs, CC1Args, Dir.str()); 203 } 204 } 205 } 206 207 void BareMetal::addClangTargetOptions(const ArgList &DriverArgs, 208 ArgStringList &CC1Args, 209 Action::OffloadKind) const { 210 CC1Args.push_back("-nostdsysteminc"); 211 } 212 213 void BareMetal::AddClangCXXStdlibIncludeArgs( 214 const ArgList &DriverArgs, ArgStringList &CC1Args) const { 215 if (DriverArgs.hasArg(options::OPT_nostdinc) || 216 DriverArgs.hasArg(options::OPT_nostdlibinc) || 217 DriverArgs.hasArg(options::OPT_nostdincxx)) 218 return; 219 220 std::string SysRoot(computeSysRoot()); 221 if (SysRoot.empty()) 222 return; 223 224 switch (GetCXXStdlibType(DriverArgs)) { 225 case ToolChain::CST_Libcxx: { 226 SmallString<128> Dir(SysRoot); 227 llvm::sys::path::append(Dir, "include", "c++", "v1"); 228 addSystemInclude(DriverArgs, CC1Args, Dir.str()); 229 break; 230 } 231 case ToolChain::CST_Libstdcxx: { 232 SmallString<128> Dir(SysRoot); 233 llvm::sys::path::append(Dir, "include", "c++"); 234 std::error_code EC; 235 Generic_GCC::GCCVersion Version = {"", -1, -1, -1, "", "", ""}; 236 // Walk the subdirs, and find the one with the newest gcc version: 237 for (llvm::vfs::directory_iterator 238 LI = getDriver().getVFS().dir_begin(Dir.str(), EC), 239 LE; 240 !EC && LI != LE; LI = LI.increment(EC)) { 241 StringRef VersionText = llvm::sys::path::filename(LI->path()); 242 auto CandidateVersion = Generic_GCC::GCCVersion::Parse(VersionText); 243 if (CandidateVersion.Major == -1) 244 continue; 245 if (CandidateVersion <= Version) 246 continue; 247 Version = CandidateVersion; 248 } 249 if (Version.Major == -1) 250 return; 251 llvm::sys::path::append(Dir, Version.Text); 252 addSystemInclude(DriverArgs, CC1Args, Dir.str()); 253 break; 254 } 255 } 256 } 257 258 void BareMetal::AddCXXStdlibLibArgs(const ArgList &Args, 259 ArgStringList &CmdArgs) const { 260 switch (GetCXXStdlibType(Args)) { 261 case ToolChain::CST_Libcxx: 262 CmdArgs.push_back("-lc++"); 263 CmdArgs.push_back("-lc++abi"); 264 break; 265 case ToolChain::CST_Libstdcxx: 266 CmdArgs.push_back("-lstdc++"); 267 CmdArgs.push_back("-lsupc++"); 268 break; 269 } 270 CmdArgs.push_back("-lunwind"); 271 } 272 273 void BareMetal::AddLinkRuntimeLib(const ArgList &Args, 274 ArgStringList &CmdArgs) const { 275 ToolChain::RuntimeLibType RLT = GetRuntimeLibType(Args); 276 switch (RLT) { 277 case ToolChain::RLT_CompilerRT: 278 CmdArgs.push_back( 279 Args.MakeArgString("-lclang_rt.builtins-" + getTriple().getArchName())); 280 return; 281 case ToolChain::RLT_Libgcc: 282 CmdArgs.push_back("-lgcc"); 283 return; 284 } 285 llvm_unreachable("Unhandled RuntimeLibType."); 286 } 287 288 void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA, 289 const InputInfo &Output, 290 const InputInfoList &Inputs, 291 const ArgList &Args, 292 const char *LinkingOutput) const { 293 ArgStringList CmdArgs; 294 295 auto &TC = static_cast<const toolchains::BareMetal&>(getToolChain()); 296 297 AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA); 298 299 CmdArgs.push_back("-Bstatic"); 300 301 CmdArgs.push_back(Args.MakeArgString("-L" + TC.getRuntimesDir())); 302 303 TC.AddFilePathLibArgs(Args, CmdArgs); 304 Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, 305 options::OPT_e, options::OPT_s, options::OPT_t, 306 options::OPT_Z_Flag, options::OPT_r}); 307 308 if (TC.ShouldLinkCXXStdlib(Args)) 309 TC.AddCXXStdlibLibArgs(Args, CmdArgs); 310 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { 311 CmdArgs.push_back("-lc"); 312 CmdArgs.push_back("-lm"); 313 314 TC.AddLinkRuntimeLib(Args, CmdArgs); 315 } 316 317 CmdArgs.push_back("-o"); 318 CmdArgs.push_back(Output.getFilename()); 319 320 C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), 321 Args.MakeArgString(TC.GetLinkerPath()), 322 CmdArgs, Inputs, Output)); 323 } 324