568 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "NetBSD.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/Driver.h"17#include "clang/Driver/SanitizerArgs.h"18#include "clang/Options/Options.h"19#include "llvm/Option/ArgList.h"20#include "llvm/Support/VirtualFileSystem.h"21 22using namespace clang::driver;23using namespace clang::driver::tools;24using namespace clang::driver::toolchains;25using namespace clang;26using namespace llvm::opt;27 28void netbsd::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 NetBSD &>(getToolChain());34 const Driver &D = ToolChain.getDriver();35 const llvm::Triple &Triple = ToolChain.getTriple();36 ArgStringList CmdArgs;37 38 claimNoWarnArgs(Args);39 40 // GNU as needs different flags for creating the correct output format41 // 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 else74 CmdArgs.push_back("-EB");75 76 AddAssemblerKPIC(ToolChain, Args, CmdArgs);77 break;78 }79 80 case llvm::Triple::sparc: {81 CmdArgs.push_back("-32");82 std::string CPU = getCPUName(D, Args, Triple);83 CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, Triple));84 AddAssemblerKPIC(ToolChain, Args, CmdArgs);85 break;86 }87 88 case llvm::Triple::sparcv9: {89 CmdArgs.push_back("-64");90 std::string CPU = getCPUName(D, Args, Triple);91 CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, Triple));92 AddAssemblerKPIC(ToolChain, Args, CmdArgs);93 break;94 }95 96 default:97 break;98 }99 100 Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);101 102 CmdArgs.push_back("-o");103 CmdArgs.push_back(Output.getFilename());104 105 for (const auto &II : Inputs)106 CmdArgs.push_back(II.getFilename());107 108 const char *Exec = Args.MakeArgString((ToolChain.GetProgramPath("as")));109 C.addCommand(std::make_unique<Command>(JA, *this,110 ResponseFileSupport::AtFileCurCP(),111 Exec, CmdArgs, Inputs, Output));112}113 114void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,115 const InputInfo &Output,116 const InputInfoList &Inputs,117 const ArgList &Args,118 const char *LinkingOutput) const {119 const auto &ToolChain = static_cast<const NetBSD &>(getToolChain());120 const Driver &D = ToolChain.getDriver();121 const llvm::Triple &Triple = ToolChain.getTriple();122 const llvm::Triple::ArchType Arch = ToolChain.getArch();123 const bool Static = Args.hasArg(options::OPT_static);124 const bool Shared = Args.hasArg(options::OPT_shared);125 const bool Pie = Args.hasArg(options::OPT_pie);126 ArgStringList CmdArgs;127 128 if (!D.SysRoot.empty())129 CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));130 131 CmdArgs.push_back("--eh-frame-hdr");132 if (Static) {133 CmdArgs.push_back("-Bstatic");134 if (Pie) {135 Args.AddAllArgs(CmdArgs, options::OPT_pie);136 CmdArgs.push_back("--no-dynamic-linker");137 }138 } else {139 if (Args.hasArg(options::OPT_rdynamic))140 CmdArgs.push_back("-export-dynamic");141 if (Shared) {142 CmdArgs.push_back("-shared");143 } else if (!Args.hasArg(options::OPT_r)) {144 Args.AddAllArgs(CmdArgs, options::OPT_pie);145 CmdArgs.push_back("-dynamic-linker");146 CmdArgs.push_back("/libexec/ld.elf_so");147 }148 }149 150 // Many NetBSD architectures support more than one ABI.151 // Determine the correct emulation for ld.152 switch (Arch) {153 case llvm::Triple::x86:154 CmdArgs.push_back("-m");155 CmdArgs.push_back("elf_i386");156 break;157 case llvm::Triple::arm:158 case llvm::Triple::thumb:159 CmdArgs.push_back("-m");160 switch (Triple.getEnvironment()) {161 case llvm::Triple::EABI:162 case llvm::Triple::GNUEABI:163 CmdArgs.push_back("armelf_nbsd_eabi");164 break;165 case llvm::Triple::EABIHF:166 case llvm::Triple::GNUEABIHF:167 CmdArgs.push_back("armelf_nbsd_eabihf");168 break;169 default:170 CmdArgs.push_back("armelf_nbsd");171 break;172 }173 break;174 case llvm::Triple::armeb:175 case llvm::Triple::thumbeb:176 arm::appendBE8LinkFlag(Args, CmdArgs, ToolChain.getEffectiveTriple());177 CmdArgs.push_back("-m");178 switch (Triple.getEnvironment()) {179 case llvm::Triple::EABI:180 case llvm::Triple::GNUEABI:181 CmdArgs.push_back("armelfb_nbsd_eabi");182 break;183 case llvm::Triple::EABIHF:184 case llvm::Triple::GNUEABIHF:185 CmdArgs.push_back("armelfb_nbsd_eabihf");186 break;187 default:188 CmdArgs.push_back("armelfb_nbsd");189 break;190 }191 break;192 case llvm::Triple::mips64:193 case llvm::Triple::mips64el:194 if (mips::hasMipsAbiArg(Args, "32")) {195 CmdArgs.push_back("-m");196 if (Arch == llvm::Triple::mips64)197 CmdArgs.push_back("elf32btsmip");198 else199 CmdArgs.push_back("elf32ltsmip");200 } else if (mips::hasMipsAbiArg(Args, "64")) {201 CmdArgs.push_back("-m");202 if (Arch == llvm::Triple::mips64)203 CmdArgs.push_back("elf64btsmip");204 else205 CmdArgs.push_back("elf64ltsmip");206 }207 break;208 case llvm::Triple::ppc:209 CmdArgs.push_back("-m");210 CmdArgs.push_back("elf32ppc_nbsd");211 break;212 213 case llvm::Triple::ppc64:214 case llvm::Triple::ppc64le:215 CmdArgs.push_back("-m");216 CmdArgs.push_back("elf64ppc");217 break;218 219 case llvm::Triple::riscv32:220 CmdArgs.push_back("-m");221 CmdArgs.push_back("elf32lriscv");222 break;223 224 case llvm::Triple::riscv64:225 CmdArgs.push_back("-m");226 CmdArgs.push_back("elf64lriscv");227 break;228 229 case llvm::Triple::sparc:230 CmdArgs.push_back("-m");231 CmdArgs.push_back("elf32_sparc");232 break;233 234 case llvm::Triple::sparcv9:235 CmdArgs.push_back("-m");236 CmdArgs.push_back("elf64_sparc");237 break;238 239 default:240 break;241 }242 243 if (Triple.isRISCV()) {244 CmdArgs.push_back("-X");245 if (Args.hasArg(options::OPT_mno_relax))246 CmdArgs.push_back("--no-relax");247 }248 249 assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");250 if (Output.isFilename()) {251 CmdArgs.push_back("-o");252 CmdArgs.push_back(Output.getFilename());253 }254 255 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,256 options::OPT_r)) {257 const char *crt0 = nullptr;258 const char *crtbegin = nullptr;259 if (!Shared)260 crt0 = "crt0.o";261 262 if (Shared || Pie)263 crtbegin = "crtbeginS.o";264 else265 crtbegin = "crtbegin.o";266 267 if (crt0)268 CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt0)));269 CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o")));270 CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin)));271 }272 273 Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group,274 options::OPT_s, options::OPT_t});275 ToolChain.AddFilePathLibArgs(Args, CmdArgs);276 277 bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs);278 bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs);279 AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);280 281 const SanitizerArgs &SanArgs = ToolChain.getSanitizerArgs(Args);282 if (SanArgs.needsSharedRt()) {283 CmdArgs.push_back("-rpath");284 CmdArgs.push_back(Args.MakeArgString(ToolChain.getCompilerRTPath()));285 }286 287 bool useLibgcc = true;288 switch (ToolChain.getArch()) {289 case llvm::Triple::aarch64:290 case llvm::Triple::aarch64_be:291 case llvm::Triple::arm:292 case llvm::Triple::armeb:293 case llvm::Triple::thumb:294 case llvm::Triple::thumbeb:295 case llvm::Triple::ppc:296 case llvm::Triple::ppc64:297 case llvm::Triple::ppc64le:298 case llvm::Triple::riscv32:299 case llvm::Triple::riscv64:300 case llvm::Triple::sparc:301 case llvm::Triple::sparcv9:302 case llvm::Triple::x86:303 case llvm::Triple::x86_64:304 useLibgcc = false;305 break;306 default:307 break;308 }309 310 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs,311 options::OPT_r)) {312 // Use the static OpenMP runtime with -static-openmp313 bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && !Static;314 addOpenMPRuntime(C, CmdArgs, ToolChain, Args, StaticOpenMP);315 316 if (D.CCCIsCXX()) {317 if (ToolChain.ShouldLinkCXXStdlib(Args))318 ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);319 CmdArgs.push_back("-lm");320 }321 322 // Silence warnings when linking C code with a C++ '-stdlib' argument.323 Args.ClaimAllArgs(options::OPT_stdlib_EQ);324 325 // Additional linker set-up and flags for Fortran. This is required in order326 // to generate executables. As Fortran runtime depends on the C runtime,327 // these dependencies need to be listed before the C runtime below (i.e.328 // AddRunTimeLibs).329 if (D.IsFlangMode() &&330 !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {331 ToolChain.addFortranRuntimeLibraryPath(Args, CmdArgs);332 ToolChain.addFortranRuntimeLibs(Args, CmdArgs);333 CmdArgs.push_back("-lm");334 }335 336 if (NeedsSanitizerDeps)337 linkSanitizerRuntimeDeps(ToolChain, Args, CmdArgs);338 if (NeedsXRayDeps)339 linkXRayRuntimeDeps(ToolChain, Args, CmdArgs);340 if (Args.hasArg(options::OPT_pthread))341 CmdArgs.push_back("-lpthread");342 CmdArgs.push_back("-lc");343 344 if (useLibgcc) {345 if (Static) {346 // libgcc_eh depends on libc, so resolve as much as possible,347 // pull in any new requirements from libc and then get the rest348 // of libgcc.349 CmdArgs.push_back("-lgcc_eh");350 CmdArgs.push_back("-lc");351 CmdArgs.push_back("-lgcc");352 } else {353 CmdArgs.push_back("-lgcc");354 CmdArgs.push_back("--as-needed");355 CmdArgs.push_back("-lgcc_s");356 CmdArgs.push_back("--no-as-needed");357 }358 }359 }360 361 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,362 options::OPT_r)) {363 const char *crtend = nullptr;364 if (Shared || Pie)365 crtend = "crtendS.o";366 else367 crtend = "crtend.o";368 369 CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend)));370 CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o")));371 }372 373 ToolChain.addProfileRTLibs(Args, CmdArgs);374 375 const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());376 C.addCommand(std::make_unique<Command>(JA, *this,377 ResponseFileSupport::AtFileCurCP(),378 Exec, CmdArgs, Inputs, Output));379}380 381/// NetBSD - NetBSD tool chain which can call as(1) and ld(1) directly.382 383NetBSD::NetBSD(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)384 : Generic_ELF(D, Triple, Args) {385 if (!Args.hasArg(options::OPT_nostdlib)) {386 // When targeting a 32-bit platform, try the special directory used on387 // 64-bit hosts, and only fall back to the main library directory if that388 // doesn't work.389 // FIXME: It'd be nicer to test if this directory exists, but I'm not sure390 // what all logic is needed to emulate the '=' prefix here.391 switch (Triple.getArch()) {392 case llvm::Triple::x86:393 getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib/i386"));394 break;395 case llvm::Triple::arm:396 case llvm::Triple::armeb:397 case llvm::Triple::thumb:398 case llvm::Triple::thumbeb:399 switch (Triple.getEnvironment()) {400 case llvm::Triple::EABI:401 case llvm::Triple::GNUEABI:402 getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib/eabi"));403 break;404 case llvm::Triple::EABIHF:405 case llvm::Triple::GNUEABIHF:406 getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib/eabihf"));407 break;408 default:409 getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib/oabi"));410 break;411 }412 break;413 case llvm::Triple::mips64:414 case llvm::Triple::mips64el:415 if (tools::mips::hasMipsAbiArg(Args, "o32"))416 getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib/o32"));417 else if (tools::mips::hasMipsAbiArg(Args, "64"))418 getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib/64"));419 break;420 case llvm::Triple::ppc:421 getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib/powerpc"));422 break;423 case llvm::Triple::sparc:424 getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib/sparc"));425 break;426 default:427 break;428 }429 430 getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib"));431 }432}433 434Tool *NetBSD::buildAssembler() const {435 return new tools::netbsd::Assembler(*this);436}437 438Tool *NetBSD::buildLinker() const { return new tools::netbsd::Linker(*this); }439 440ToolChain::CXXStdlibType NetBSD::GetDefaultCXXStdlibType() const {441 switch (getArch()) {442 case llvm::Triple::aarch64:443 case llvm::Triple::aarch64_be:444 case llvm::Triple::arm:445 case llvm::Triple::armeb:446 case llvm::Triple::thumb:447 case llvm::Triple::thumbeb:448 case llvm::Triple::ppc:449 case llvm::Triple::ppc64:450 case llvm::Triple::ppc64le:451 case llvm::Triple::riscv32:452 case llvm::Triple::riscv64:453 case llvm::Triple::sparc:454 case llvm::Triple::sparcv9:455 case llvm::Triple::x86:456 case llvm::Triple::x86_64:457 return ToolChain::CST_Libcxx;458 default:459 break;460 }461 return ToolChain::CST_Libstdcxx;462}463 464void NetBSD::AddClangSystemIncludeArgs(465 const llvm::opt::ArgList &DriverArgs,466 llvm::opt::ArgStringList &CC1Args) const {467 const Driver &D = getDriver();468 469 if (DriverArgs.hasArg(options::OPT_nostdinc))470 return;471 472 if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {473 SmallString<128> Dir(D.ResourceDir);474 llvm::sys::path::append(Dir, "include");475 addSystemInclude(DriverArgs, CC1Args, Dir.str());476 }477 478 if (DriverArgs.hasArg(options::OPT_nostdlibinc))479 return;480 481 // Check for configure-time C include directories.482 StringRef CIncludeDirs(C_INCLUDE_DIRS);483 if (CIncludeDirs != "") {484 SmallVector<StringRef, 5> dirs;485 CIncludeDirs.split(dirs, ":");486 for (StringRef dir : dirs) {487 StringRef Prefix =488 llvm::sys::path::is_absolute(dir) ? StringRef(D.SysRoot) : "";489 addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir);490 }491 return;492 }493 494 addExternCSystemInclude(DriverArgs, CC1Args,495 concat(D.SysRoot, "/usr/include"));496}497 498void NetBSD::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,499 llvm::opt::ArgStringList &CC1Args) const {500 const std::string Candidates[] = {501 // directory relative to build tree502 concat(getDriver().Dir, "/../include/c++/v1"),503 // system install with full upstream path504 concat(getDriver().SysRoot, "/usr/include/c++/v1"),505 // system install from src506 concat(getDriver().SysRoot, "/usr/include/c++"),507 };508 509 for (const auto &IncludePath : Candidates) {510 if (!getVFS().exists(IncludePath + "/__config"))511 continue;512 513 // Use the first candidate that looks valid.514 addSystemInclude(DriverArgs, CC1Args, IncludePath);515 return;516 }517}518 519void NetBSD::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,520 llvm::opt::ArgStringList &CC1Args) const {521 addLibStdCXXIncludePaths(concat(getDriver().SysRoot, "/usr/include/g++"), "", "",522 DriverArgs, CC1Args);523}524 525llvm::ExceptionHandling NetBSD::GetExceptionModel(const ArgList &Args) const {526 // NetBSD uses Dwarf exceptions on ARM.527 llvm::Triple::ArchType TArch = getTriple().getArch();528 if (TArch == llvm::Triple::arm || TArch == llvm::Triple::armeb ||529 TArch == llvm::Triple::thumb || TArch == llvm::Triple::thumbeb)530 return llvm::ExceptionHandling::DwarfCFI;531 return llvm::ExceptionHandling::None;532}533 534SanitizerMask NetBSD::getSupportedSanitizers() const {535 const bool IsX86 = getTriple().getArch() == llvm::Triple::x86;536 const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64;537 SanitizerMask Res = ToolChain::getSupportedSanitizers();538 if (IsX86 || IsX86_64) {539 Res |= SanitizerKind::Address;540 Res |= SanitizerKind::PointerCompare;541 Res |= SanitizerKind::PointerSubtract;542 Res |= SanitizerKind::Leak;543 Res |= SanitizerKind::SafeStack;544 Res |= SanitizerKind::Scudo;545 Res |= SanitizerKind::Vptr;546 }547 if (IsX86_64) {548 Res |= SanitizerKind::DataFlow;549 Res |= SanitizerKind::Fuzzer;550 Res |= SanitizerKind::FuzzerNoLink;551 Res |= SanitizerKind::HWAddress;552 Res |= SanitizerKind::KernelAddress;553 Res |= SanitizerKind::KernelHWAddress;554 Res |= SanitizerKind::KernelMemory;555 Res |= SanitizerKind::Memory;556 Res |= SanitizerKind::Thread;557 }558 return Res;559}560 561void NetBSD::addClangTargetOptions(const ArgList &DriverArgs,562 ArgStringList &CC1Args,563 Action::OffloadKind) const {564 const SanitizerArgs &SanArgs = getSanitizerArgs(DriverArgs);565 if (SanArgs.hasAnySanitizer())566 CC1Args.push_back("-D_REENTRANT");567}568