1 //===--- OpenBSD.cpp - OpenBSD ToolChain Implementations --------*- 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 "OpenBSD.h" 10 #include "Arch/ARM.h" 11 #include "Arch/Mips.h" 12 #include "Arch/Sparc.h" 13 #include "clang/Config/config.h" 14 #include "clang/Driver/CommonArgs.h" 15 #include "clang/Driver/Compilation.h" 16 #include "clang/Driver/Options.h" 17 #include "clang/Driver/SanitizerArgs.h" 18 #include "llvm/Option/ArgList.h" 19 #include "llvm/Support/Path.h" 20 #include "llvm/Support/VirtualFileSystem.h" 21 22 using namespace clang::driver; 23 using namespace clang::driver::tools; 24 using namespace clang::driver::toolchains; 25 using namespace clang; 26 using namespace llvm::opt; 27 28 void openbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, 29 const InputInfo &Output, 30 const InputInfoList &Inputs, 31 const ArgList &Args, 32 const char *LinkingOutput) const { 33 const auto &ToolChain = static_cast<const OpenBSD &>(getToolChain()); 34 const Driver &D = ToolChain.getDriver(); 35 const llvm::Triple &Triple = ToolChain.getTriple(); 36 ArgStringList CmdArgs; 37 38 claimNoWarnArgs(Args); 39 40 switch (ToolChain.getArch()) { 41 case llvm::Triple::x86: 42 // When building 32-bit code on OpenBSD/amd64, we have to explicitly 43 // instruct as in the base system to assemble 32-bit code. 44 CmdArgs.push_back("--32"); 45 break; 46 47 case llvm::Triple::arm: { 48 StringRef MArch, MCPU; 49 arm::getARMArchCPUFromArgs(Args, MArch, MCPU, /*FromAs*/ true); 50 std::string Arch = arm::getARMTargetCPU(MCPU, MArch, Triple); 51 CmdArgs.push_back(Args.MakeArgString("-mcpu=" + Arch)); 52 break; 53 } 54 55 case llvm::Triple::ppc: 56 CmdArgs.push_back("-mppc"); 57 CmdArgs.push_back("-many"); 58 break; 59 60 case llvm::Triple::sparcv9: { 61 CmdArgs.push_back("-64"); 62 std::string CPU = getCPUName(D, Args, Triple); 63 CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, Triple)); 64 AddAssemblerKPIC(ToolChain, Args, CmdArgs); 65 break; 66 } 67 68 case llvm::Triple::mips64: 69 case llvm::Triple::mips64el: { 70 StringRef CPUName; 71 StringRef ABIName; 72 mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName); 73 74 CmdArgs.push_back("-march"); 75 CmdArgs.push_back(CPUName.data()); 76 77 CmdArgs.push_back("-mabi"); 78 CmdArgs.push_back(mips::getGnuCompatibleMipsABIName(ABIName).data()); 79 80 if (Triple.isLittleEndian()) 81 CmdArgs.push_back("-EL"); 82 else 83 CmdArgs.push_back("-EB"); 84 85 AddAssemblerKPIC(ToolChain, Args, CmdArgs); 86 break; 87 } 88 89 default: 90 break; 91 } 92 93 Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); 94 95 CmdArgs.push_back("-o"); 96 CmdArgs.push_back(Output.getFilename()); 97 98 for (const auto &II : Inputs) 99 CmdArgs.push_back(II.getFilename()); 100 101 const char *Exec = Args.MakeArgString(ToolChain.GetProgramPath("as")); 102 C.addCommand(std::make_unique<Command>(JA, *this, 103 ResponseFileSupport::AtFileCurCP(), 104 Exec, CmdArgs, Inputs, Output)); 105 } 106 107 void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, 108 const InputInfo &Output, 109 const InputInfoList &Inputs, 110 const ArgList &Args, 111 const char *LinkingOutput) const { 112 const auto &ToolChain = static_cast<const OpenBSD &>(getToolChain()); 113 const Driver &D = ToolChain.getDriver(); 114 const llvm::Triple &Triple = ToolChain.getTriple(); 115 const llvm::Triple::ArchType Arch = ToolChain.getArch(); 116 const bool Static = Args.hasArg(options::OPT_static); 117 const bool Shared = Args.hasArg(options::OPT_shared); 118 const bool Profiling = Args.hasArg(options::OPT_pg); 119 const bool Pie = Args.hasArg(options::OPT_pie); 120 const bool Nopie = Args.hasArg(options::OPT_no_pie, options::OPT_nopie); 121 const bool Relocatable = Args.hasArg(options::OPT_r); 122 ArgStringList CmdArgs; 123 124 // Silence warning for "clang -g foo.o -o foo" 125 Args.ClaimAllArgs(options::OPT_g_Group); 126 // and "clang -emit-llvm foo.o -o foo" 127 Args.ClaimAllArgs(options::OPT_emit_llvm); 128 // and for "clang -w foo.o -o foo". Other warning options are already 129 // handled somewhere else. 130 Args.ClaimAllArgs(options::OPT_w); 131 132 if (!D.SysRoot.empty()) 133 CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); 134 135 if (Arch == llvm::Triple::mips64) 136 CmdArgs.push_back("-EB"); 137 else if (Arch == llvm::Triple::mips64el) 138 CmdArgs.push_back("-EL"); 139 140 if (!Args.hasArg(options::OPT_nostdlib) && !Shared && !Relocatable) { 141 CmdArgs.push_back("-e"); 142 CmdArgs.push_back("__start"); 143 } 144 145 CmdArgs.push_back("--eh-frame-hdr"); 146 if (Static) { 147 CmdArgs.push_back("-Bstatic"); 148 } else { 149 if (Args.hasArg(options::OPT_rdynamic)) 150 CmdArgs.push_back("-export-dynamic"); 151 if (Shared) { 152 CmdArgs.push_back("-shared"); 153 } else if (!Relocatable) { 154 CmdArgs.push_back("-dynamic-linker"); 155 CmdArgs.push_back("/usr/libexec/ld.so"); 156 } 157 } 158 159 if (Pie) 160 CmdArgs.push_back("-pie"); 161 if (Nopie || Profiling) 162 CmdArgs.push_back("-nopie"); 163 164 if (Triple.isLoongArch64() || Triple.isRISCV64()) { 165 CmdArgs.push_back("-X"); 166 if (Args.hasArg(options::OPT_mno_relax)) 167 CmdArgs.push_back("--no-relax"); 168 } 169 170 assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); 171 if (Output.isFilename()) { 172 CmdArgs.push_back("-o"); 173 CmdArgs.push_back(Output.getFilename()); 174 } 175 176 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, 177 options::OPT_r)) { 178 const char *crt0 = nullptr; 179 const char *crtbegin = nullptr; 180 if (!Shared) { 181 if (Profiling) 182 crt0 = "gcrt0.o"; 183 else if (Static && !Nopie) 184 crt0 = "rcrt0.o"; 185 else 186 crt0 = "crt0.o"; 187 crtbegin = "crtbegin.o"; 188 } else { 189 crtbegin = "crtbeginS.o"; 190 } 191 192 if (crt0) 193 CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt0))); 194 CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); 195 } 196 197 Args.AddAllArgs(CmdArgs, options::OPT_L); 198 ToolChain.AddFilePathLibArgs(Args, CmdArgs); 199 Args.addAllArgs(CmdArgs, 200 {options::OPT_T_Group, options::OPT_s, options::OPT_t}); 201 202 if (D.isUsingLTO()) 203 addLTOOptions(ToolChain, Args, CmdArgs, Output, Inputs, 204 D.getLTOMode() == LTOK_Thin); 205 206 bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs); 207 bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs); 208 AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); 209 210 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs, 211 options::OPT_r)) { 212 // Use the static OpenMP runtime with -static-openmp 213 bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && !Static; 214 addOpenMPRuntime(C, CmdArgs, ToolChain, Args, StaticOpenMP); 215 216 if (D.CCCIsCXX()) { 217 if (ToolChain.ShouldLinkCXXStdlib(Args)) 218 ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); 219 if (Profiling) 220 CmdArgs.push_back("-lm_p"); 221 else 222 CmdArgs.push_back("-lm"); 223 } 224 225 // Silence warnings when linking C code with a C++ '-stdlib' argument. 226 Args.ClaimAllArgs(options::OPT_stdlib_EQ); 227 228 // Additional linker set-up and flags for Fortran. This is required in order 229 // to generate executables. As Fortran runtime depends on the C runtime, 230 // these dependencies need to be listed before the C runtime below (i.e. 231 // AddRunTimeLibs). 232 if (D.IsFlangMode() && 233 !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { 234 ToolChain.addFortranRuntimeLibraryPath(Args, CmdArgs); 235 ToolChain.addFortranRuntimeLibs(Args, CmdArgs); 236 if (Profiling) 237 CmdArgs.push_back("-lm_p"); 238 else 239 CmdArgs.push_back("-lm"); 240 } 241 242 if (NeedsSanitizerDeps) { 243 CmdArgs.push_back(ToolChain.getCompilerRTArgString(Args, "builtins")); 244 linkSanitizerRuntimeDeps(ToolChain, Args, CmdArgs); 245 } 246 if (NeedsXRayDeps) { 247 CmdArgs.push_back(ToolChain.getCompilerRTArgString(Args, "builtins")); 248 linkXRayRuntimeDeps(ToolChain, Args, CmdArgs); 249 } 250 // FIXME: For some reason GCC passes -lgcc before adding 251 // the default system libraries. Just mimic this for now. 252 CmdArgs.push_back("-lcompiler_rt"); 253 254 if (Args.hasArg(options::OPT_pthread)) { 255 if (!Shared && Profiling) 256 CmdArgs.push_back("-lpthread_p"); 257 else 258 CmdArgs.push_back("-lpthread"); 259 } 260 261 if (!Shared) { 262 if (Profiling) 263 CmdArgs.push_back("-lc_p"); 264 else 265 CmdArgs.push_back("-lc"); 266 } 267 268 CmdArgs.push_back("-lcompiler_rt"); 269 } 270 271 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, 272 options::OPT_r)) { 273 const char *crtend = nullptr; 274 if (!Shared) 275 crtend = "crtend.o"; 276 else 277 crtend = "crtendS.o"; 278 279 CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend))); 280 } 281 282 ToolChain.addProfileRTLibs(Args, CmdArgs); 283 284 const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); 285 C.addCommand(std::make_unique<Command>(JA, *this, 286 ResponseFileSupport::AtFileCurCP(), 287 Exec, CmdArgs, Inputs, Output)); 288 } 289 290 SanitizerMask OpenBSD::getSupportedSanitizers() const { 291 const bool IsX86 = getTriple().getArch() == llvm::Triple::x86; 292 const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64; 293 SanitizerMask Res = ToolChain::getSupportedSanitizers(); 294 if (IsX86 || IsX86_64) { 295 Res |= SanitizerKind::Vptr; 296 Res |= SanitizerKind::Fuzzer; 297 Res |= SanitizerKind::FuzzerNoLink; 298 } 299 if (IsX86_64) { 300 Res |= SanitizerKind::KernelAddress; 301 } 302 return Res; 303 } 304 305 /// OpenBSD - OpenBSD tool chain which can call as(1) and ld(1) directly. 306 307 OpenBSD::OpenBSD(const Driver &D, const llvm::Triple &Triple, 308 const ArgList &Args) 309 : Generic_ELF(D, Triple, Args) { 310 getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib")); 311 } 312 313 void OpenBSD::AddClangSystemIncludeArgs( 314 const llvm::opt::ArgList &DriverArgs, 315 llvm::opt::ArgStringList &CC1Args) const { 316 const Driver &D = getDriver(); 317 318 if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc)) 319 return; 320 321 if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { 322 SmallString<128> Dir(D.ResourceDir); 323 llvm::sys::path::append(Dir, "include"); 324 addSystemInclude(DriverArgs, CC1Args, Dir.str()); 325 } 326 327 if (DriverArgs.hasArg(options::OPT_nostdlibinc)) 328 return; 329 330 // Check for configure-time C include directories. 331 StringRef CIncludeDirs(C_INCLUDE_DIRS); 332 if (CIncludeDirs != "") { 333 SmallVector<StringRef, 5> dirs; 334 CIncludeDirs.split(dirs, ":"); 335 for (StringRef dir : dirs) { 336 StringRef Prefix = 337 llvm::sys::path::is_absolute(dir) ? StringRef(D.SysRoot) : ""; 338 addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir); 339 } 340 return; 341 } 342 343 addExternCSystemInclude(DriverArgs, CC1Args, 344 concat(D.SysRoot, "/usr/include")); 345 } 346 347 void OpenBSD::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, 348 llvm::opt::ArgStringList &CC1Args) const { 349 addSystemInclude(DriverArgs, CC1Args, 350 concat(getDriver().SysRoot, "/usr/include/c++/v1")); 351 } 352 353 void OpenBSD::AddCXXStdlibLibArgs(const ArgList &Args, 354 ArgStringList &CmdArgs) const { 355 bool Profiling = Args.hasArg(options::OPT_pg); 356 357 CmdArgs.push_back(Profiling ? "-lc++_p" : "-lc++"); 358 if (Args.hasArg(options::OPT_fexperimental_library)) 359 CmdArgs.push_back("-lc++experimental"); 360 CmdArgs.push_back(Profiling ? "-lc++abi_p" : "-lc++abi"); 361 CmdArgs.push_back(Profiling ? "-lpthread_p" : "-lpthread"); 362 } 363 364 std::string OpenBSD::getCompilerRT(const ArgList &Args, StringRef Component, 365 FileType Type, bool IsFortran) const { 366 if (Component == "builtins") { 367 SmallString<128> Path(getDriver().SysRoot); 368 llvm::sys::path::append(Path, "/usr/lib/libcompiler_rt.a"); 369 if (getVFS().exists(Path)) 370 return std::string(Path); 371 } 372 SmallString<128> P(getDriver().ResourceDir); 373 std::string CRTBasename = buildCompilerRTBasename( 374 Args, Component, Type, /*AddArch=*/false, IsFortran); 375 llvm::sys::path::append(P, "lib", CRTBasename); 376 // Checks if this is the base system case which uses a different location. 377 if (getVFS().exists(P)) 378 return std::string(P); 379 return ToolChain::getCompilerRT(Args, Component, Type, IsFortran); 380 } 381 382 Tool *OpenBSD::buildAssembler() const { 383 return new tools::openbsd::Assembler(*this); 384 } 385 386 Tool *OpenBSD::buildLinker() const { return new tools::openbsd::Linker(*this); } 387 388 bool OpenBSD::HasNativeLLVMSupport() const { return true; } 389 390 ToolChain::UnwindTableLevel 391 OpenBSD::getDefaultUnwindTableLevel(const ArgList &Args) const { 392 switch (getArch()) { 393 case llvm::Triple::arm: 394 return UnwindTableLevel::None; 395 default: 396 return UnwindTableLevel::Asynchronous; 397 } 398 } 399