Path: blob/main/contrib/llvm-project/clang/lib/Driver/ToolChains/Fuchsia.cpp
35294 views
//===--- Fuchsia.cpp - Fuchsia 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 "Fuchsia.h"9#include "CommonArgs.h"10#include "clang/Config/config.h"11#include "clang/Driver/Compilation.h"12#include "clang/Driver/Driver.h"13#include "clang/Driver/DriverDiagnostic.h"14#include "clang/Driver/MultilibBuilder.h"15#include "clang/Driver/Options.h"16#include "clang/Driver/SanitizerArgs.h"17#include "llvm/Option/ArgList.h"18#include "llvm/ProfileData/InstrProf.h"19#include "llvm/Support/FileSystem.h"20#include "llvm/Support/Path.h"21#include "llvm/Support/VirtualFileSystem.h"2223using namespace clang::driver;24using namespace clang::driver::toolchains;25using namespace clang::driver::tools;26using namespace clang;27using namespace llvm::opt;2829using tools::addMultilibFlag;3031void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA,32const InputInfo &Output,33const InputInfoList &Inputs,34const ArgList &Args,35const char *LinkingOutput) const {36const auto &ToolChain = static_cast<const Fuchsia &>(getToolChain());37const Driver &D = ToolChain.getDriver();3839const llvm::Triple &Triple = ToolChain.getEffectiveTriple();4041ArgStringList CmdArgs;4243// Silence warning for "clang -g foo.o -o foo"44Args.ClaimAllArgs(options::OPT_g_Group);45// and "clang -emit-llvm foo.o -o foo"46Args.ClaimAllArgs(options::OPT_emit_llvm);47// and for "clang -w foo.o -o foo". Other warning options are already48// handled somewhere else.49Args.ClaimAllArgs(options::OPT_w);5051CmdArgs.push_back("-z");52CmdArgs.push_back("max-page-size=4096");5354CmdArgs.push_back("-z");55CmdArgs.push_back("now");5657CmdArgs.push_back("-z");58CmdArgs.push_back("start-stop-visibility=hidden");5960const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());61if (llvm::sys::path::filename(Exec).equals_insensitive("ld.lld") ||62llvm::sys::path::stem(Exec).equals_insensitive("ld.lld")) {63CmdArgs.push_back("-z");64CmdArgs.push_back("rodynamic");65CmdArgs.push_back("-z");66CmdArgs.push_back("separate-loadable-segments");67CmdArgs.push_back("-z");68CmdArgs.push_back("rel");69CmdArgs.push_back("--pack-dyn-relocs=relr");70}7172if (!D.SysRoot.empty())73CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));7475if (!Args.hasArg(options::OPT_shared) && !Args.hasArg(options::OPT_r))76CmdArgs.push_back("-pie");7778if (Args.hasArg(options::OPT_rdynamic))79CmdArgs.push_back("-export-dynamic");8081if (Args.hasArg(options::OPT_s))82CmdArgs.push_back("-s");8384if (Args.hasArg(options::OPT_r)) {85CmdArgs.push_back("-r");86} else {87CmdArgs.push_back("--build-id");88CmdArgs.push_back("--hash-style=gnu");89}9091if (ToolChain.getArch() == llvm::Triple::aarch64) {92CmdArgs.push_back("--execute-only");9394std::string CPU = getCPUName(D, Args, Triple);95if (CPU.empty() || CPU == "generic" || CPU == "cortex-a53")96CmdArgs.push_back("--fix-cortex-a53-843419");97}9899CmdArgs.push_back("--eh-frame-hdr");100101if (Args.hasArg(options::OPT_static))102CmdArgs.push_back("-Bstatic");103else if (Args.hasArg(options::OPT_shared))104CmdArgs.push_back("-shared");105106const SanitizerArgs &SanArgs = ToolChain.getSanitizerArgs(Args);107108if (!Args.hasArg(options::OPT_shared) && !Args.hasArg(options::OPT_r)) {109std::string Dyld = D.DyldPrefix;110if (SanArgs.needsAsanRt() && SanArgs.needsSharedRt())111Dyld += "asan/";112if (SanArgs.needsHwasanRt() && SanArgs.needsSharedRt())113Dyld += "hwasan/";114if (SanArgs.needsTsanRt() && SanArgs.needsSharedRt())115Dyld += "tsan/";116Dyld += "ld.so.1";117CmdArgs.push_back("-dynamic-linker");118CmdArgs.push_back(Args.MakeArgString(Dyld));119}120121if (Triple.isRISCV64()) {122CmdArgs.push_back("-X");123if (Args.hasArg(options::OPT_mno_relax))124CmdArgs.push_back("--no-relax");125}126127CmdArgs.push_back("-o");128CmdArgs.push_back(Output.getFilename());129130if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,131options::OPT_r)) {132if (!Args.hasArg(options::OPT_shared)) {133CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("Scrt1.o")));134}135}136137Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_u});138139ToolChain.AddFilePathLibArgs(Args, CmdArgs);140141if (D.isUsingLTO()) {142assert(!Inputs.empty() && "Must have at least one input.");143// Find the first filename InputInfo object.144auto Input = llvm::find_if(145Inputs, [](const InputInfo &II) -> bool { return II.isFilename(); });146if (Input == Inputs.end())147// For a very rare case, all of the inputs to the linker are148// InputArg. If that happens, just use the first InputInfo.149Input = Inputs.begin();150151addLTOOptions(ToolChain, Args, CmdArgs, Output, *Input,152D.getLTOMode() == LTOK_Thin);153}154155addLinkerCompressDebugSectionsOption(ToolChain, Args, CmdArgs);156AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);157158if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs,159options::OPT_r)) {160if (Args.hasArg(options::OPT_static))161CmdArgs.push_back("-Bdynamic");162163if (D.CCCIsCXX()) {164if (ToolChain.ShouldLinkCXXStdlib(Args)) {165bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) &&166!Args.hasArg(options::OPT_static);167CmdArgs.push_back("--push-state");168CmdArgs.push_back("--as-needed");169if (OnlyLibstdcxxStatic)170CmdArgs.push_back("-Bstatic");171ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);172if (OnlyLibstdcxxStatic)173CmdArgs.push_back("-Bdynamic");174CmdArgs.push_back("-lm");175CmdArgs.push_back("--pop-state");176}177}178179// Note that Fuchsia never needs to link in sanitizer runtime deps. Any180// sanitizer runtimes with system dependencies use the `.deplibs` feature181// instead.182addSanitizerRuntimes(ToolChain, Args, CmdArgs);183184addXRayRuntime(ToolChain, Args, CmdArgs);185186ToolChain.addProfileRTLibs(Args, CmdArgs);187188AddRunTimeLibs(ToolChain, D, CmdArgs, Args);189190if (Args.hasArg(options::OPT_pthread) ||191Args.hasArg(options::OPT_pthreads))192CmdArgs.push_back("-lpthread");193194if (Args.hasArg(options::OPT_fsplit_stack))195CmdArgs.push_back("--wrap=pthread_create");196197if (!Args.hasArg(options::OPT_nolibc))198CmdArgs.push_back("-lc");199}200201C.addCommand(std::make_unique<Command>(JA, *this,202ResponseFileSupport::AtFileCurCP(),203Exec, CmdArgs, Inputs, Output));204}205206void fuchsia::StaticLibTool::ConstructJob(Compilation &C, const JobAction &JA,207const InputInfo &Output,208const InputInfoList &Inputs,209const ArgList &Args,210const char *LinkingOutput) const {211const Driver &D = getToolChain().getDriver();212213// Silence warning for "clang -g foo.o -o foo"214Args.ClaimAllArgs(options::OPT_g_Group);215// and "clang -emit-llvm foo.o -o foo"216Args.ClaimAllArgs(options::OPT_emit_llvm);217// and for "clang -w foo.o -o foo". Other warning options are already218// handled somewhere else.219Args.ClaimAllArgs(options::OPT_w);220// Silence warnings when linking C code with a C++ '-stdlib' argument.221Args.ClaimAllArgs(options::OPT_stdlib_EQ);222223// ar tool command "llvm-ar <options> <output_file> <input_files>".224ArgStringList CmdArgs;225// Create and insert file members with a deterministic index.226CmdArgs.push_back("rcsD");227CmdArgs.push_back(Output.getFilename());228229for (const auto &II : Inputs) {230if (II.isFilename()) {231CmdArgs.push_back(II.getFilename());232}233}234235// Delete old output archive file if it already exists before generating a new236// archive file.237const char *OutputFileName = Output.getFilename();238if (Output.isFilename() && llvm::sys::fs::exists(OutputFileName)) {239if (std::error_code EC = llvm::sys::fs::remove(OutputFileName)) {240D.Diag(diag::err_drv_unable_to_remove_file) << EC.message();241return;242}243}244245const char *Exec = Args.MakeArgString(getToolChain().GetStaticLibToolPath());246C.addCommand(std::make_unique<Command>(JA, *this,247ResponseFileSupport::AtFileCurCP(),248Exec, CmdArgs, Inputs, Output));249}250251/// Fuchsia - Fuchsia tool chain which can call as(1) and ld(1) directly.252253Fuchsia::Fuchsia(const Driver &D, const llvm::Triple &Triple,254const ArgList &Args)255: ToolChain(D, Triple, Args) {256getProgramPaths().push_back(getDriver().Dir);257258if (!D.SysRoot.empty()) {259SmallString<128> P(D.SysRoot);260llvm::sys::path::append(P, "lib");261getFilePaths().push_back(std::string(P));262}263264auto FilePaths = [&](const Multilib &M) -> std::vector<std::string> {265std::vector<std::string> FP;266if (std::optional<std::string> Path = getStdlibPath()) {267SmallString<128> P(*Path);268llvm::sys::path::append(P, M.gccSuffix());269FP.push_back(std::string(P));270}271return FP;272};273274Multilibs.push_back(Multilib());275// Use the noexcept variant with -fno-exceptions to avoid the extra overhead.276Multilibs.push_back(MultilibBuilder("noexcept", {}, {})277.flag("-fexceptions", /*Disallow=*/true)278.flag("-fno-exceptions")279.makeMultilib());280// ASan has higher priority because we always want the instrumentated version.281Multilibs.push_back(MultilibBuilder("asan", {}, {})282.flag("-fsanitize=address")283.makeMultilib());284// Use the asan+noexcept variant with ASan and -fno-exceptions.285Multilibs.push_back(MultilibBuilder("asan+noexcept", {}, {})286.flag("-fsanitize=address")287.flag("-fexceptions", /*Disallow=*/true)288.flag("-fno-exceptions")289.makeMultilib());290// HWASan has higher priority because we always want the instrumentated291// version.292Multilibs.push_back(MultilibBuilder("hwasan", {}, {})293.flag("-fsanitize=hwaddress")294.makeMultilib());295// Use the hwasan+noexcept variant with HWASan and -fno-exceptions.296Multilibs.push_back(MultilibBuilder("hwasan+noexcept", {}, {})297.flag("-fsanitize=hwaddress")298.flag("-fexceptions", /*Disallow=*/true)299.flag("-fno-exceptions")300.makeMultilib());301// Use Itanium C++ ABI for the compat multilib.302Multilibs.push_back(MultilibBuilder("compat", {}, {})303.flag("-fc++-abi=itanium")304.makeMultilib());305306Multilibs.FilterOut([&](const Multilib &M) {307std::vector<std::string> RD = FilePaths(M);308return llvm::all_of(RD, [&](std::string P) { return !getVFS().exists(P); });309});310311Multilib::flags_list Flags;312bool Exceptions =313Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions, true);314addMultilibFlag(Exceptions, "-fexceptions", Flags);315addMultilibFlag(!Exceptions, "-fno-exceptions", Flags);316addMultilibFlag(getSanitizerArgs(Args).needsAsanRt(), "-fsanitize=address",317Flags);318addMultilibFlag(getSanitizerArgs(Args).needsHwasanRt(),319"-fsanitize=hwaddress", Flags);320321addMultilibFlag(Args.getLastArgValue(options::OPT_fcxx_abi_EQ) == "itanium",322"-fc++-abi=itanium", Flags);323324Multilibs.setFilePathsCallback(FilePaths);325326if (Multilibs.select(Flags, SelectedMultilibs)) {327// Ensure that -print-multi-directory only outputs one multilib directory.328Multilib LastSelected = SelectedMultilibs.back();329SelectedMultilibs = {LastSelected};330331if (!SelectedMultilibs.back().isDefault())332if (const auto &PathsCallback = Multilibs.filePathsCallback())333for (const auto &Path : PathsCallback(SelectedMultilibs.back()))334// Prepend the multilib path to ensure it takes the precedence.335getFilePaths().insert(getFilePaths().begin(), Path);336}337}338339std::string Fuchsia::ComputeEffectiveClangTriple(const ArgList &Args,340types::ID InputType) const {341llvm::Triple Triple(ComputeLLVMTriple(Args, InputType));342return Triple.str();343}344345Tool *Fuchsia::buildLinker() const {346return new tools::fuchsia::Linker(*this);347}348349Tool *Fuchsia::buildStaticLibTool() const {350return new tools::fuchsia::StaticLibTool(*this);351}352353ToolChain::RuntimeLibType Fuchsia::GetRuntimeLibType(354const ArgList &Args) const {355if (Arg *A = Args.getLastArg(clang::driver::options::OPT_rtlib_EQ)) {356StringRef Value = A->getValue();357if (Value != "compiler-rt")358getDriver().Diag(clang::diag::err_drv_invalid_rtlib_name)359<< A->getAsString(Args);360}361362return ToolChain::RLT_CompilerRT;363}364365ToolChain::CXXStdlibType366Fuchsia::GetCXXStdlibType(const ArgList &Args) const {367if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) {368StringRef Value = A->getValue();369if (Value != "libc++")370getDriver().Diag(diag::err_drv_invalid_stdlib_name)371<< A->getAsString(Args);372}373374return ToolChain::CST_Libcxx;375}376377void Fuchsia::addClangTargetOptions(const ArgList &DriverArgs,378ArgStringList &CC1Args,379Action::OffloadKind) const {380if (!DriverArgs.hasFlag(options::OPT_fuse_init_array,381options::OPT_fno_use_init_array, true))382CC1Args.push_back("-fno-use-init-array");383}384385void Fuchsia::AddClangSystemIncludeArgs(const ArgList &DriverArgs,386ArgStringList &CC1Args) const {387const Driver &D = getDriver();388389if (DriverArgs.hasArg(options::OPT_nostdinc))390return;391392if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {393SmallString<128> P(D.ResourceDir);394llvm::sys::path::append(P, "include");395addSystemInclude(DriverArgs, CC1Args, P);396}397398if (DriverArgs.hasArg(options::OPT_nostdlibinc))399return;400401// Check for configure-time C include directories.402StringRef CIncludeDirs(C_INCLUDE_DIRS);403if (CIncludeDirs != "") {404SmallVector<StringRef, 5> dirs;405CIncludeDirs.split(dirs, ":");406for (StringRef dir : dirs) {407StringRef Prefix =408llvm::sys::path::is_absolute(dir) ? "" : StringRef(D.SysRoot);409addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir);410}411return;412}413414if (!D.SysRoot.empty()) {415SmallString<128> P(D.SysRoot);416llvm::sys::path::append(P, "include");417addExternCSystemInclude(DriverArgs, CC1Args, P.str());418}419}420421void Fuchsia::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,422ArgStringList &CC1Args) const {423if (DriverArgs.hasArg(options::OPT_nostdinc, options::OPT_nostdlibinc,424options::OPT_nostdincxx))425return;426427const Driver &D = getDriver();428std::string Target = getTripleString();429430auto AddCXXIncludePath = [&](StringRef Path) {431std::string Version = detectLibcxxVersion(Path);432if (Version.empty())433return;434435// First add the per-target multilib include dir.436if (!SelectedMultilibs.empty() && !SelectedMultilibs.back().isDefault()) {437const Multilib &M = SelectedMultilibs.back();438SmallString<128> TargetDir(Path);439llvm::sys::path::append(TargetDir, Target, M.gccSuffix(), "c++", Version);440if (getVFS().exists(TargetDir)) {441addSystemInclude(DriverArgs, CC1Args, TargetDir);442}443}444445// Second add the per-target include dir.446SmallString<128> TargetDir(Path);447llvm::sys::path::append(TargetDir, Target, "c++", Version);448if (getVFS().exists(TargetDir))449addSystemInclude(DriverArgs, CC1Args, TargetDir);450451// Third the generic one.452SmallString<128> Dir(Path);453llvm::sys::path::append(Dir, "c++", Version);454addSystemInclude(DriverArgs, CC1Args, Dir);455};456457switch (GetCXXStdlibType(DriverArgs)) {458case ToolChain::CST_Libcxx: {459SmallString<128> P(D.Dir);460llvm::sys::path::append(P, "..", "include");461AddCXXIncludePath(P);462break;463}464465default:466llvm_unreachable("invalid stdlib name");467}468}469470void Fuchsia::AddCXXStdlibLibArgs(const ArgList &Args,471ArgStringList &CmdArgs) const {472switch (GetCXXStdlibType(Args)) {473case ToolChain::CST_Libcxx:474CmdArgs.push_back("-lc++");475if (Args.hasArg(options::OPT_fexperimental_library))476CmdArgs.push_back("-lc++experimental");477break;478479case ToolChain::CST_Libstdcxx:480llvm_unreachable("invalid stdlib name");481}482}483484SanitizerMask Fuchsia::getSupportedSanitizers() const {485SanitizerMask Res = ToolChain::getSupportedSanitizers();486Res |= SanitizerKind::Address;487Res |= SanitizerKind::HWAddress;488Res |= SanitizerKind::PointerCompare;489Res |= SanitizerKind::PointerSubtract;490Res |= SanitizerKind::Fuzzer;491Res |= SanitizerKind::FuzzerNoLink;492Res |= SanitizerKind::Leak;493Res |= SanitizerKind::SafeStack;494Res |= SanitizerKind::Scudo;495Res |= SanitizerKind::Thread;496return Res;497}498499SanitizerMask Fuchsia::getDefaultSanitizers() const {500SanitizerMask Res;501switch (getTriple().getArch()) {502case llvm::Triple::aarch64:503case llvm::Triple::riscv64:504Res |= SanitizerKind::ShadowCallStack;505break;506case llvm::Triple::x86_64:507Res |= SanitizerKind::SafeStack;508break;509default:510break;511}512return Res;513}514515516