506 lines · cpp
1//===--- FreeBSD.cpp - FreeBSD 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 "FreeBSD.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/SanitizerArgs.h"17#include "clang/Options/Options.h"18#include "llvm/Option/ArgList.h"19#include "llvm/Support/VirtualFileSystem.h"20 21using namespace clang::driver;22using namespace clang::driver::tools;23using namespace clang::driver::toolchains;24using namespace clang;25using namespace llvm::opt;26 27void freebsd::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 auto &ToolChain = static_cast<const FreeBSD &>(getToolChain());33 const auto &D = getToolChain().getDriver();34 const llvm::Triple &Triple = ToolChain.getTriple();35 ArgStringList CmdArgs;36 37 claimNoWarnArgs(Args);38 39 // When building 32-bit code on FreeBSD/amd64, we have to explicitly40 // instruct as in the base system to assemble 32-bit code.41 switch (ToolChain.getArch()) {42 default:43 break;44 case llvm::Triple::x86:45 CmdArgs.push_back("--32");46 break;47 case llvm::Triple::ppc:48 case llvm::Triple::ppcle:49 CmdArgs.push_back("-a32");50 break;51 case llvm::Triple::mips:52 case llvm::Triple::mipsel:53 case llvm::Triple::mips64:54 case llvm::Triple::mips64el: {55 StringRef CPUName;56 StringRef ABIName;57 mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName);58 59 CmdArgs.push_back("-march");60 CmdArgs.push_back(CPUName.data());61 62 CmdArgs.push_back("-mabi");63 CmdArgs.push_back(mips::getGnuCompatibleMipsABIName(ABIName).data());64 65 if (Triple.isLittleEndian())66 CmdArgs.push_back("-EL");67 else68 CmdArgs.push_back("-EB");69 70 if (Arg *A = Args.getLastArg(options::OPT_G)) {71 StringRef v = A->getValue();72 CmdArgs.push_back(Args.MakeArgString("-G" + v));73 A->claim();74 }75 76 AddAssemblerKPIC(ToolChain, Args, CmdArgs);77 break;78 }79 case llvm::Triple::arm:80 case llvm::Triple::armeb:81 case llvm::Triple::thumb:82 case llvm::Triple::thumbeb: {83 arm::FloatABI ABI = arm::getARMFloatABI(ToolChain, Args);84 85 if (ABI == arm::FloatABI::Hard)86 CmdArgs.push_back("-mfpu=vfp");87 else88 CmdArgs.push_back("-mfpu=softvfp");89 90 CmdArgs.push_back("-meabi=5");91 break;92 }93 case llvm::Triple::sparcv9: {94 std::string CPU = getCPUName(D, Args, Triple);95 CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, Triple));96 AddAssemblerKPIC(ToolChain, Args, CmdArgs);97 break;98 }99 }100 101 for (const Arg *A : Args.filtered(options::OPT_ffile_prefix_map_EQ,102 options::OPT_fdebug_prefix_map_EQ)) {103 StringRef Map = A->getValue();104 if (!Map.contains('='))105 D.Diag(diag::err_drv_invalid_argument_to_option)106 << Map << A->getOption().getName();107 else {108 CmdArgs.push_back(Args.MakeArgString("--debug-prefix-map"));109 CmdArgs.push_back(Args.MakeArgString(Map));110 }111 A->claim();112 }113 114 Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);115 116 CmdArgs.push_back("-o");117 CmdArgs.push_back(Output.getFilename());118 119 for (const auto &II : Inputs)120 CmdArgs.push_back(II.getFilename());121 122 const char *Exec = Args.MakeArgString(ToolChain.GetProgramPath("as"));123 C.addCommand(std::make_unique<Command>(JA, *this,124 ResponseFileSupport::AtFileCurCP(),125 Exec, CmdArgs, Inputs, Output));126}127 128void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,129 const InputInfo &Output,130 const InputInfoList &Inputs,131 const ArgList &Args,132 const char *LinkingOutput) const {133 const auto &ToolChain = static_cast<const FreeBSD &>(getToolChain());134 const Driver &D = ToolChain.getDriver();135 const llvm::Triple &Triple = ToolChain.getTriple();136 const llvm::Triple::ArchType Arch = ToolChain.getArch();137 const bool IsPIE =138 !Args.hasArg(options::OPT_shared) &&139 (Args.hasArg(options::OPT_pie) || ToolChain.isPIEDefault(Args));140 ArgStringList CmdArgs;141 142 // Silence warning for "clang -g foo.o -o foo"143 Args.ClaimAllArgs(options::OPT_g_Group);144 // and "clang -emit-llvm foo.o -o foo"145 Args.ClaimAllArgs(options::OPT_emit_llvm);146 // and for "clang -w foo.o -o foo". Other warning options are already147 // handled somewhere else.148 Args.ClaimAllArgs(options::OPT_w);149 150 if (!D.SysRoot.empty())151 CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));152 153 if (IsPIE)154 CmdArgs.push_back("-pie");155 156 CmdArgs.push_back("--eh-frame-hdr");157 if (Args.hasArg(options::OPT_static)) {158 CmdArgs.push_back("-Bstatic");159 } else {160 if (Args.hasArg(options::OPT_rdynamic))161 CmdArgs.push_back("-export-dynamic");162 if (Args.hasArg(options::OPT_shared)) {163 CmdArgs.push_back("-shared");164 } else if (!Args.hasArg(options::OPT_r)) {165 CmdArgs.push_back("-dynamic-linker");166 CmdArgs.push_back("/libexec/ld-elf.so.1");167 }168 if (Arch == llvm::Triple::arm || Triple.isX86())169 CmdArgs.push_back("--hash-style=both");170 CmdArgs.push_back("--enable-new-dtags");171 }172 173 // Explicitly set the linker emulation for platforms that might not174 // be the default emulation for the linker.175 switch (Arch) {176 case llvm::Triple::x86:177 CmdArgs.push_back("-m");178 CmdArgs.push_back("elf_i386_fbsd");179 break;180 case llvm::Triple::ppc:181 CmdArgs.push_back("-m");182 CmdArgs.push_back("elf32ppc_fbsd");183 break;184 case llvm::Triple::ppcle:185 CmdArgs.push_back("-m");186 // Use generic -- only usage is for freestanding.187 CmdArgs.push_back("elf32lppc");188 break;189 case llvm::Triple::mips:190 CmdArgs.push_back("-m");191 CmdArgs.push_back("elf32btsmip_fbsd");192 break;193 case llvm::Triple::mipsel:194 CmdArgs.push_back("-m");195 CmdArgs.push_back("elf32ltsmip_fbsd");196 break;197 case llvm::Triple::mips64:198 CmdArgs.push_back("-m");199 if (tools::mips::hasMipsAbiArg(Args, "n32"))200 CmdArgs.push_back("elf32btsmipn32_fbsd");201 else202 CmdArgs.push_back("elf64btsmip_fbsd");203 break;204 case llvm::Triple::mips64el:205 CmdArgs.push_back("-m");206 if (tools::mips::hasMipsAbiArg(Args, "n32"))207 CmdArgs.push_back("elf32ltsmipn32_fbsd");208 else209 CmdArgs.push_back("elf64ltsmip_fbsd");210 break;211 case llvm::Triple::riscv64:212 CmdArgs.push_back("-m");213 CmdArgs.push_back("elf64lriscv");214 break;215 case llvm::Triple::loongarch64:216 CmdArgs.push_back("-m");217 CmdArgs.push_back("elf64loongarch");218 break;219 default:220 break;221 }222 223 if (Triple.isLoongArch64() || Triple.isRISCV64()) {224 CmdArgs.push_back("-X");225 if (Args.hasArg(options::OPT_mno_relax))226 CmdArgs.push_back("--no-relax");227 }228 229 if (Arg *A = Args.getLastArg(options::OPT_G)) {230 if (ToolChain.getTriple().isMIPS()) {231 StringRef v = A->getValue();232 CmdArgs.push_back(Args.MakeArgString("-G" + v));233 A->claim();234 }235 }236 237 assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");238 if (Output.isFilename()) {239 CmdArgs.push_back("-o");240 CmdArgs.push_back(Output.getFilename());241 }242 243 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,244 options::OPT_r)) {245 const char *crt1 = nullptr;246 if (!Args.hasArg(options::OPT_shared)) {247 if (Args.hasArg(options::OPT_pg))248 crt1 = "gcrt1.o";249 else if (IsPIE)250 crt1 = "Scrt1.o";251 else252 crt1 = "crt1.o";253 }254 if (crt1)255 CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt1)));256 257 CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o")));258 259 const char *crtbegin = nullptr;260 if (Args.hasArg(options::OPT_static))261 crtbegin = "crtbeginT.o";262 else if (Args.hasArg(options::OPT_shared) || IsPIE)263 crtbegin = "crtbeginS.o";264 else265 crtbegin = "crtbegin.o";266 267 CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin)));268 }269 270 Args.AddAllArgs(CmdArgs, options::OPT_L);271 ToolChain.AddFilePathLibArgs(Args, CmdArgs);272 Args.addAllArgs(CmdArgs,273 {options::OPT_T_Group, options::OPT_s, options::OPT_t});274 275 if (D.isUsingLTO())276 addLTOOptions(ToolChain, Args, CmdArgs, Output, Inputs,277 D.getLTOMode() == LTOK_Thin);278 279 bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs);280 bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs);281 addLinkerCompressDebugSectionsOption(ToolChain, Args, CmdArgs);282 AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);283 284 unsigned Major = ToolChain.getTriple().getOSMajorVersion();285 bool Profiling = Args.hasArg(options::OPT_pg) && Major != 0 && Major < 14;286 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs,287 options::OPT_r)) {288 // Use the static OpenMP runtime with -static-openmp289 bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) &&290 !Args.hasArg(options::OPT_static);291 addOpenMPRuntime(C, CmdArgs, ToolChain, Args, StaticOpenMP);292 293 if (D.CCCIsCXX()) {294 if (ToolChain.ShouldLinkCXXStdlib(Args))295 ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);296 if (Profiling)297 CmdArgs.push_back("-lm_p");298 else299 CmdArgs.push_back("-lm");300 }301 302 // Silence warnings when linking C code with a C++ '-stdlib' argument.303 Args.ClaimAllArgs(options::OPT_stdlib_EQ);304 305 // Additional linker set-up and flags for Fortran. This is required in order306 // to generate executables. As Fortran runtime depends on the C runtime,307 // these dependencies need to be listed before the C runtime below (i.e.308 // AddRunTimeLibs).309 if (D.IsFlangMode() &&310 !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {311 ToolChain.addFortranRuntimeLibraryPath(Args, CmdArgs);312 ToolChain.addFortranRuntimeLibs(Args, CmdArgs);313 if (Profiling)314 CmdArgs.push_back("-lm_p");315 else316 CmdArgs.push_back("-lm");317 }318 319 if (NeedsSanitizerDeps)320 linkSanitizerRuntimeDeps(ToolChain, Args, CmdArgs);321 if (NeedsXRayDeps)322 linkXRayRuntimeDeps(ToolChain, Args, CmdArgs);323 // FIXME: For some reason GCC passes -lgcc and -lgcc_s before adding324 // the default system libraries. Just mimic this for now.325 if (Profiling)326 CmdArgs.push_back("-lgcc_p");327 else328 CmdArgs.push_back("-lgcc");329 if (Args.hasArg(options::OPT_static)) {330 CmdArgs.push_back("-lgcc_eh");331 } else if (Profiling) {332 CmdArgs.push_back("-lgcc_eh_p");333 } else {334 CmdArgs.push_back("--as-needed");335 CmdArgs.push_back("-lgcc_s");336 CmdArgs.push_back("--no-as-needed");337 }338 339 if (Args.hasArg(options::OPT_pthread)) {340 if (Profiling)341 CmdArgs.push_back("-lpthread_p");342 else343 CmdArgs.push_back("-lpthread");344 }345 346 if (Profiling) {347 if (Args.hasArg(options::OPT_shared))348 CmdArgs.push_back("-lc");349 else350 CmdArgs.push_back("-lc_p");351 CmdArgs.push_back("-lgcc_p");352 } else {353 CmdArgs.push_back("-lc");354 CmdArgs.push_back("-lgcc");355 }356 357 if (Args.hasArg(options::OPT_static)) {358 CmdArgs.push_back("-lgcc_eh");359 } else if (Profiling) {360 CmdArgs.push_back("-lgcc_eh_p");361 } else {362 CmdArgs.push_back("--as-needed");363 CmdArgs.push_back("-lgcc_s");364 CmdArgs.push_back("--no-as-needed");365 }366 }367 368 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,369 options::OPT_r)) {370 const char *crtend = nullptr;371 if (Args.hasArg(options::OPT_shared) || IsPIE)372 crtend = "crtendS.o";373 else374 crtend = "crtend.o";375 CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend)));376 CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o")));377 }378 379 ToolChain.addProfileRTLibs(Args, CmdArgs);380 381 const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());382 C.addCommand(std::make_unique<Command>(JA, *this,383 ResponseFileSupport::AtFileCurCP(),384 Exec, CmdArgs, Inputs, Output));385}386 387/// FreeBSD - FreeBSD tool chain which can call as(1) and ld(1) directly.388 389FreeBSD::FreeBSD(const Driver &D, const llvm::Triple &Triple,390 const ArgList &Args)391 : Generic_ELF(D, Triple, Args) {392 393 // When targeting 32-bit platforms, look for '/usr/lib32/crt1.o' and fall394 // back to '/usr/lib' if it doesn't exist.395 if (Triple.isArch32Bit() &&396 D.getVFS().exists(concat(getDriver().SysRoot, "/usr/lib32/crt1.o")))397 getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib32"));398 else399 getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib"));400}401 402void FreeBSD::AddClangSystemIncludeArgs(403 const llvm::opt::ArgList &DriverArgs,404 llvm::opt::ArgStringList &CC1Args) const {405 const Driver &D = getDriver();406 407 if (DriverArgs.hasArg(options::OPT_nostdinc))408 return;409 410 if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {411 SmallString<128> Dir(D.ResourceDir);412 llvm::sys::path::append(Dir, "include");413 addSystemInclude(DriverArgs, CC1Args, Dir.str());414 }415 416 if (DriverArgs.hasArg(options::OPT_nostdlibinc))417 return;418 419 // Check for configure-time C include directories.420 StringRef CIncludeDirs(C_INCLUDE_DIRS);421 if (CIncludeDirs != "") {422 SmallVector<StringRef, 5> dirs;423 CIncludeDirs.split(dirs, ":");424 for (StringRef dir : dirs) {425 StringRef Prefix =426 llvm::sys::path::is_absolute(dir) ? StringRef(D.SysRoot) : "";427 addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir);428 }429 return;430 }431 432 addExternCSystemInclude(DriverArgs, CC1Args,433 concat(D.SysRoot, "/usr/include"));434}435 436void FreeBSD::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,437 llvm::opt::ArgStringList &CC1Args) const {438 addSystemInclude(DriverArgs, CC1Args,439 concat(getDriver().SysRoot, "/usr/include/c++/v1"));440}441 442void FreeBSD::AddCXXStdlibLibArgs(const ArgList &Args,443 ArgStringList &CmdArgs) const {444 Generic_ELF::AddCXXStdlibLibArgs(Args, CmdArgs);445 unsigned Major = getTriple().getOSMajorVersion();446 bool SuffixedLib = Args.hasArg(options::OPT_pg) && Major != 0 && Major < 14;447 if (SuffixedLib && GetCXXStdlibType(Args) == CST_Libcxx)448 std::replace_if(449 CmdArgs.begin(), CmdArgs.end(),450 [](const char *S) { return StringRef(S) == "-lc++"; }, "-lc++_p");451}452 453void FreeBSD::AddCudaIncludeArgs(const ArgList &DriverArgs,454 ArgStringList &CC1Args) const {455 CudaInstallation->AddCudaIncludeArgs(DriverArgs, CC1Args);456}457 458void FreeBSD::AddHIPIncludeArgs(const ArgList &DriverArgs,459 ArgStringList &CC1Args) const {460 RocmInstallation->AddHIPIncludeArgs(DriverArgs, CC1Args);461}462 463Tool *FreeBSD::buildAssembler() const {464 return new tools::freebsd::Assembler(*this);465}466 467Tool *FreeBSD::buildLinker() const { return new tools::freebsd::Linker(*this); }468 469bool FreeBSD::HasNativeLLVMSupport() const { return true; }470 471ToolChain::UnwindTableLevel472FreeBSD::getDefaultUnwindTableLevel(const ArgList &Args) const {473 return UnwindTableLevel::Asynchronous;474}475 476bool FreeBSD::isPIEDefault(const llvm::opt::ArgList &Args) const {477 return getSanitizerArgs(Args).requiresPIE();478}479 480SanitizerMask FreeBSD::getSupportedSanitizers() const {481 const bool IsAArch64 = getTriple().getArch() == llvm::Triple::aarch64;482 const bool IsX86 = getTriple().getArch() == llvm::Triple::x86;483 const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64;484 const bool IsMIPS64 = getTriple().isMIPS64();485 SanitizerMask Res = ToolChain::getSupportedSanitizers();486 Res |= SanitizerKind::Address;487 Res |= SanitizerKind::PointerCompare;488 Res |= SanitizerKind::PointerSubtract;489 Res |= SanitizerKind::Vptr;490 if (IsAArch64 || IsX86_64 || IsMIPS64) {491 Res |= SanitizerKind::Leak;492 Res |= SanitizerKind::Thread;493 }494 if (IsAArch64 || IsX86 || IsX86_64) {495 Res |= SanitizerKind::SafeStack;496 Res |= SanitizerKind::Fuzzer;497 Res |= SanitizerKind::FuzzerNoLink;498 }499 if (IsAArch64 || IsX86_64) {500 Res |= SanitizerKind::KernelAddress;501 Res |= SanitizerKind::KernelMemory;502 Res |= SanitizerKind::Memory;503 }504 return Res;505}506