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 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::buildCompilerRTBasename(const llvm::opt::ArgList &, 164 StringRef, FileType, 165 bool) const { 166 return ("libclang_rt.builtins-" + getTriple().getArchName() + ".a").str(); 167 } 168 169 std::string BareMetal::getRuntimesDir() const { 170 SmallString<128> Dir(getDriver().ResourceDir); 171 llvm::sys::path::append(Dir, "lib", "baremetal"); 172 Dir += SelectedMultilib.gccSuffix(); 173 return std::string(Dir.str()); 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( 215 const ArgList &DriverArgs, 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 std::string SysRoot(computeSysRoot()); 222 if (SysRoot.empty()) 223 return; 224 225 switch (GetCXXStdlibType(DriverArgs)) { 226 case ToolChain::CST_Libcxx: { 227 SmallString<128> Dir(SysRoot); 228 llvm::sys::path::append(Dir, "include", "c++", "v1"); 229 addSystemInclude(DriverArgs, CC1Args, Dir.str()); 230 break; 231 } 232 case ToolChain::CST_Libstdcxx: { 233 SmallString<128> Dir(SysRoot); 234 llvm::sys::path::append(Dir, "include", "c++"); 235 std::error_code EC; 236 Generic_GCC::GCCVersion Version = {"", -1, -1, -1, "", "", ""}; 237 // Walk the subdirs, and find the one with the newest gcc version: 238 for (llvm::vfs::directory_iterator 239 LI = getDriver().getVFS().dir_begin(Dir.str(), EC), 240 LE; 241 !EC && LI != LE; LI = LI.increment(EC)) { 242 StringRef VersionText = llvm::sys::path::filename(LI->path()); 243 auto CandidateVersion = Generic_GCC::GCCVersion::Parse(VersionText); 244 if (CandidateVersion.Major == -1) 245 continue; 246 if (CandidateVersion <= Version) 247 continue; 248 Version = CandidateVersion; 249 } 250 if (Version.Major == -1) 251 return; 252 llvm::sys::path::append(Dir, Version.Text); 253 addSystemInclude(DriverArgs, CC1Args, Dir.str()); 254 break; 255 } 256 } 257 } 258 259 void BareMetal::AddCXXStdlibLibArgs(const ArgList &Args, 260 ArgStringList &CmdArgs) const { 261 switch (GetCXXStdlibType(Args)) { 262 case ToolChain::CST_Libcxx: 263 CmdArgs.push_back("-lc++"); 264 CmdArgs.push_back("-lc++abi"); 265 break; 266 case ToolChain::CST_Libstdcxx: 267 CmdArgs.push_back("-lstdc++"); 268 CmdArgs.push_back("-lsupc++"); 269 break; 270 } 271 CmdArgs.push_back("-lunwind"); 272 } 273 274 void BareMetal::AddLinkRuntimeLib(const ArgList &Args, 275 ArgStringList &CmdArgs) const { 276 ToolChain::RuntimeLibType RLT = GetRuntimeLibType(Args); 277 switch (RLT) { 278 case ToolChain::RLT_CompilerRT: 279 CmdArgs.push_back( 280 Args.MakeArgString("-lclang_rt.builtins-" + getTriple().getArchName())); 281 return; 282 case ToolChain::RLT_Libgcc: 283 CmdArgs.push_back("-lgcc"); 284 return; 285 } 286 llvm_unreachable("Unhandled RuntimeLibType."); 287 } 288 289 void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA, 290 const InputInfo &Output, 291 const InputInfoList &Inputs, 292 const ArgList &Args, 293 const char *LinkingOutput) const { 294 ArgStringList CmdArgs; 295 296 auto &TC = static_cast<const toolchains::BareMetal&>(getToolChain()); 297 298 AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA); 299 300 CmdArgs.push_back("-Bstatic"); 301 302 Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, 303 options::OPT_e, options::OPT_s, options::OPT_t, 304 options::OPT_Z_Flag, options::OPT_r}); 305 306 TC.AddFilePathLibArgs(Args, CmdArgs); 307 308 CmdArgs.push_back(Args.MakeArgString("-L" + TC.getRuntimesDir())); 309 310 if (TC.ShouldLinkCXXStdlib(Args)) 311 TC.AddCXXStdlibLibArgs(Args, CmdArgs); 312 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { 313 CmdArgs.push_back("-lc"); 314 CmdArgs.push_back("-lm"); 315 316 TC.AddLinkRuntimeLib(Args, CmdArgs); 317 } 318 319 CmdArgs.push_back("-o"); 320 CmdArgs.push_back(Output.getFilename()); 321 322 C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), 323 Args.MakeArgString(TC.GetLinkerPath()), 324 CmdArgs, Inputs, Output)); 325 } 326