509 lines · cpp
1//===--- Fuchsia.cpp - Fuchsia 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 "Fuchsia.h"10#include "clang/Config/config.h"11#include "clang/Driver/CommonArgs.h"12#include "clang/Driver/Compilation.h"13#include "clang/Driver/Driver.h"14#include "clang/Driver/MultilibBuilder.h"15#include "clang/Driver/SanitizerArgs.h"16#include "clang/Options/Options.h"17#include "llvm/Option/ArgList.h"18#include "llvm/Support/FileSystem.h"19#include "llvm/Support/Path.h"20#include "llvm/Support/VirtualFileSystem.h"21 22using namespace clang::driver;23using namespace clang::driver::toolchains;24using namespace clang::driver::tools;25using namespace clang;26using namespace llvm::opt;27 28using tools::addMultilibFlag;29 30void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA,31 const InputInfo &Output,32 const InputInfoList &Inputs,33 const ArgList &Args,34 const char *LinkingOutput) const {35 const auto &ToolChain = static_cast<const Fuchsia &>(getToolChain());36 const Driver &D = ToolChain.getDriver();37 38 const llvm::Triple &Triple = ToolChain.getEffectiveTriple();39 40 ArgStringList CmdArgs;41 42 // Silence warning for "clang -g foo.o -o foo"43 Args.ClaimAllArgs(options::OPT_g_Group);44 // and "clang -emit-llvm foo.o -o foo"45 Args.ClaimAllArgs(options::OPT_emit_llvm);46 // and for "clang -w foo.o -o foo". Other warning options are already47 // handled somewhere else.48 Args.ClaimAllArgs(options::OPT_w);49 50 CmdArgs.push_back("-z");51 CmdArgs.push_back("max-page-size=4096");52 53 CmdArgs.push_back("-z");54 CmdArgs.push_back("now");55 56 CmdArgs.push_back("-z");57 CmdArgs.push_back("start-stop-visibility=hidden");58 59 const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());60 if (llvm::sys::path::filename(Exec).equals_insensitive("ld.lld") ||61 llvm::sys::path::stem(Exec).equals_insensitive("ld.lld")) {62 CmdArgs.push_back("-z");63 CmdArgs.push_back("rodynamic");64 CmdArgs.push_back("-z");65 CmdArgs.push_back("separate-loadable-segments");66 CmdArgs.push_back("-z");67 CmdArgs.push_back("rel");68 CmdArgs.push_back("--pack-dyn-relocs=relr");69 }70 71 if (!D.SysRoot.empty())72 CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));73 74 if (!Args.hasArg(options::OPT_shared) && !Args.hasArg(options::OPT_r))75 CmdArgs.push_back("-pie");76 77 if (Args.hasArg(options::OPT_rdynamic))78 CmdArgs.push_back("-export-dynamic");79 80 if (Args.hasArg(options::OPT_s))81 CmdArgs.push_back("-s");82 83 if (Args.hasArg(options::OPT_r)) {84 CmdArgs.push_back("-r");85 } else {86 CmdArgs.push_back("--build-id");87 CmdArgs.push_back("--hash-style=gnu");88 }89 90 if (ToolChain.getArch() == llvm::Triple::aarch64) {91 CmdArgs.push_back("--execute-only");92 93 std::string CPU = getCPUName(D, Args, Triple);94 if (Args.hasFlag(options::OPT_mfix_cortex_a53_843419,95 options::OPT_mno_fix_cortex_a53_843419, true) &&96 (CPU.empty() || CPU == "generic" || CPU == "cortex-a53"))97 CmdArgs.push_back("--fix-cortex-a53-843419");98 }99 100 CmdArgs.push_back("--eh-frame-hdr");101 102 if (Args.hasArg(options::OPT_static))103 CmdArgs.push_back("-Bstatic");104 else if (Args.hasArg(options::OPT_shared))105 CmdArgs.push_back("-shared");106 107 const SanitizerArgs &SanArgs = ToolChain.getSanitizerArgs(Args);108 109 if (!Args.hasArg(options::OPT_shared) && !Args.hasArg(options::OPT_r)) {110 std::string Dyld = D.DyldPrefix;111 if (SanArgs.needsAsanRt() && SanArgs.needsSharedRt())112 Dyld += "asan/";113 if (SanArgs.needsHwasanRt() && SanArgs.needsSharedRt())114 Dyld += "hwasan/";115 if (SanArgs.needsTsanRt() && SanArgs.needsSharedRt())116 Dyld += "tsan/";117 Dyld += "ld.so.1";118 CmdArgs.push_back("-dynamic-linker");119 CmdArgs.push_back(Args.MakeArgString(Dyld));120 }121 122 if (Triple.isRISCV64()) {123 CmdArgs.push_back("-X");124 if (Args.hasArg(options::OPT_mno_relax))125 CmdArgs.push_back("--no-relax");126 }127 128 CmdArgs.push_back("-o");129 CmdArgs.push_back(Output.getFilename());130 131 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,132 options::OPT_r)) {133 if (!Args.hasArg(options::OPT_shared)) {134 CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("Scrt1.o")));135 }136 }137 138 Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_u});139 140 ToolChain.AddFilePathLibArgs(Args, CmdArgs);141 142 if (D.isUsingLTO())143 addLTOOptions(ToolChain, Args, CmdArgs, Output, Inputs,144 D.getLTOMode() == LTOK_Thin);145 146 addLinkerCompressDebugSectionsOption(ToolChain, Args, CmdArgs);147 AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);148 149 // Sample these options first so they are claimed even under -nostdlib et al.150 bool NoLibc = Args.hasArg(options::OPT_nolibc);151 bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) &&152 !Args.hasArg(options::OPT_static);153 bool Pthreads = Args.hasArg(options::OPT_pthread, options::OPT_pthreads);154 bool SplitStack = Args.hasArg(options::OPT_fsplit_stack);155 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs,156 options::OPT_r)) {157 if (Args.hasArg(options::OPT_static))158 CmdArgs.push_back("-Bdynamic");159 160 if (D.CCCIsCXX()) {161 if (ToolChain.ShouldLinkCXXStdlib(Args)) {162 CmdArgs.push_back("--push-state");163 CmdArgs.push_back("--as-needed");164 if (OnlyLibstdcxxStatic)165 CmdArgs.push_back("-Bstatic");166 ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);167 if (OnlyLibstdcxxStatic)168 CmdArgs.push_back("-Bdynamic");169 CmdArgs.push_back("-lm");170 CmdArgs.push_back("--pop-state");171 }172 }173 174 // Note that Fuchsia never needs to link in sanitizer runtime deps. Any175 // sanitizer runtimes with system dependencies use the `.deplibs` feature176 // instead.177 addSanitizerRuntimes(ToolChain, Args, CmdArgs);178 179 addXRayRuntime(ToolChain, Args, CmdArgs);180 181 ToolChain.addProfileRTLibs(Args, CmdArgs);182 183 AddRunTimeLibs(ToolChain, D, CmdArgs, Args);184 185 if (Pthreads)186 CmdArgs.push_back("-lpthread");187 188 if (SplitStack)189 CmdArgs.push_back("--wrap=pthread_create");190 191 if (!NoLibc)192 CmdArgs.push_back("-lc");193 }194 195 C.addCommand(std::make_unique<Command>(JA, *this,196 ResponseFileSupport::AtFileCurCP(),197 Exec, CmdArgs, Inputs, Output));198}199 200void fuchsia::StaticLibTool::ConstructJob(Compilation &C, const JobAction &JA,201 const InputInfo &Output,202 const InputInfoList &Inputs,203 const ArgList &Args,204 const char *LinkingOutput) const {205 const Driver &D = getToolChain().getDriver();206 207 // Silence warning for "clang -g foo.o -o foo"208 Args.ClaimAllArgs(options::OPT_g_Group);209 // and "clang -emit-llvm foo.o -o foo"210 Args.ClaimAllArgs(options::OPT_emit_llvm);211 // and for "clang -w foo.o -o foo". Other warning options are already212 // handled somewhere else.213 Args.ClaimAllArgs(options::OPT_w);214 // Silence warnings when linking C code with a C++ '-stdlib' argument.215 Args.ClaimAllArgs(options::OPT_stdlib_EQ);216 217 // ar tool command "llvm-ar <options> <output_file> <input_files>".218 ArgStringList CmdArgs;219 // Create and insert file members with a deterministic index.220 CmdArgs.push_back("rcsD");221 CmdArgs.push_back(Output.getFilename());222 223 for (const auto &II : Inputs) {224 if (II.isFilename()) {225 CmdArgs.push_back(II.getFilename());226 }227 }228 229 // Delete old output archive file if it already exists before generating a new230 // archive file.231 const char *OutputFileName = Output.getFilename();232 if (Output.isFilename() && llvm::sys::fs::exists(OutputFileName)) {233 if (std::error_code EC = llvm::sys::fs::remove(OutputFileName)) {234 D.Diag(diag::err_drv_unable_to_remove_file) << EC.message();235 return;236 }237 }238 239 const char *Exec = Args.MakeArgString(getToolChain().GetStaticLibToolPath());240 C.addCommand(std::make_unique<Command>(JA, *this,241 ResponseFileSupport::AtFileCurCP(),242 Exec, CmdArgs, Inputs, Output));243}244 245/// Fuchsia - Fuchsia tool chain which can call as(1) and ld(1) directly.246 247Fuchsia::Fuchsia(const Driver &D, const llvm::Triple &Triple,248 const ArgList &Args)249 : ToolChain(D, Triple, Args) {250 getProgramPaths().push_back(getDriver().Dir);251 252 if (!D.SysRoot.empty()) {253 SmallString<128> P(D.SysRoot);254 llvm::sys::path::append(P, "lib");255 getFilePaths().push_back(std::string(P));256 }257 258 auto FilePaths = [&](const Multilib &M) -> std::vector<std::string> {259 std::vector<std::string> FP;260 if (std::optional<std::string> Path = getStdlibPath()) {261 SmallString<128> P(*Path);262 llvm::sys::path::append(P, M.gccSuffix());263 FP.push_back(std::string(P));264 }265 return FP;266 };267 268 Multilibs.push_back(Multilib());269 // Use the noexcept variant with -fno-exceptions to avoid the extra overhead.270 Multilibs.push_back(MultilibBuilder("noexcept", {}, {})271 .flag("-fexceptions", /*Disallow=*/true)272 .flag("-fno-exceptions")273 .makeMultilib());274 // ASan has higher priority because we always want the instrumentated version.275 Multilibs.push_back(MultilibBuilder("asan", {}, {})276 .flag("-fsanitize=address")277 .makeMultilib());278 // Use the asan+noexcept variant with ASan and -fno-exceptions.279 Multilibs.push_back(MultilibBuilder("asan+noexcept", {}, {})280 .flag("-fsanitize=address")281 .flag("-fexceptions", /*Disallow=*/true)282 .flag("-fno-exceptions")283 .makeMultilib());284 // HWASan has higher priority because we always want the instrumentated285 // version.286 Multilibs.push_back(MultilibBuilder("hwasan", {}, {})287 .flag("-fsanitize=hwaddress")288 .makeMultilib());289 // Use the hwasan+noexcept variant with HWASan and -fno-exceptions.290 Multilibs.push_back(MultilibBuilder("hwasan+noexcept", {}, {})291 .flag("-fsanitize=hwaddress")292 .flag("-fexceptions", /*Disallow=*/true)293 .flag("-fno-exceptions")294 .makeMultilib());295 // Use Itanium C++ ABI for the compat multilib.296 Multilibs.push_back(MultilibBuilder("compat", {}, {})297 .flag("-fc++-abi=itanium")298 .makeMultilib());299 300 Multilibs.FilterOut([&](const Multilib &M) {301 std::vector<std::string> RD = FilePaths(M);302 return llvm::all_of(RD, [&](std::string P) { return !getVFS().exists(P); });303 });304 305 Multilib::flags_list Flags;306 bool Exceptions =307 Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions, true);308 addMultilibFlag(Exceptions, "-fexceptions", Flags);309 addMultilibFlag(!Exceptions, "-fno-exceptions", Flags);310 addMultilibFlag(getSanitizerArgs(Args).needsAsanRt(), "-fsanitize=address",311 Flags);312 addMultilibFlag(getSanitizerArgs(Args).needsHwasanRt(),313 "-fsanitize=hwaddress", Flags);314 315 addMultilibFlag(Args.getLastArgValue(options::OPT_fcxx_abi_EQ) == "itanium",316 "-fc++-abi=itanium", Flags);317 318 Multilibs.setFilePathsCallback(FilePaths);319 320 if (Multilibs.select(D, Flags, SelectedMultilibs)) {321 // Ensure that -print-multi-directory only outputs one multilib directory.322 Multilib LastSelected = SelectedMultilibs.back();323 SelectedMultilibs = {LastSelected};324 325 if (!SelectedMultilibs.back().isDefault())326 if (const auto &PathsCallback = Multilibs.filePathsCallback())327 for (const auto &Path : PathsCallback(SelectedMultilibs.back()))328 // Prepend the multilib path to ensure it takes the precedence.329 getFilePaths().insert(getFilePaths().begin(), Path);330 }331}332 333std::string Fuchsia::ComputeEffectiveClangTriple(const ArgList &Args,334 types::ID InputType) const {335 llvm::Triple Triple(ComputeLLVMTriple(Args, InputType));336 return Triple.str();337}338 339Tool *Fuchsia::buildLinker() const { return new tools::fuchsia::Linker(*this); }340 341Tool *Fuchsia::buildStaticLibTool() const {342 return new tools::fuchsia::StaticLibTool(*this);343}344 345ToolChain::RuntimeLibType346Fuchsia::GetRuntimeLibType(const ArgList &Args) const {347 if (Arg *A = Args.getLastArg(options::OPT_rtlib_EQ)) {348 StringRef Value = A->getValue();349 if (Value != "compiler-rt")350 getDriver().Diag(clang::diag::err_drv_invalid_rtlib_name)351 << A->getAsString(Args);352 }353 354 return ToolChain::RLT_CompilerRT;355}356 357ToolChain::CXXStdlibType Fuchsia::GetCXXStdlibType(const ArgList &Args) const {358 if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) {359 StringRef Value = A->getValue();360 if (Value != "libc++")361 getDriver().Diag(diag::err_drv_invalid_stdlib_name)362 << A->getAsString(Args);363 }364 365 return ToolChain::CST_Libcxx;366}367 368void Fuchsia::addClangTargetOptions(const ArgList &DriverArgs,369 ArgStringList &CC1Args,370 Action::OffloadKind) const {371 if (!DriverArgs.hasFlag(options::OPT_fuse_init_array,372 options::OPT_fno_use_init_array, true))373 CC1Args.push_back("-fno-use-init-array");374}375 376void Fuchsia::AddClangSystemIncludeArgs(const ArgList &DriverArgs,377 ArgStringList &CC1Args) const {378 const Driver &D = getDriver();379 380 if (DriverArgs.hasArg(options::OPT_nostdinc))381 return;382 383 if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {384 SmallString<128> P(D.ResourceDir);385 llvm::sys::path::append(P, "include");386 addSystemInclude(DriverArgs, CC1Args, P);387 }388 389 if (DriverArgs.hasArg(options::OPT_nostdlibinc))390 return;391 392 // Check for configure-time C include directories.393 StringRef CIncludeDirs(C_INCLUDE_DIRS);394 if (CIncludeDirs != "") {395 SmallVector<StringRef, 5> dirs;396 CIncludeDirs.split(dirs, ":");397 for (StringRef dir : dirs) {398 StringRef Prefix =399 llvm::sys::path::is_absolute(dir) ? "" : StringRef(D.SysRoot);400 addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir);401 }402 return;403 }404 405 if (!D.SysRoot.empty()) {406 SmallString<128> P(D.SysRoot);407 llvm::sys::path::append(P, "include");408 addExternCSystemInclude(DriverArgs, CC1Args, P.str());409 }410}411 412void Fuchsia::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,413 ArgStringList &CC1Args) const {414 if (DriverArgs.hasArg(options::OPT_nostdinc, options::OPT_nostdlibinc,415 options::OPT_nostdincxx))416 return;417 418 const Driver &D = getDriver();419 std::string Target = getTripleString();420 421 auto AddCXXIncludePath = [&](StringRef Path) {422 std::string Version = detectLibcxxVersion(Path);423 if (Version.empty())424 return;425 426 // First add the per-target multilib include dir.427 if (!SelectedMultilibs.empty() && !SelectedMultilibs.back().isDefault()) {428 const Multilib &M = SelectedMultilibs.back();429 SmallString<128> TargetDir(Path);430 llvm::sys::path::append(TargetDir, Target, M.gccSuffix(), "c++", Version);431 if (getVFS().exists(TargetDir)) {432 addSystemInclude(DriverArgs, CC1Args, TargetDir);433 }434 }435 436 // Second add the per-target include dir.437 SmallString<128> TargetDir(Path);438 llvm::sys::path::append(TargetDir, Target, "c++", Version);439 if (getVFS().exists(TargetDir))440 addSystemInclude(DriverArgs, CC1Args, TargetDir);441 442 // Third the generic one.443 SmallString<128> Dir(Path);444 llvm::sys::path::append(Dir, "c++", Version);445 addSystemInclude(DriverArgs, CC1Args, Dir);446 };447 448 switch (GetCXXStdlibType(DriverArgs)) {449 case ToolChain::CST_Libcxx: {450 SmallString<128> P(D.Dir);451 llvm::sys::path::append(P, "..", "include");452 AddCXXIncludePath(P);453 break;454 }455 456 default:457 llvm_unreachable("invalid stdlib name");458 }459}460 461void Fuchsia::AddCXXStdlibLibArgs(const ArgList &Args,462 ArgStringList &CmdArgs) const {463 switch (GetCXXStdlibType(Args)) {464 case ToolChain::CST_Libcxx:465 CmdArgs.push_back("-lc++");466 if (Args.hasArg(options::OPT_fexperimental_library))467 CmdArgs.push_back("-lc++experimental");468 break;469 470 case ToolChain::CST_Libstdcxx:471 llvm_unreachable("invalid stdlib name");472 }473}474 475SanitizerMask Fuchsia::getSupportedSanitizers() const {476 SanitizerMask Res = ToolChain::getSupportedSanitizers();477 Res |= SanitizerKind::Address;478 Res |= SanitizerKind::HWAddress;479 Res |= SanitizerKind::PointerCompare;480 Res |= SanitizerKind::PointerSubtract;481 Res |= SanitizerKind::Fuzzer;482 Res |= SanitizerKind::FuzzerNoLink;483 Res |= SanitizerKind::Leak;484 Res |= SanitizerKind::Scudo;485 Res |= SanitizerKind::Thread;486 if (getTriple().getArch() == llvm::Triple::x86_64 ||487 getTriple().getArch() == llvm::Triple::x86) {488 Res |= SanitizerKind::SafeStack;489 }490 return Res;491}492 493SanitizerMask Fuchsia::getDefaultSanitizers() const {494 SanitizerMask Res;495 switch (getTriple().getArch()) {496 case llvm::Triple::aarch64:497 case llvm::Triple::riscv64:498 Res |= SanitizerKind::ShadowCallStack;499 break;500 case llvm::Triple::x86:501 case llvm::Triple::x86_64:502 Res |= SanitizerKind::SafeStack;503 break;504 default:505 break;506 }507 return Res;508}509