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::ArchType Arch = ToolChain.getArch(); 115 const bool Static = Args.hasArg(options::OPT_static); 116 const bool Shared = Args.hasArg(options::OPT_shared); 117 const bool Profiling = Args.hasArg(options::OPT_pg); 118 const bool Pie = Args.hasArg(options::OPT_pie); 119 const bool Nopie = Args.hasArg(options::OPT_no_pie, options::OPT_nopie); 120 const bool Relocatable = Args.hasArg(options::OPT_r); 121 ArgStringList CmdArgs; 122 123 // Silence warning for "clang -g foo.o -o foo" 124 Args.ClaimAllArgs(options::OPT_g_Group); 125 // and "clang -emit-llvm foo.o -o foo" 126 Args.ClaimAllArgs(options::OPT_emit_llvm); 127 // and for "clang -w foo.o -o foo". Other warning options are already 128 // handled somewhere else. 129 Args.ClaimAllArgs(options::OPT_w); 130 131 if (!D.SysRoot.empty()) 132 CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); 133 134 if (Arch == llvm::Triple::mips64) 135 CmdArgs.push_back("-EB"); 136 else if (Arch == llvm::Triple::mips64el) 137 CmdArgs.push_back("-EL"); 138 139 if (!Args.hasArg(options::OPT_nostdlib) && !Shared && !Relocatable) { 140 CmdArgs.push_back("-e"); 141 CmdArgs.push_back("__start"); 142 } 143 144 CmdArgs.push_back("--eh-frame-hdr"); 145 if (Static) { 146 CmdArgs.push_back("-Bstatic"); 147 } else { 148 if (Args.hasArg(options::OPT_rdynamic)) 149 CmdArgs.push_back("-export-dynamic"); 150 if (Shared) { 151 CmdArgs.push_back("-shared"); 152 } else if (!Relocatable) { 153 CmdArgs.push_back("-dynamic-linker"); 154 CmdArgs.push_back("/usr/libexec/ld.so"); 155 } 156 } 157 158 if (Pie) 159 CmdArgs.push_back("-pie"); 160 if (Nopie || Profiling) 161 CmdArgs.push_back("-nopie"); 162 163 if (Arch == llvm::Triple::riscv64) 164 CmdArgs.push_back("-X"); 165 166 assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); 167 if (Output.isFilename()) { 168 CmdArgs.push_back("-o"); 169 CmdArgs.push_back(Output.getFilename()); 170 } 171 172 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, 173 options::OPT_r)) { 174 const char *crt0 = nullptr; 175 const char *crtbegin = nullptr; 176 if (!Shared) { 177 if (Profiling) 178 crt0 = "gcrt0.o"; 179 else if (Static && !Nopie) 180 crt0 = "rcrt0.o"; 181 else 182 crt0 = "crt0.o"; 183 crtbegin = "crtbegin.o"; 184 } else { 185 crtbegin = "crtbeginS.o"; 186 } 187 188 if (crt0) 189 CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt0))); 190 CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); 191 } 192 193 Args.AddAllArgs(CmdArgs, options::OPT_L); 194 ToolChain.AddFilePathLibArgs(Args, CmdArgs); 195 Args.addAllArgs(CmdArgs, {options::OPT_T_Group, options::OPT_s, 196 options::OPT_t, options::OPT_r}); 197 198 if (D.isUsingLTO()) { 199 assert(!Inputs.empty() && "Must have at least one input."); 200 // Find the first filename InputInfo object. 201 auto Input = llvm::find_if( 202 Inputs, [](const InputInfo &II) -> bool { return II.isFilename(); }); 203 if (Input == Inputs.end()) 204 // For a very rare case, all of the inputs to the linker are 205 // InputArg. If that happens, just use the first InputInfo. 206 Input = Inputs.begin(); 207 208 addLTOOptions(ToolChain, Args, CmdArgs, Output, *Input, 209 D.getLTOMode() == LTOK_Thin); 210 } 211 212 bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs); 213 bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs); 214 AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); 215 216 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs, 217 options::OPT_r)) { 218 // Use the static OpenMP runtime with -static-openmp 219 bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && !Static; 220 addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP); 221 222 if (D.CCCIsCXX()) { 223 if (ToolChain.ShouldLinkCXXStdlib(Args)) 224 ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); 225 if (Profiling) 226 CmdArgs.push_back("-lm_p"); 227 else 228 CmdArgs.push_back("-lm"); 229 } 230 231 // Silence warnings when linking C code with a C++ '-stdlib' argument. 232 Args.ClaimAllArgs(options::OPT_stdlib_EQ); 233 234 // Additional linker set-up and flags for Fortran. This is required in order 235 // to generate executables. As Fortran runtime depends on the C runtime, 236 // these dependencies need to be listed before the C runtime below (i.e. 237 // AddRunTimeLibs). 238 if (D.IsFlangMode()) { 239 addFortranRuntimeLibraryPath(ToolChain, Args, CmdArgs); 240 addFortranRuntimeLibs(ToolChain, Args, CmdArgs); 241 if (Profiling) 242 CmdArgs.push_back("-lm_p"); 243 else 244 CmdArgs.push_back("-lm"); 245 } 246 247 if (NeedsSanitizerDeps) { 248 CmdArgs.push_back(ToolChain.getCompilerRTArgString(Args, "builtins")); 249 linkSanitizerRuntimeDeps(ToolChain, Args, CmdArgs); 250 } 251 if (NeedsXRayDeps) { 252 CmdArgs.push_back(ToolChain.getCompilerRTArgString(Args, "builtins")); 253 linkXRayRuntimeDeps(ToolChain, Args, CmdArgs); 254 } 255 // FIXME: For some reason GCC passes -lgcc before adding 256 // the default system libraries. Just mimic this for now. 257 CmdArgs.push_back("-lcompiler_rt"); 258 259 if (Args.hasArg(options::OPT_pthread)) { 260 if (!Shared && Profiling) 261 CmdArgs.push_back("-lpthread_p"); 262 else 263 CmdArgs.push_back("-lpthread"); 264 } 265 266 if (!Shared) { 267 if (Profiling) 268 CmdArgs.push_back("-lc_p"); 269 else 270 CmdArgs.push_back("-lc"); 271 } 272 273 CmdArgs.push_back("-lcompiler_rt"); 274 } 275 276 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, 277 options::OPT_r)) { 278 const char *crtend = nullptr; 279 if (!Shared) 280 crtend = "crtend.o"; 281 else 282 crtend = "crtendS.o"; 283 284 CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend))); 285 } 286 287 ToolChain.addProfileRTLibs(Args, CmdArgs); 288 289 const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); 290 C.addCommand(std::make_unique<Command>(JA, *this, 291 ResponseFileSupport::AtFileCurCP(), 292 Exec, CmdArgs, Inputs, Output)); 293 } 294 295 SanitizerMask OpenBSD::getSupportedSanitizers() const { 296 const bool IsX86 = getTriple().getArch() == llvm::Triple::x86; 297 const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64; 298 SanitizerMask Res = ToolChain::getSupportedSanitizers(); 299 if (IsX86 || IsX86_64) { 300 Res |= SanitizerKind::Vptr; 301 Res |= SanitizerKind::Fuzzer; 302 Res |= SanitizerKind::FuzzerNoLink; 303 } 304 if (IsX86_64) { 305 Res |= SanitizerKind::KernelAddress; 306 } 307 return Res; 308 } 309 310 /// OpenBSD - OpenBSD tool chain which can call as(1) and ld(1) directly. 311 312 OpenBSD::OpenBSD(const Driver &D, const llvm::Triple &Triple, 313 const ArgList &Args) 314 : Generic_ELF(D, Triple, Args) { 315 getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib")); 316 } 317 318 void OpenBSD::AddClangSystemIncludeArgs( 319 const llvm::opt::ArgList &DriverArgs, 320 llvm::opt::ArgStringList &CC1Args) const { 321 const Driver &D = getDriver(); 322 323 if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc)) 324 return; 325 326 if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { 327 SmallString<128> Dir(D.ResourceDir); 328 llvm::sys::path::append(Dir, "include"); 329 addSystemInclude(DriverArgs, CC1Args, Dir.str()); 330 } 331 332 if (DriverArgs.hasArg(options::OPT_nostdlibinc)) 333 return; 334 335 // Check for configure-time C include directories. 336 StringRef CIncludeDirs(C_INCLUDE_DIRS); 337 if (CIncludeDirs != "") { 338 SmallVector<StringRef, 5> dirs; 339 CIncludeDirs.split(dirs, ":"); 340 for (StringRef dir : dirs) { 341 StringRef Prefix = 342 llvm::sys::path::is_absolute(dir) ? StringRef(D.SysRoot) : ""; 343 addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir); 344 } 345 return; 346 } 347 348 addExternCSystemInclude(DriverArgs, CC1Args, 349 concat(D.SysRoot, "/usr/include")); 350 } 351 352 void OpenBSD::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, 353 llvm::opt::ArgStringList &CC1Args) const { 354 addSystemInclude(DriverArgs, CC1Args, 355 concat(getDriver().SysRoot, "/usr/include/c++/v1")); 356 } 357 358 void OpenBSD::AddCXXStdlibLibArgs(const ArgList &Args, 359 ArgStringList &CmdArgs) const { 360 bool Profiling = Args.hasArg(options::OPT_pg); 361 362 CmdArgs.push_back(Profiling ? "-lc++_p" : "-lc++"); 363 if (Args.hasArg(options::OPT_fexperimental_library)) 364 CmdArgs.push_back("-lc++experimental"); 365 CmdArgs.push_back(Profiling ? "-lc++abi_p" : "-lc++abi"); 366 CmdArgs.push_back(Profiling ? "-lpthread_p" : "-lpthread"); 367 } 368 369 std::string OpenBSD::getCompilerRT(const ArgList &Args, StringRef Component, 370 FileType Type) const { 371 if (Component == "builtins") { 372 SmallString<128> Path(getDriver().SysRoot); 373 llvm::sys::path::append(Path, "/usr/lib/libcompiler_rt.a"); 374 if (getVFS().exists(Path)) 375 return std::string(Path); 376 } 377 SmallString<128> P(getDriver().ResourceDir); 378 std::string CRTBasename = 379 buildCompilerRTBasename(Args, Component, Type, /*AddArch=*/false); 380 llvm::sys::path::append(P, "lib", CRTBasename); 381 // Checks if this is the base system case which uses a different location. 382 if (getVFS().exists(P)) 383 return std::string(P); 384 return ToolChain::getCompilerRT(Args, Component, Type); 385 } 386 387 Tool *OpenBSD::buildAssembler() const { 388 return new tools::openbsd::Assembler(*this); 389 } 390 391 Tool *OpenBSD::buildLinker() const { return new tools::openbsd::Linker(*this); } 392 393 bool OpenBSD::HasNativeLLVMSupport() const { return true; } 394 395 ToolChain::UnwindTableLevel 396 OpenBSD::getDefaultUnwindTableLevel(const ArgList &Args) const { 397 switch (getArch()) { 398 case llvm::Triple::arm: 399 return UnwindTableLevel::None; 400 default: 401 return UnwindTableLevel::Asynchronous; 402 } 403 } 404