Path: blob/main/contrib/llvm-project/clang/lib/Driver/ToolChains/FreeBSD.cpp
35269 views
//===--- FreeBSD.cpp - FreeBSD ToolChain Implementations --------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "FreeBSD.h"9#include "Arch/ARM.h"10#include "Arch/Mips.h"11#include "Arch/Sparc.h"12#include "CommonArgs.h"13#include "clang/Config/config.h"14#include "clang/Driver/Compilation.h"15#include "clang/Driver/DriverDiagnostic.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"2021using namespace clang::driver;22using namespace clang::driver::tools;23using namespace clang::driver::toolchains;24using namespace clang;25using namespace llvm::opt;2627void freebsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA,28const InputInfo &Output,29const InputInfoList &Inputs,30const ArgList &Args,31const char *LinkingOutput) const {32const auto &ToolChain = static_cast<const FreeBSD &>(getToolChain());33const auto &D = getToolChain().getDriver();34const llvm::Triple &Triple = ToolChain.getTriple();35ArgStringList CmdArgs;3637claimNoWarnArgs(Args);3839// When building 32-bit code on FreeBSD/amd64, we have to explicitly40// instruct as in the base system to assemble 32-bit code.41switch (ToolChain.getArch()) {42default:43break;44case llvm::Triple::x86:45CmdArgs.push_back("--32");46break;47case llvm::Triple::ppc:48case llvm::Triple::ppcle:49CmdArgs.push_back("-a32");50break;51case llvm::Triple::mips:52case llvm::Triple::mipsel:53case llvm::Triple::mips64:54case llvm::Triple::mips64el: {55StringRef CPUName;56StringRef ABIName;57mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName);5859CmdArgs.push_back("-march");60CmdArgs.push_back(CPUName.data());6162CmdArgs.push_back("-mabi");63CmdArgs.push_back(mips::getGnuCompatibleMipsABIName(ABIName).data());6465if (Triple.isLittleEndian())66CmdArgs.push_back("-EL");67else68CmdArgs.push_back("-EB");6970if (Arg *A = Args.getLastArg(options::OPT_G)) {71StringRef v = A->getValue();72CmdArgs.push_back(Args.MakeArgString("-G" + v));73A->claim();74}7576AddAssemblerKPIC(ToolChain, Args, CmdArgs);77break;78}79case llvm::Triple::arm:80case llvm::Triple::armeb:81case llvm::Triple::thumb:82case llvm::Triple::thumbeb: {83arm::FloatABI ABI = arm::getARMFloatABI(ToolChain, Args);8485if (ABI == arm::FloatABI::Hard)86CmdArgs.push_back("-mfpu=vfp");87else88CmdArgs.push_back("-mfpu=softvfp");8990CmdArgs.push_back("-meabi=5");91break;92}93case llvm::Triple::sparcv9: {94std::string CPU = getCPUName(D, Args, Triple);95CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, Triple));96AddAssemblerKPIC(ToolChain, Args, CmdArgs);97break;98}99}100101for (const Arg *A : Args.filtered(options::OPT_ffile_prefix_map_EQ,102options::OPT_fdebug_prefix_map_EQ)) {103StringRef Map = A->getValue();104if (!Map.contains('='))105D.Diag(diag::err_drv_invalid_argument_to_option)106<< Map << A->getOption().getName();107else {108CmdArgs.push_back(Args.MakeArgString("--debug-prefix-map"));109CmdArgs.push_back(Args.MakeArgString(Map));110}111A->claim();112}113114Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);115116CmdArgs.push_back("-o");117CmdArgs.push_back(Output.getFilename());118119for (const auto &II : Inputs)120CmdArgs.push_back(II.getFilename());121122const char *Exec = Args.MakeArgString(ToolChain.GetProgramPath("as"));123C.addCommand(std::make_unique<Command>(JA, *this,124ResponseFileSupport::AtFileCurCP(),125Exec, CmdArgs, Inputs, Output));126}127128void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,129const InputInfo &Output,130const InputInfoList &Inputs,131const ArgList &Args,132const char *LinkingOutput) const {133const auto &ToolChain = static_cast<const FreeBSD &>(getToolChain());134const Driver &D = ToolChain.getDriver();135const llvm::Triple &Triple = ToolChain.getTriple();136const llvm::Triple::ArchType Arch = ToolChain.getArch();137const bool IsPIE =138!Args.hasArg(options::OPT_shared) &&139(Args.hasArg(options::OPT_pie) || ToolChain.isPIEDefault(Args));140ArgStringList CmdArgs;141142// Silence warning for "clang -g foo.o -o foo"143Args.ClaimAllArgs(options::OPT_g_Group);144// and "clang -emit-llvm foo.o -o foo"145Args.ClaimAllArgs(options::OPT_emit_llvm);146// and for "clang -w foo.o -o foo". Other warning options are already147// handled somewhere else.148Args.ClaimAllArgs(options::OPT_w);149150if (!D.SysRoot.empty())151CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));152153if (IsPIE)154CmdArgs.push_back("-pie");155156CmdArgs.push_back("--eh-frame-hdr");157if (Args.hasArg(options::OPT_static)) {158CmdArgs.push_back("-Bstatic");159} else {160if (Args.hasArg(options::OPT_rdynamic))161CmdArgs.push_back("-export-dynamic");162if (Args.hasArg(options::OPT_shared)) {163CmdArgs.push_back("-shared");164} else if (!Args.hasArg(options::OPT_r)) {165CmdArgs.push_back("-dynamic-linker");166CmdArgs.push_back("/libexec/ld-elf.so.1");167}168if (Arch == llvm::Triple::arm || Triple.isX86())169CmdArgs.push_back("--hash-style=both");170CmdArgs.push_back("--enable-new-dtags");171}172173// Explicitly set the linker emulation for platforms that might not174// be the default emulation for the linker.175switch (Arch) {176case llvm::Triple::x86:177CmdArgs.push_back("-m");178CmdArgs.push_back("elf_i386_fbsd");179break;180case llvm::Triple::ppc:181CmdArgs.push_back("-m");182CmdArgs.push_back("elf32ppc_fbsd");183break;184case llvm::Triple::ppcle:185CmdArgs.push_back("-m");186// Use generic -- only usage is for freestanding.187CmdArgs.push_back("elf32lppc");188break;189case llvm::Triple::mips:190CmdArgs.push_back("-m");191CmdArgs.push_back("elf32btsmip_fbsd");192break;193case llvm::Triple::mipsel:194CmdArgs.push_back("-m");195CmdArgs.push_back("elf32ltsmip_fbsd");196break;197case llvm::Triple::mips64:198CmdArgs.push_back("-m");199if (tools::mips::hasMipsAbiArg(Args, "n32"))200CmdArgs.push_back("elf32btsmipn32_fbsd");201else202CmdArgs.push_back("elf64btsmip_fbsd");203break;204case llvm::Triple::mips64el:205CmdArgs.push_back("-m");206if (tools::mips::hasMipsAbiArg(Args, "n32"))207CmdArgs.push_back("elf32ltsmipn32_fbsd");208else209CmdArgs.push_back("elf64ltsmip_fbsd");210break;211case llvm::Triple::riscv64:212CmdArgs.push_back("-m");213CmdArgs.push_back("elf64lriscv");214break;215default:216break;217}218219if (Triple.isRISCV64()) {220CmdArgs.push_back("-X");221if (Args.hasArg(options::OPT_mno_relax))222CmdArgs.push_back("--no-relax");223}224225if (Arg *A = Args.getLastArg(options::OPT_G)) {226if (ToolChain.getTriple().isMIPS()) {227StringRef v = A->getValue();228CmdArgs.push_back(Args.MakeArgString("-G" + v));229A->claim();230}231}232233assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");234if (Output.isFilename()) {235CmdArgs.push_back("-o");236CmdArgs.push_back(Output.getFilename());237}238239if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,240options::OPT_r)) {241const char *crt1 = nullptr;242if (!Args.hasArg(options::OPT_shared)) {243if (Args.hasArg(options::OPT_pg))244crt1 = "gcrt1.o";245else if (IsPIE)246crt1 = "Scrt1.o";247else248crt1 = "crt1.o";249}250if (crt1)251CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt1)));252253CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o")));254255const char *crtbegin = nullptr;256if (Args.hasArg(options::OPT_static))257crtbegin = "crtbeginT.o";258else if (Args.hasArg(options::OPT_shared) || IsPIE)259crtbegin = "crtbeginS.o";260else261crtbegin = "crtbegin.o";262263CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin)));264}265266Args.AddAllArgs(CmdArgs, options::OPT_L);267ToolChain.AddFilePathLibArgs(Args, CmdArgs);268Args.addAllArgs(CmdArgs,269{options::OPT_T_Group, options::OPT_s, options::OPT_t});270271if (D.isUsingLTO()) {272assert(!Inputs.empty() && "Must have at least one input.");273// Find the first filename InputInfo object.274auto Input = llvm::find_if(275Inputs, [](const InputInfo &II) -> bool { return II.isFilename(); });276if (Input == Inputs.end())277// For a very rare case, all of the inputs to the linker are278// InputArg. If that happens, just use the first InputInfo.279Input = Inputs.begin();280281addLTOOptions(ToolChain, Args, CmdArgs, Output, *Input,282D.getLTOMode() == LTOK_Thin);283}284285bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs);286bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs);287addLinkerCompressDebugSectionsOption(ToolChain, Args, CmdArgs);288AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);289290unsigned Major = ToolChain.getTriple().getOSMajorVersion();291bool Profiling = Args.hasArg(options::OPT_pg) && Major != 0 && Major < 14;292if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs,293options::OPT_r)) {294// Use the static OpenMP runtime with -static-openmp295bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) &&296!Args.hasArg(options::OPT_static);297addOpenMPRuntime(C, CmdArgs, ToolChain, Args, StaticOpenMP);298299if (D.CCCIsCXX()) {300if (ToolChain.ShouldLinkCXXStdlib(Args))301ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);302if (Profiling)303CmdArgs.push_back("-lm_p");304else305CmdArgs.push_back("-lm");306}307308// Silence warnings when linking C code with a C++ '-stdlib' argument.309Args.ClaimAllArgs(options::OPT_stdlib_EQ);310311// Additional linker set-up and flags for Fortran. This is required in order312// to generate executables. As Fortran runtime depends on the C runtime,313// these dependencies need to be listed before the C runtime below (i.e.314// AddRunTimeLibs).315if (D.IsFlangMode()) {316addFortranRuntimeLibraryPath(ToolChain, Args, CmdArgs);317addFortranRuntimeLibs(ToolChain, Args, CmdArgs);318if (Profiling)319CmdArgs.push_back("-lm_p");320else321CmdArgs.push_back("-lm");322}323324if (NeedsSanitizerDeps)325linkSanitizerRuntimeDeps(ToolChain, Args, CmdArgs);326if (NeedsXRayDeps)327linkXRayRuntimeDeps(ToolChain, Args, CmdArgs);328// FIXME: For some reason GCC passes -lgcc and -lgcc_s before adding329// the default system libraries. Just mimic this for now.330if (Profiling)331CmdArgs.push_back("-lgcc_p");332else333CmdArgs.push_back("-lgcc");334if (Args.hasArg(options::OPT_static)) {335CmdArgs.push_back("-lgcc_eh");336} else if (Profiling) {337CmdArgs.push_back("-lgcc_eh_p");338} else {339CmdArgs.push_back("--as-needed");340CmdArgs.push_back("-lgcc_s");341CmdArgs.push_back("--no-as-needed");342}343344if (Args.hasArg(options::OPT_pthread)) {345if (Profiling)346CmdArgs.push_back("-lpthread_p");347else348CmdArgs.push_back("-lpthread");349}350351if (Profiling) {352if (Args.hasArg(options::OPT_shared))353CmdArgs.push_back("-lc");354else355CmdArgs.push_back("-lc_p");356CmdArgs.push_back("-lgcc_p");357} else {358CmdArgs.push_back("-lc");359CmdArgs.push_back("-lgcc");360}361362if (Args.hasArg(options::OPT_static)) {363CmdArgs.push_back("-lgcc_eh");364} else if (Profiling) {365CmdArgs.push_back("-lgcc_eh_p");366} else {367CmdArgs.push_back("--as-needed");368CmdArgs.push_back("-lgcc_s");369CmdArgs.push_back("--no-as-needed");370}371}372373if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,374options::OPT_r)) {375const char *crtend = nullptr;376if (Args.hasArg(options::OPT_shared) || IsPIE)377crtend = "crtendS.o";378else379crtend = "crtend.o";380CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend)));381CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o")));382}383384ToolChain.addProfileRTLibs(Args, CmdArgs);385386const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());387C.addCommand(std::make_unique<Command>(JA, *this,388ResponseFileSupport::AtFileCurCP(),389Exec, CmdArgs, Inputs, Output));390}391392/// FreeBSD - FreeBSD tool chain which can call as(1) and ld(1) directly.393394FreeBSD::FreeBSD(const Driver &D, const llvm::Triple &Triple,395const ArgList &Args)396: Generic_ELF(D, Triple, Args) {397398// When targeting 32-bit platforms, look for '/usr/lib32/crt1.o' and fall399// back to '/usr/lib' if it doesn't exist.400if (Triple.isArch32Bit() &&401D.getVFS().exists(concat(getDriver().SysRoot, "/usr/lib32/crt1.o")))402getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib32"));403else404getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib"));405}406407void FreeBSD::AddClangSystemIncludeArgs(408const llvm::opt::ArgList &DriverArgs,409llvm::opt::ArgStringList &CC1Args) const {410const Driver &D = getDriver();411412if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc))413return;414415if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {416SmallString<128> Dir(D.ResourceDir);417llvm::sys::path::append(Dir, "include");418addSystemInclude(DriverArgs, CC1Args, Dir.str());419}420421if (DriverArgs.hasArg(options::OPT_nostdlibinc))422return;423424// Check for configure-time C include directories.425StringRef CIncludeDirs(C_INCLUDE_DIRS);426if (CIncludeDirs != "") {427SmallVector<StringRef, 5> dirs;428CIncludeDirs.split(dirs, ":");429for (StringRef dir : dirs) {430StringRef Prefix =431llvm::sys::path::is_absolute(dir) ? StringRef(D.SysRoot) : "";432addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir);433}434return;435}436437addExternCSystemInclude(DriverArgs, CC1Args,438concat(D.SysRoot, "/usr/include"));439}440441void FreeBSD::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,442llvm::opt::ArgStringList &CC1Args) const {443addSystemInclude(DriverArgs, CC1Args,444concat(getDriver().SysRoot, "/usr/include/c++/v1"));445}446447void FreeBSD::AddCXXStdlibLibArgs(const ArgList &Args,448ArgStringList &CmdArgs) const {449unsigned Major = getTriple().getOSMajorVersion();450bool Profiling = Args.hasArg(options::OPT_pg) && Major != 0 && Major < 14;451452CmdArgs.push_back(Profiling ? "-lc++_p" : "-lc++");453if (Args.hasArg(options::OPT_fexperimental_library))454CmdArgs.push_back("-lc++experimental");455}456457void FreeBSD::AddCudaIncludeArgs(const ArgList &DriverArgs,458ArgStringList &CC1Args) const {459CudaInstallation->AddCudaIncludeArgs(DriverArgs, CC1Args);460}461462void FreeBSD::AddHIPIncludeArgs(const ArgList &DriverArgs,463ArgStringList &CC1Args) const {464RocmInstallation->AddHIPIncludeArgs(DriverArgs, CC1Args);465}466467Tool *FreeBSD::buildAssembler() const {468return new tools::freebsd::Assembler(*this);469}470471Tool *FreeBSD::buildLinker() const { return new tools::freebsd::Linker(*this); }472473bool FreeBSD::HasNativeLLVMSupport() const { return true; }474475ToolChain::UnwindTableLevel476FreeBSD::getDefaultUnwindTableLevel(const ArgList &Args) const {477return UnwindTableLevel::Asynchronous;478}479480bool FreeBSD::isPIEDefault(const llvm::opt::ArgList &Args) const {481return getSanitizerArgs(Args).requiresPIE();482}483484SanitizerMask FreeBSD::getSupportedSanitizers() const {485const bool IsAArch64 = getTriple().getArch() == llvm::Triple::aarch64;486const bool IsX86 = getTriple().getArch() == llvm::Triple::x86;487const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64;488const bool IsMIPS64 = getTriple().isMIPS64();489SanitizerMask Res = ToolChain::getSupportedSanitizers();490Res |= SanitizerKind::Address;491Res |= SanitizerKind::PointerCompare;492Res |= SanitizerKind::PointerSubtract;493Res |= SanitizerKind::Vptr;494if (IsAArch64 || IsX86_64 || IsMIPS64) {495Res |= SanitizerKind::Leak;496Res |= SanitizerKind::Thread;497}498if (IsAArch64 || IsX86 || IsX86_64) {499Res |= SanitizerKind::SafeStack;500Res |= SanitizerKind::Fuzzer;501Res |= SanitizerKind::FuzzerNoLink;502}503if (IsAArch64 || IsX86_64) {504Res |= SanitizerKind::KernelAddress;505Res |= SanitizerKind::KernelMemory;506Res |= SanitizerKind::Memory;507}508return Res;509}510511512