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 "CommonArgs.h" 14 #include "clang/Config/config.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.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 assert(!Inputs.empty() && "Must have at least one input."); 204 // Find the first filename InputInfo object. 205 auto Input = llvm::find_if( 206 Inputs, [](const InputInfo &II) -> bool { return II.isFilename(); }); 207 if (Input == Inputs.end()) 208 // For a very rare case, all of the inputs to the linker are 209 // InputArg. If that happens, just use the first InputInfo. 210 Input = Inputs.begin(); 211 212 addLTOOptions(ToolChain, Args, CmdArgs, Output, *Input, 213 D.getLTOMode() == LTOK_Thin); 214 } 215 216 bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs); 217 bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs); 218 AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); 219 220 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs, 221 options::OPT_r)) { 222 // Use the static OpenMP runtime with -static-openmp 223 bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && !Static; 224 addOpenMPRuntime(C, CmdArgs, ToolChain, Args, StaticOpenMP); 225 226 if (D.CCCIsCXX()) { 227 if (ToolChain.ShouldLinkCXXStdlib(Args)) 228 ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); 229 if (Profiling) 230 CmdArgs.push_back("-lm_p"); 231 else 232 CmdArgs.push_back("-lm"); 233 } 234 235 // Silence warnings when linking C code with a C++ '-stdlib' argument. 236 Args.ClaimAllArgs(options::OPT_stdlib_EQ); 237 238 // Additional linker set-up and flags for Fortran. This is required in order 239 // to generate executables. As Fortran runtime depends on the C runtime, 240 // these dependencies need to be listed before the C runtime below (i.e. 241 // AddRunTimeLibs). 242 if (D.IsFlangMode()) { 243 addFortranRuntimeLibraryPath(ToolChain, Args, CmdArgs); 244 addFortranRuntimeLibs(ToolChain, Args, CmdArgs); 245 if (Profiling) 246 CmdArgs.push_back("-lm_p"); 247 else 248 CmdArgs.push_back("-lm"); 249 } 250 251 if (NeedsSanitizerDeps) { 252 CmdArgs.push_back(ToolChain.getCompilerRTArgString(Args, "builtins")); 253 linkSanitizerRuntimeDeps(ToolChain, Args, CmdArgs); 254 } 255 if (NeedsXRayDeps) { 256 CmdArgs.push_back(ToolChain.getCompilerRTArgString(Args, "builtins")); 257 linkXRayRuntimeDeps(ToolChain, Args, CmdArgs); 258 } 259 // FIXME: For some reason GCC passes -lgcc before adding 260 // the default system libraries. Just mimic this for now. 261 CmdArgs.push_back("-lcompiler_rt"); 262 263 if (Args.hasArg(options::OPT_pthread)) { 264 if (!Shared && Profiling) 265 CmdArgs.push_back("-lpthread_p"); 266 else 267 CmdArgs.push_back("-lpthread"); 268 } 269 270 if (!Shared) { 271 if (Profiling) 272 CmdArgs.push_back("-lc_p"); 273 else 274 CmdArgs.push_back("-lc"); 275 } 276 277 CmdArgs.push_back("-lcompiler_rt"); 278 } 279 280 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, 281 options::OPT_r)) { 282 const char *crtend = nullptr; 283 if (!Shared) 284 crtend = "crtend.o"; 285 else 286 crtend = "crtendS.o"; 287 288 CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend))); 289 } 290 291 ToolChain.addProfileRTLibs(Args, CmdArgs); 292 293 const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); 294 C.addCommand(std::make_unique<Command>(JA, *this, 295 ResponseFileSupport::AtFileCurCP(), 296 Exec, CmdArgs, Inputs, Output)); 297 } 298 299 SanitizerMask OpenBSD::getSupportedSanitizers() const { 300 const bool IsX86 = getTriple().getArch() == llvm::Triple::x86; 301 const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64; 302 SanitizerMask Res = ToolChain::getSupportedSanitizers(); 303 if (IsX86 || IsX86_64) { 304 Res |= SanitizerKind::Vptr; 305 Res |= SanitizerKind::Fuzzer; 306 Res |= SanitizerKind::FuzzerNoLink; 307 } 308 if (IsX86_64) { 309 Res |= SanitizerKind::KernelAddress; 310 } 311 return Res; 312 } 313 314 /// OpenBSD - OpenBSD tool chain which can call as(1) and ld(1) directly. 315 316 OpenBSD::OpenBSD(const Driver &D, const llvm::Triple &Triple, 317 const ArgList &Args) 318 : Generic_ELF(D, Triple, Args) { 319 getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib")); 320 } 321 322 void OpenBSD::AddClangSystemIncludeArgs( 323 const llvm::opt::ArgList &DriverArgs, 324 llvm::opt::ArgStringList &CC1Args) const { 325 const Driver &D = getDriver(); 326 327 if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc)) 328 return; 329 330 if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { 331 SmallString<128> Dir(D.ResourceDir); 332 llvm::sys::path::append(Dir, "include"); 333 addSystemInclude(DriverArgs, CC1Args, Dir.str()); 334 } 335 336 if (DriverArgs.hasArg(options::OPT_nostdlibinc)) 337 return; 338 339 // Check for configure-time C include directories. 340 StringRef CIncludeDirs(C_INCLUDE_DIRS); 341 if (CIncludeDirs != "") { 342 SmallVector<StringRef, 5> dirs; 343 CIncludeDirs.split(dirs, ":"); 344 for (StringRef dir : dirs) { 345 StringRef Prefix = 346 llvm::sys::path::is_absolute(dir) ? StringRef(D.SysRoot) : ""; 347 addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir); 348 } 349 return; 350 } 351 352 addExternCSystemInclude(DriverArgs, CC1Args, 353 concat(D.SysRoot, "/usr/include")); 354 } 355 356 void OpenBSD::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, 357 llvm::opt::ArgStringList &CC1Args) const { 358 addSystemInclude(DriverArgs, CC1Args, 359 concat(getDriver().SysRoot, "/usr/include/c++/v1")); 360 } 361 362 void OpenBSD::AddCXXStdlibLibArgs(const ArgList &Args, 363 ArgStringList &CmdArgs) const { 364 bool Profiling = Args.hasArg(options::OPT_pg); 365 366 CmdArgs.push_back(Profiling ? "-lc++_p" : "-lc++"); 367 if (Args.hasArg(options::OPT_fexperimental_library)) 368 CmdArgs.push_back("-lc++experimental"); 369 CmdArgs.push_back(Profiling ? "-lc++abi_p" : "-lc++abi"); 370 CmdArgs.push_back(Profiling ? "-lpthread_p" : "-lpthread"); 371 } 372 373 std::string OpenBSD::getCompilerRT(const ArgList &Args, StringRef Component, 374 FileType Type) const { 375 if (Component == "builtins") { 376 SmallString<128> Path(getDriver().SysRoot); 377 llvm::sys::path::append(Path, "/usr/lib/libcompiler_rt.a"); 378 if (getVFS().exists(Path)) 379 return std::string(Path); 380 } 381 SmallString<128> P(getDriver().ResourceDir); 382 std::string CRTBasename = 383 buildCompilerRTBasename(Args, Component, Type, /*AddArch=*/false); 384 llvm::sys::path::append(P, "lib", CRTBasename); 385 // Checks if this is the base system case which uses a different location. 386 if (getVFS().exists(P)) 387 return std::string(P); 388 return ToolChain::getCompilerRT(Args, Component, Type); 389 } 390 391 Tool *OpenBSD::buildAssembler() const { 392 return new tools::openbsd::Assembler(*this); 393 } 394 395 Tool *OpenBSD::buildLinker() const { return new tools::openbsd::Linker(*this); } 396 397 bool OpenBSD::HasNativeLLVMSupport() const { return true; } 398 399 ToolChain::UnwindTableLevel 400 OpenBSD::getDefaultUnwindTableLevel(const ArgList &Args) const { 401 switch (getArch()) { 402 case llvm::Triple::arm: 403 return UnwindTableLevel::None; 404 default: 405 return UnwindTableLevel::Asynchronous; 406 } 407 } 408