Summary: For Gnu, FreeBSD and NetBSD, this option forces linking with the static OpenMP host runtime (similar to -static-libgcc and -static-libstdcxx). Android's NDK will start the shared OpenMP runtime in addition to the static libomp. In this scenario, the linker will prefer to use the shared library by default. Add this option to enable linking with the static libomp. Reviewers: Hahnfeld, danalbert, srhines, joerg, jdoerfert Subscribers: guansong, cfe-commits Tags: #clang Fixes https://github.com/android-ndk/ndk/issues/1028 Differential Revision: https://reviews.llvm.org/D67200 llvm-svn: 371437
448 lines
14 KiB
C++
448 lines
14 KiB
C++
//===--- FreeBSD.cpp - FreeBSD ToolChain Implementations --------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "FreeBSD.h"
|
|
#include "Arch/ARM.h"
|
|
#include "Arch/Mips.h"
|
|
#include "Arch/Sparc.h"
|
|
#include "CommonArgs.h"
|
|
#include "clang/Driver/Compilation.h"
|
|
#include "clang/Driver/Options.h"
|
|
#include "clang/Driver/SanitizerArgs.h"
|
|
#include "llvm/Option/ArgList.h"
|
|
#include "llvm/Support/VirtualFileSystem.h"
|
|
|
|
using namespace clang::driver;
|
|
using namespace clang::driver::tools;
|
|
using namespace clang::driver::toolchains;
|
|
using namespace clang;
|
|
using namespace llvm::opt;
|
|
|
|
void freebsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
|
|
const InputInfo &Output,
|
|
const InputInfoList &Inputs,
|
|
const ArgList &Args,
|
|
const char *LinkingOutput) const {
|
|
claimNoWarnArgs(Args);
|
|
ArgStringList CmdArgs;
|
|
|
|
// When building 32-bit code on FreeBSD/amd64, we have to explicitly
|
|
// instruct as in the base system to assemble 32-bit code.
|
|
switch (getToolChain().getArch()) {
|
|
default:
|
|
break;
|
|
case llvm::Triple::x86:
|
|
CmdArgs.push_back("--32");
|
|
break;
|
|
case llvm::Triple::ppc:
|
|
CmdArgs.push_back("-a32");
|
|
break;
|
|
case llvm::Triple::mips:
|
|
case llvm::Triple::mipsel:
|
|
case llvm::Triple::mips64:
|
|
case llvm::Triple::mips64el: {
|
|
StringRef CPUName;
|
|
StringRef ABIName;
|
|
mips::getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName);
|
|
|
|
CmdArgs.push_back("-march");
|
|
CmdArgs.push_back(CPUName.data());
|
|
|
|
CmdArgs.push_back("-mabi");
|
|
CmdArgs.push_back(mips::getGnuCompatibleMipsABIName(ABIName).data());
|
|
|
|
if (getToolChain().getTriple().isLittleEndian())
|
|
CmdArgs.push_back("-EL");
|
|
else
|
|
CmdArgs.push_back("-EB");
|
|
|
|
if (Arg *A = Args.getLastArg(options::OPT_G)) {
|
|
StringRef v = A->getValue();
|
|
CmdArgs.push_back(Args.MakeArgString("-G" + v));
|
|
A->claim();
|
|
}
|
|
|
|
AddAssemblerKPIC(getToolChain(), Args, CmdArgs);
|
|
break;
|
|
}
|
|
case llvm::Triple::arm:
|
|
case llvm::Triple::armeb:
|
|
case llvm::Triple::thumb:
|
|
case llvm::Triple::thumbeb: {
|
|
arm::FloatABI ABI = arm::getARMFloatABI(getToolChain(), Args);
|
|
|
|
if (ABI == arm::FloatABI::Hard)
|
|
CmdArgs.push_back("-mfpu=vfp");
|
|
else
|
|
CmdArgs.push_back("-mfpu=softvfp");
|
|
|
|
switch (getToolChain().getTriple().getEnvironment()) {
|
|
case llvm::Triple::GNUEABIHF:
|
|
case llvm::Triple::GNUEABI:
|
|
case llvm::Triple::EABI:
|
|
CmdArgs.push_back("-meabi=5");
|
|
break;
|
|
|
|
default:
|
|
CmdArgs.push_back("-matpcs");
|
|
}
|
|
break;
|
|
}
|
|
case llvm::Triple::sparc:
|
|
case llvm::Triple::sparcel:
|
|
case llvm::Triple::sparcv9: {
|
|
std::string CPU = getCPUName(Args, getToolChain().getTriple());
|
|
CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple()));
|
|
AddAssemblerKPIC(getToolChain(), Args, CmdArgs);
|
|
break;
|
|
}
|
|
}
|
|
|
|
Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
|
|
|
|
CmdArgs.push_back("-o");
|
|
CmdArgs.push_back(Output.getFilename());
|
|
|
|
for (const auto &II : Inputs)
|
|
CmdArgs.push_back(II.getFilename());
|
|
|
|
const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
|
|
C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
|
|
}
|
|
|
|
void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
|
|
const InputInfo &Output,
|
|
const InputInfoList &Inputs,
|
|
const ArgList &Args,
|
|
const char *LinkingOutput) const {
|
|
const toolchains::FreeBSD &ToolChain =
|
|
static_cast<const toolchains::FreeBSD &>(getToolChain());
|
|
const Driver &D = ToolChain.getDriver();
|
|
const llvm::Triple::ArchType Arch = ToolChain.getArch();
|
|
const bool IsPIE =
|
|
!Args.hasArg(options::OPT_shared) &&
|
|
(Args.hasArg(options::OPT_pie) || ToolChain.isPIEDefault());
|
|
ArgStringList CmdArgs;
|
|
|
|
// Silence warning for "clang -g foo.o -o foo"
|
|
Args.ClaimAllArgs(options::OPT_g_Group);
|
|
// and "clang -emit-llvm foo.o -o foo"
|
|
Args.ClaimAllArgs(options::OPT_emit_llvm);
|
|
// and for "clang -w foo.o -o foo". Other warning options are already
|
|
// handled somewhere else.
|
|
Args.ClaimAllArgs(options::OPT_w);
|
|
|
|
if (!D.SysRoot.empty())
|
|
CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
|
|
|
|
if (IsPIE)
|
|
CmdArgs.push_back("-pie");
|
|
|
|
CmdArgs.push_back("--eh-frame-hdr");
|
|
if (Args.hasArg(options::OPT_static)) {
|
|
CmdArgs.push_back("-Bstatic");
|
|
} else {
|
|
if (Args.hasArg(options::OPT_rdynamic))
|
|
CmdArgs.push_back("-export-dynamic");
|
|
if (Args.hasArg(options::OPT_shared)) {
|
|
CmdArgs.push_back("-Bshareable");
|
|
} else {
|
|
CmdArgs.push_back("-dynamic-linker");
|
|
CmdArgs.push_back("/libexec/ld-elf.so.1");
|
|
}
|
|
if (ToolChain.getTriple().getOSMajorVersion() >= 9) {
|
|
if (Arch == llvm::Triple::arm || Arch == llvm::Triple::sparc ||
|
|
Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64) {
|
|
CmdArgs.push_back("--hash-style=both");
|
|
}
|
|
}
|
|
CmdArgs.push_back("--enable-new-dtags");
|
|
}
|
|
|
|
// Explicitly set the linker emulation for platforms that might not
|
|
// be the default emulation for the linker.
|
|
switch (Arch) {
|
|
case llvm::Triple::x86:
|
|
CmdArgs.push_back("-m");
|
|
CmdArgs.push_back("elf_i386_fbsd");
|
|
break;
|
|
case llvm::Triple::ppc:
|
|
CmdArgs.push_back("-m");
|
|
CmdArgs.push_back("elf32ppc_fbsd");
|
|
break;
|
|
case llvm::Triple::mips:
|
|
CmdArgs.push_back("-m");
|
|
CmdArgs.push_back("elf32btsmip_fbsd");
|
|
break;
|
|
case llvm::Triple::mipsel:
|
|
CmdArgs.push_back("-m");
|
|
CmdArgs.push_back("elf32ltsmip_fbsd");
|
|
break;
|
|
case llvm::Triple::mips64:
|
|
CmdArgs.push_back("-m");
|
|
if (tools::mips::hasMipsAbiArg(Args, "n32"))
|
|
CmdArgs.push_back("elf32btsmipn32_fbsd");
|
|
else
|
|
CmdArgs.push_back("elf64btsmip_fbsd");
|
|
break;
|
|
case llvm::Triple::mips64el:
|
|
CmdArgs.push_back("-m");
|
|
if (tools::mips::hasMipsAbiArg(Args, "n32"))
|
|
CmdArgs.push_back("elf32ltsmipn32_fbsd");
|
|
else
|
|
CmdArgs.push_back("elf64ltsmip_fbsd");
|
|
break;
|
|
case llvm::Triple::riscv32:
|
|
CmdArgs.push_back("-m");
|
|
CmdArgs.push_back("elf32lriscv");
|
|
break;
|
|
case llvm::Triple::riscv64:
|
|
CmdArgs.push_back("-m");
|
|
CmdArgs.push_back("elf64lriscv");
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (Arg *A = Args.getLastArg(options::OPT_G)) {
|
|
if (ToolChain.getTriple().isMIPS()) {
|
|
StringRef v = A->getValue();
|
|
CmdArgs.push_back(Args.MakeArgString("-G" + v));
|
|
A->claim();
|
|
}
|
|
}
|
|
|
|
if (Output.isFilename()) {
|
|
CmdArgs.push_back("-o");
|
|
CmdArgs.push_back(Output.getFilename());
|
|
} else {
|
|
assert(Output.isNothing() && "Invalid output.");
|
|
}
|
|
|
|
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
|
|
const char *crt1 = nullptr;
|
|
if (!Args.hasArg(options::OPT_shared)) {
|
|
if (Args.hasArg(options::OPT_pg))
|
|
crt1 = "gcrt1.o";
|
|
else if (IsPIE)
|
|
crt1 = "Scrt1.o";
|
|
else
|
|
crt1 = "crt1.o";
|
|
}
|
|
if (crt1)
|
|
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt1)));
|
|
|
|
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o")));
|
|
|
|
const char *crtbegin = nullptr;
|
|
if (Args.hasArg(options::OPT_static))
|
|
crtbegin = "crtbeginT.o";
|
|
else if (Args.hasArg(options::OPT_shared) || IsPIE)
|
|
crtbegin = "crtbeginS.o";
|
|
else
|
|
crtbegin = "crtbegin.o";
|
|
|
|
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin)));
|
|
}
|
|
|
|
Args.AddAllArgs(CmdArgs, options::OPT_L);
|
|
ToolChain.AddFilePathLibArgs(Args, CmdArgs);
|
|
Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
|
|
Args.AddAllArgs(CmdArgs, options::OPT_e);
|
|
Args.AddAllArgs(CmdArgs, options::OPT_s);
|
|
Args.AddAllArgs(CmdArgs, options::OPT_t);
|
|
Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag);
|
|
Args.AddAllArgs(CmdArgs, options::OPT_r);
|
|
|
|
if (D.isUsingLTO()) {
|
|
assert(!Inputs.empty() && "Must have at least one input.");
|
|
AddGoldPlugin(ToolChain, Args, CmdArgs, Output, Inputs[0],
|
|
D.getLTOMode() == LTOK_Thin);
|
|
}
|
|
|
|
bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs);
|
|
bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs);
|
|
AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
|
|
|
|
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
|
|
// Use the static OpenMP runtime with -static-openmp
|
|
bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) &&
|
|
!Args.hasArg(options::OPT_static);
|
|
addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP);
|
|
|
|
if (D.CCCIsCXX()) {
|
|
if (ToolChain.ShouldLinkCXXStdlib(Args))
|
|
ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
|
|
if (Args.hasArg(options::OPT_pg))
|
|
CmdArgs.push_back("-lm_p");
|
|
else
|
|
CmdArgs.push_back("-lm");
|
|
}
|
|
if (NeedsSanitizerDeps)
|
|
linkSanitizerRuntimeDeps(ToolChain, CmdArgs);
|
|
if (NeedsXRayDeps)
|
|
linkXRayRuntimeDeps(ToolChain, CmdArgs);
|
|
// FIXME: For some reason GCC passes -lgcc and -lgcc_s before adding
|
|
// the default system libraries. Just mimic this for now.
|
|
if (Args.hasArg(options::OPT_pg))
|
|
CmdArgs.push_back("-lgcc_p");
|
|
else
|
|
CmdArgs.push_back("-lgcc");
|
|
if (Args.hasArg(options::OPT_static)) {
|
|
CmdArgs.push_back("-lgcc_eh");
|
|
} else if (Args.hasArg(options::OPT_pg)) {
|
|
CmdArgs.push_back("-lgcc_eh_p");
|
|
} else {
|
|
CmdArgs.push_back("--as-needed");
|
|
CmdArgs.push_back("-lgcc_s");
|
|
CmdArgs.push_back("--no-as-needed");
|
|
}
|
|
|
|
if (Args.hasArg(options::OPT_pthread)) {
|
|
if (Args.hasArg(options::OPT_pg))
|
|
CmdArgs.push_back("-lpthread_p");
|
|
else
|
|
CmdArgs.push_back("-lpthread");
|
|
}
|
|
|
|
if (Args.hasArg(options::OPT_pg)) {
|
|
if (Args.hasArg(options::OPT_shared))
|
|
CmdArgs.push_back("-lc");
|
|
else
|
|
CmdArgs.push_back("-lc_p");
|
|
CmdArgs.push_back("-lgcc_p");
|
|
} else {
|
|
CmdArgs.push_back("-lc");
|
|
CmdArgs.push_back("-lgcc");
|
|
}
|
|
|
|
if (Args.hasArg(options::OPT_static)) {
|
|
CmdArgs.push_back("-lgcc_eh");
|
|
} else if (Args.hasArg(options::OPT_pg)) {
|
|
CmdArgs.push_back("-lgcc_eh_p");
|
|
} else {
|
|
CmdArgs.push_back("--as-needed");
|
|
CmdArgs.push_back("-lgcc_s");
|
|
CmdArgs.push_back("--no-as-needed");
|
|
}
|
|
}
|
|
|
|
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
|
|
if (Args.hasArg(options::OPT_shared) || IsPIE)
|
|
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtendS.o")));
|
|
else
|
|
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o")));
|
|
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o")));
|
|
}
|
|
|
|
ToolChain.addProfileRTLibs(Args, CmdArgs);
|
|
|
|
const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
|
|
C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
|
|
}
|
|
|
|
/// FreeBSD - FreeBSD tool chain which can call as(1) and ld(1) directly.
|
|
|
|
FreeBSD::FreeBSD(const Driver &D, const llvm::Triple &Triple,
|
|
const ArgList &Args)
|
|
: Generic_ELF(D, Triple, Args) {
|
|
|
|
// When targeting 32-bit platforms, look for '/usr/lib32/crt1.o' and fall
|
|
// back to '/usr/lib' if it doesn't exist.
|
|
if ((Triple.getArch() == llvm::Triple::x86 || Triple.isMIPS32() ||
|
|
Triple.getArch() == llvm::Triple::ppc) &&
|
|
D.getVFS().exists(getDriver().SysRoot + "/usr/lib32/crt1.o"))
|
|
getFilePaths().push_back(getDriver().SysRoot + "/usr/lib32");
|
|
else
|
|
getFilePaths().push_back(getDriver().SysRoot + "/usr/lib");
|
|
}
|
|
|
|
ToolChain::CXXStdlibType FreeBSD::GetDefaultCXXStdlibType() const {
|
|
if (getTriple().getOSMajorVersion() >= 10)
|
|
return ToolChain::CST_Libcxx;
|
|
return ToolChain::CST_Libstdcxx;
|
|
}
|
|
|
|
unsigned FreeBSD::GetDefaultDwarfVersion() const {
|
|
if (getTriple().getOSMajorVersion() < 12)
|
|
return 2;
|
|
return 4;
|
|
}
|
|
|
|
void FreeBSD::addLibStdCxxIncludePaths(
|
|
const llvm::opt::ArgList &DriverArgs,
|
|
llvm::opt::ArgStringList &CC1Args) const {
|
|
addLibStdCXXIncludePaths(getDriver().SysRoot, "/usr/include/c++/4.2", "", "",
|
|
"", "", DriverArgs, CC1Args);
|
|
}
|
|
|
|
void FreeBSD::AddCXXStdlibLibArgs(const ArgList &Args,
|
|
ArgStringList &CmdArgs) const {
|
|
CXXStdlibType Type = GetCXXStdlibType(Args);
|
|
bool Profiling = Args.hasArg(options::OPT_pg);
|
|
|
|
switch (Type) {
|
|
case ToolChain::CST_Libcxx:
|
|
CmdArgs.push_back(Profiling ? "-lc++_p" : "-lc++");
|
|
break;
|
|
|
|
case ToolChain::CST_Libstdcxx:
|
|
CmdArgs.push_back(Profiling ? "-lstdc++_p" : "-lstdc++");
|
|
break;
|
|
}
|
|
}
|
|
|
|
Tool *FreeBSD::buildAssembler() const {
|
|
return new tools::freebsd::Assembler(*this);
|
|
}
|
|
|
|
Tool *FreeBSD::buildLinker() const { return new tools::freebsd::Linker(*this); }
|
|
|
|
llvm::ExceptionHandling FreeBSD::GetExceptionModel(const ArgList &Args) const {
|
|
// FreeBSD uses SjLj exceptions on ARM oabi.
|
|
switch (getTriple().getEnvironment()) {
|
|
case llvm::Triple::GNUEABIHF:
|
|
case llvm::Triple::GNUEABI:
|
|
case llvm::Triple::EABI:
|
|
return llvm::ExceptionHandling::None;
|
|
default:
|
|
if (getTriple().getArch() == llvm::Triple::arm ||
|
|
getTriple().getArch() == llvm::Triple::thumb)
|
|
return llvm::ExceptionHandling::SjLj;
|
|
return llvm::ExceptionHandling::None;
|
|
}
|
|
}
|
|
|
|
bool FreeBSD::HasNativeLLVMSupport() const { return true; }
|
|
|
|
bool FreeBSD::isPIEDefault() const { return getSanitizerArgs().requiresPIE(); }
|
|
|
|
SanitizerMask FreeBSD::getSupportedSanitizers() const {
|
|
const bool IsX86 = getTriple().getArch() == llvm::Triple::x86;
|
|
const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64;
|
|
const bool IsMIPS64 = getTriple().isMIPS64();
|
|
SanitizerMask Res = ToolChain::getSupportedSanitizers();
|
|
Res |= SanitizerKind::Address;
|
|
Res |= SanitizerKind::PointerCompare;
|
|
Res |= SanitizerKind::PointerSubtract;
|
|
Res |= SanitizerKind::Vptr;
|
|
if (IsX86_64 || IsMIPS64) {
|
|
Res |= SanitizerKind::Leak;
|
|
Res |= SanitizerKind::Thread;
|
|
}
|
|
if (IsX86 || IsX86_64) {
|
|
Res |= SanitizerKind::Function;
|
|
Res |= SanitizerKind::SafeStack;
|
|
Res |= SanitizerKind::Fuzzer;
|
|
Res |= SanitizerKind::FuzzerNoLink;
|
|
}
|
|
if (IsX86_64)
|
|
Res |= SanitizerKind::Memory;
|
|
return Res;
|
|
}
|