1 //===--- NetBSD.cpp - NetBSD 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 "NetBSD.h" 10 #include "Arch/ARM.h" 11 #include "Arch/Mips.h" 12 #include "Arch/Sparc.h" 13 #include "CommonArgs.h" 14 #include "clang/Driver/Compilation.h" 15 #include "clang/Driver/Driver.h" 16 #include "clang/Driver/Options.h" 17 #include "clang/Driver/SanitizerArgs.h" 18 #include "llvm/Option/ArgList.h" 19 #include "llvm/Support/VirtualFileSystem.h" 20 21 using namespace clang::driver; 22 using namespace clang::driver::tools; 23 using namespace clang::driver::toolchains; 24 using namespace clang; 25 using namespace llvm::opt; 26 27 void netbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, 28 const InputInfo &Output, 29 const InputInfoList &Inputs, 30 const ArgList &Args, 31 const char *LinkingOutput) const { 32 const toolchains::NetBSD &ToolChain = 33 static_cast<const toolchains::NetBSD &>(getToolChain()); 34 const Driver &D = ToolChain.getDriver(); 35 const llvm::Triple &Triple = ToolChain.getTriple(); 36 37 claimNoWarnArgs(Args); 38 ArgStringList CmdArgs; 39 40 // GNU as needs different flags for creating the correct output format 41 // on architectures with different ABIs or optional feature sets. 42 switch (ToolChain.getArch()) { 43 case llvm::Triple::x86: 44 CmdArgs.push_back("--32"); 45 break; 46 case llvm::Triple::arm: 47 case llvm::Triple::armeb: 48 case llvm::Triple::thumb: 49 case llvm::Triple::thumbeb: { 50 StringRef MArch, MCPU; 51 arm::getARMArchCPUFromArgs(Args, MArch, MCPU, /*FromAs*/ true); 52 std::string Arch = arm::getARMTargetCPU(MCPU, MArch, Triple); 53 CmdArgs.push_back(Args.MakeArgString("-mcpu=" + Arch)); 54 break; 55 } 56 57 case llvm::Triple::mips: 58 case llvm::Triple::mipsel: 59 case llvm::Triple::mips64: 60 case llvm::Triple::mips64el: { 61 StringRef CPUName; 62 StringRef ABIName; 63 mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName); 64 65 CmdArgs.push_back("-march"); 66 CmdArgs.push_back(CPUName.data()); 67 68 CmdArgs.push_back("-mabi"); 69 CmdArgs.push_back(mips::getGnuCompatibleMipsABIName(ABIName).data()); 70 71 if (Triple.isLittleEndian()) 72 CmdArgs.push_back("-EL"); 73 else 74 CmdArgs.push_back("-EB"); 75 76 AddAssemblerKPIC(ToolChain, Args, CmdArgs); 77 break; 78 } 79 80 case llvm::Triple::sparc: 81 case llvm::Triple::sparcel: { 82 CmdArgs.push_back("-32"); 83 std::string CPU = getCPUName(D, Args, Triple); 84 CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, Triple)); 85 AddAssemblerKPIC(ToolChain, Args, CmdArgs); 86 break; 87 } 88 89 case llvm::Triple::sparcv9: { 90 CmdArgs.push_back("-64"); 91 std::string CPU = getCPUName(D, Args, Triple); 92 CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, Triple)); 93 AddAssemblerKPIC(ToolChain, Args, CmdArgs); 94 break; 95 } 96 97 default: 98 break; 99 } 100 101 Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); 102 103 CmdArgs.push_back("-o"); 104 CmdArgs.push_back(Output.getFilename()); 105 106 for (const auto &II : Inputs) 107 CmdArgs.push_back(II.getFilename()); 108 109 const char *Exec = Args.MakeArgString((ToolChain.GetProgramPath("as"))); 110 C.addCommand(std::make_unique<Command>(JA, *this, 111 ResponseFileSupport::AtFileCurCP(), 112 Exec, CmdArgs, Inputs, Output)); 113 } 114 115 void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, 116 const InputInfo &Output, 117 const InputInfoList &Inputs, 118 const ArgList &Args, 119 const char *LinkingOutput) const { 120 const toolchains::NetBSD &ToolChain = 121 static_cast<const toolchains::NetBSD &>(getToolChain()); 122 const Driver &D = ToolChain.getDriver(); 123 const llvm::Triple &Triple = ToolChain.getTriple(); 124 125 ArgStringList CmdArgs; 126 127 if (!D.SysRoot.empty()) 128 CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); 129 130 CmdArgs.push_back("--eh-frame-hdr"); 131 if (Args.hasArg(options::OPT_static)) { 132 CmdArgs.push_back("-Bstatic"); 133 if (Args.hasArg(options::OPT_pie)) { 134 Args.AddAllArgs(CmdArgs, options::OPT_pie); 135 CmdArgs.push_back("--no-dynamic-linker"); 136 } 137 } else { 138 if (Args.hasArg(options::OPT_rdynamic)) 139 CmdArgs.push_back("-export-dynamic"); 140 if (Args.hasArg(options::OPT_shared)) { 141 CmdArgs.push_back("-Bshareable"); 142 } else if (!Args.hasArg(options::OPT_r)) { 143 Args.AddAllArgs(CmdArgs, options::OPT_pie); 144 CmdArgs.push_back("-dynamic-linker"); 145 CmdArgs.push_back("/libexec/ld.elf_so"); 146 } 147 } 148 149 // Many NetBSD architectures support more than one ABI. 150 // Determine the correct emulation for ld. 151 switch (ToolChain.getArch()) { 152 case llvm::Triple::x86: 153 CmdArgs.push_back("-m"); 154 CmdArgs.push_back("elf_i386"); 155 break; 156 case llvm::Triple::arm: 157 case llvm::Triple::thumb: 158 CmdArgs.push_back("-m"); 159 switch (Triple.getEnvironment()) { 160 case llvm::Triple::EABI: 161 case llvm::Triple::GNUEABI: 162 CmdArgs.push_back("armelf_nbsd_eabi"); 163 break; 164 case llvm::Triple::EABIHF: 165 case llvm::Triple::GNUEABIHF: 166 CmdArgs.push_back("armelf_nbsd_eabihf"); 167 break; 168 default: 169 CmdArgs.push_back("armelf_nbsd"); 170 break; 171 } 172 break; 173 case llvm::Triple::armeb: 174 case llvm::Triple::thumbeb: 175 arm::appendBE8LinkFlag(Args, CmdArgs, ToolChain.getEffectiveTriple()); 176 CmdArgs.push_back("-m"); 177 switch (Triple.getEnvironment()) { 178 case llvm::Triple::EABI: 179 case llvm::Triple::GNUEABI: 180 CmdArgs.push_back("armelfb_nbsd_eabi"); 181 break; 182 case llvm::Triple::EABIHF: 183 case llvm::Triple::GNUEABIHF: 184 CmdArgs.push_back("armelfb_nbsd_eabihf"); 185 break; 186 default: 187 CmdArgs.push_back("armelfb_nbsd"); 188 break; 189 } 190 break; 191 case llvm::Triple::mips64: 192 case llvm::Triple::mips64el: 193 if (mips::hasMipsAbiArg(Args, "32")) { 194 CmdArgs.push_back("-m"); 195 if (ToolChain.getArch() == llvm::Triple::mips64) 196 CmdArgs.push_back("elf32btsmip"); 197 else 198 CmdArgs.push_back("elf32ltsmip"); 199 } else if (mips::hasMipsAbiArg(Args, "64")) { 200 CmdArgs.push_back("-m"); 201 if (ToolChain.getArch() == llvm::Triple::mips64) 202 CmdArgs.push_back("elf64btsmip"); 203 else 204 CmdArgs.push_back("elf64ltsmip"); 205 } 206 break; 207 case llvm::Triple::ppc: 208 CmdArgs.push_back("-m"); 209 CmdArgs.push_back("elf32ppc_nbsd"); 210 break; 211 212 case llvm::Triple::ppc64: 213 case llvm::Triple::ppc64le: 214 CmdArgs.push_back("-m"); 215 CmdArgs.push_back("elf64ppc"); 216 break; 217 218 case llvm::Triple::sparc: 219 CmdArgs.push_back("-m"); 220 CmdArgs.push_back("elf32_sparc"); 221 break; 222 223 case llvm::Triple::sparcv9: 224 CmdArgs.push_back("-m"); 225 CmdArgs.push_back("elf64_sparc"); 226 break; 227 228 default: 229 break; 230 } 231 232 if (Output.isFilename()) { 233 CmdArgs.push_back("-o"); 234 CmdArgs.push_back(Output.getFilename()); 235 } else { 236 assert(Output.isNothing() && "Invalid output."); 237 } 238 239 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, 240 options::OPT_r)) { 241 if (!Args.hasArg(options::OPT_shared)) { 242 CmdArgs.push_back( 243 Args.MakeArgString(ToolChain.GetFilePath("crt0.o"))); 244 } 245 CmdArgs.push_back( 246 Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); 247 if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) { 248 CmdArgs.push_back( 249 Args.MakeArgString(ToolChain.GetFilePath("crtbeginS.o"))); 250 } else { 251 CmdArgs.push_back( 252 Args.MakeArgString(ToolChain.GetFilePath("crtbegin.o"))); 253 } 254 } 255 256 Args.AddAllArgs(CmdArgs, options::OPT_L); 257 Args.AddAllArgs(CmdArgs, options::OPT_T_Group); 258 Args.AddAllArgs(CmdArgs, options::OPT_e); 259 Args.AddAllArgs(CmdArgs, options::OPT_s); 260 Args.AddAllArgs(CmdArgs, options::OPT_t); 261 Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag); 262 Args.AddAllArgs(CmdArgs, options::OPT_r); 263 264 bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs); 265 bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs); 266 AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); 267 268 const SanitizerArgs &SanArgs = ToolChain.getSanitizerArgs(Args); 269 if (SanArgs.needsSharedRt()) { 270 CmdArgs.push_back("-rpath"); 271 CmdArgs.push_back(Args.MakeArgString(ToolChain.getCompilerRTPath())); 272 } 273 274 VersionTuple OsVersion = Triple.getOSVersion(); 275 bool useLibgcc = true; 276 if (OsVersion >= VersionTuple(7) || OsVersion.getMajor() == 0) { 277 switch (ToolChain.getArch()) { 278 case llvm::Triple::aarch64: 279 case llvm::Triple::aarch64_be: 280 case llvm::Triple::arm: 281 case llvm::Triple::armeb: 282 case llvm::Triple::thumb: 283 case llvm::Triple::thumbeb: 284 case llvm::Triple::ppc: 285 case llvm::Triple::ppc64: 286 case llvm::Triple::ppc64le: 287 case llvm::Triple::sparc: 288 case llvm::Triple::sparcv9: 289 case llvm::Triple::x86: 290 case llvm::Triple::x86_64: 291 useLibgcc = false; 292 break; 293 default: 294 break; 295 } 296 } 297 298 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs, 299 options::OPT_r)) { 300 // Use the static OpenMP runtime with -static-openmp 301 bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && 302 !Args.hasArg(options::OPT_static); 303 addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP); 304 305 if (D.CCCIsCXX()) { 306 if (ToolChain.ShouldLinkCXXStdlib(Args)) 307 ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); 308 CmdArgs.push_back("-lm"); 309 } 310 if (NeedsSanitizerDeps) 311 linkSanitizerRuntimeDeps(ToolChain, CmdArgs); 312 if (NeedsXRayDeps) 313 linkXRayRuntimeDeps(ToolChain, CmdArgs); 314 if (Args.hasArg(options::OPT_pthread)) 315 CmdArgs.push_back("-lpthread"); 316 CmdArgs.push_back("-lc"); 317 318 if (useLibgcc) { 319 if (Args.hasArg(options::OPT_static)) { 320 // libgcc_eh depends on libc, so resolve as much as possible, 321 // pull in any new requirements from libc and then get the rest 322 // of libgcc. 323 CmdArgs.push_back("-lgcc_eh"); 324 CmdArgs.push_back("-lc"); 325 CmdArgs.push_back("-lgcc"); 326 } else { 327 CmdArgs.push_back("-lgcc"); 328 CmdArgs.push_back("--as-needed"); 329 CmdArgs.push_back("-lgcc_s"); 330 CmdArgs.push_back("--no-as-needed"); 331 } 332 } 333 } 334 335 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, 336 options::OPT_r)) { 337 if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) 338 CmdArgs.push_back( 339 Args.MakeArgString(ToolChain.GetFilePath("crtendS.o"))); 340 else 341 CmdArgs.push_back( 342 Args.MakeArgString(ToolChain.GetFilePath("crtend.o"))); 343 CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); 344 } 345 346 ToolChain.addProfileRTLibs(Args, CmdArgs); 347 348 const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); 349 C.addCommand(std::make_unique<Command>(JA, *this, 350 ResponseFileSupport::AtFileCurCP(), 351 Exec, CmdArgs, Inputs, Output)); 352 } 353 354 /// NetBSD - NetBSD tool chain which can call as(1) and ld(1) directly. 355 356 NetBSD::NetBSD(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) 357 : Generic_ELF(D, Triple, Args) { 358 if (!Args.hasArg(options::OPT_nostdlib)) { 359 // When targeting a 32-bit platform, try the special directory used on 360 // 64-bit hosts, and only fall back to the main library directory if that 361 // doesn't work. 362 // FIXME: It'd be nicer to test if this directory exists, but I'm not sure 363 // what all logic is needed to emulate the '=' prefix here. 364 switch (Triple.getArch()) { 365 case llvm::Triple::x86: 366 getFilePaths().push_back("=/usr/lib/i386"); 367 break; 368 case llvm::Triple::arm: 369 case llvm::Triple::armeb: 370 case llvm::Triple::thumb: 371 case llvm::Triple::thumbeb: 372 switch (Triple.getEnvironment()) { 373 case llvm::Triple::EABI: 374 case llvm::Triple::GNUEABI: 375 getFilePaths().push_back("=/usr/lib/eabi"); 376 break; 377 case llvm::Triple::EABIHF: 378 case llvm::Triple::GNUEABIHF: 379 getFilePaths().push_back("=/usr/lib/eabihf"); 380 break; 381 default: 382 getFilePaths().push_back("=/usr/lib/oabi"); 383 break; 384 } 385 break; 386 case llvm::Triple::mips64: 387 case llvm::Triple::mips64el: 388 if (tools::mips::hasMipsAbiArg(Args, "o32")) 389 getFilePaths().push_back("=/usr/lib/o32"); 390 else if (tools::mips::hasMipsAbiArg(Args, "64")) 391 getFilePaths().push_back("=/usr/lib/64"); 392 break; 393 case llvm::Triple::ppc: 394 getFilePaths().push_back("=/usr/lib/powerpc"); 395 break; 396 case llvm::Triple::sparc: 397 getFilePaths().push_back("=/usr/lib/sparc"); 398 break; 399 default: 400 break; 401 } 402 403 getFilePaths().push_back("=/usr/lib"); 404 } 405 } 406 407 Tool *NetBSD::buildAssembler() const { 408 return new tools::netbsd::Assembler(*this); 409 } 410 411 Tool *NetBSD::buildLinker() const { return new tools::netbsd::Linker(*this); } 412 413 ToolChain::CXXStdlibType NetBSD::GetDefaultCXXStdlibType() const { 414 VersionTuple OsVersion = getTriple().getOSVersion(); 415 if (OsVersion >= VersionTuple(7) || OsVersion.getMajor() == 0) { 416 switch (getArch()) { 417 case llvm::Triple::aarch64: 418 case llvm::Triple::aarch64_be: 419 case llvm::Triple::arm: 420 case llvm::Triple::armeb: 421 case llvm::Triple::thumb: 422 case llvm::Triple::thumbeb: 423 case llvm::Triple::ppc: 424 case llvm::Triple::ppc64: 425 case llvm::Triple::ppc64le: 426 case llvm::Triple::sparc: 427 case llvm::Triple::sparcv9: 428 case llvm::Triple::x86: 429 case llvm::Triple::x86_64: 430 return ToolChain::CST_Libcxx; 431 default: 432 break; 433 } 434 } 435 return ToolChain::CST_Libstdcxx; 436 } 437 438 void NetBSD::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, 439 llvm::opt::ArgStringList &CC1Args) const { 440 const std::string Candidates[] = { 441 // directory relative to build tree 442 getDriver().Dir + "/../include/c++/v1", 443 // system install with full upstream path 444 getDriver().SysRoot + "/usr/include/c++/v1", 445 // system install from src 446 getDriver().SysRoot + "/usr/include/c++", 447 }; 448 449 for (const auto &IncludePath : Candidates) { 450 if (!getVFS().exists(IncludePath + "/__config")) 451 continue; 452 453 // Use the first candidate that looks valid. 454 addSystemInclude(DriverArgs, CC1Args, IncludePath); 455 return; 456 } 457 } 458 459 void NetBSD::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, 460 llvm::opt::ArgStringList &CC1Args) const { 461 addLibStdCXXIncludePaths(getDriver().SysRoot + "/usr/include/g++", "", "", 462 DriverArgs, CC1Args); 463 } 464 465 llvm::ExceptionHandling NetBSD::GetExceptionModel(const ArgList &Args) const { 466 // NetBSD uses Dwarf exceptions on ARM. 467 llvm::Triple::ArchType TArch = getTriple().getArch(); 468 if (TArch == llvm::Triple::arm || TArch == llvm::Triple::armeb || 469 TArch == llvm::Triple::thumb || TArch == llvm::Triple::thumbeb) 470 return llvm::ExceptionHandling::DwarfCFI; 471 return llvm::ExceptionHandling::None; 472 } 473 474 SanitizerMask NetBSD::getSupportedSanitizers() const { 475 const bool IsX86 = getTriple().getArch() == llvm::Triple::x86; 476 const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64; 477 SanitizerMask Res = ToolChain::getSupportedSanitizers(); 478 if (IsX86 || IsX86_64) { 479 Res |= SanitizerKind::Address; 480 Res |= SanitizerKind::PointerCompare; 481 Res |= SanitizerKind::PointerSubtract; 482 Res |= SanitizerKind::Function; 483 Res |= SanitizerKind::Leak; 484 Res |= SanitizerKind::SafeStack; 485 Res |= SanitizerKind::Scudo; 486 Res |= SanitizerKind::Vptr; 487 } 488 if (IsX86_64) { 489 Res |= SanitizerKind::DataFlow; 490 Res |= SanitizerKind::Fuzzer; 491 Res |= SanitizerKind::FuzzerNoLink; 492 Res |= SanitizerKind::HWAddress; 493 Res |= SanitizerKind::KernelAddress; 494 Res |= SanitizerKind::KernelHWAddress; 495 Res |= SanitizerKind::KernelMemory; 496 Res |= SanitizerKind::Memory; 497 Res |= SanitizerKind::Thread; 498 } 499 return Res; 500 } 501 502 void NetBSD::addClangTargetOptions(const ArgList &DriverArgs, 503 ArgStringList &CC1Args, 504 Action::OffloadKind) const { 505 const SanitizerArgs &SanArgs = getSanitizerArgs(DriverArgs); 506 if (SanArgs.hasAnySanitizer()) 507 CC1Args.push_back("-D_REENTRANT"); 508 509 VersionTuple OsVersion = getTriple().getOSVersion(); 510 bool UseInitArrayDefault = 511 OsVersion >= VersionTuple(9) || OsVersion.getMajor() == 0 || 512 getTriple().getArch() == llvm::Triple::aarch64 || 513 getTriple().getArch() == llvm::Triple::aarch64_be || 514 getTriple().getArch() == llvm::Triple::arm || 515 getTriple().getArch() == llvm::Triple::armeb; 516 517 if (!DriverArgs.hasFlag(options::OPT_fuse_init_array, 518 options::OPT_fno_use_init_array, UseInitArrayDefault)) 519 CC1Args.push_back("-fno-use-init-array"); 520 } 521