Fuchsia.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  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-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. #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/Options.h"
  15. #include "clang/Driver/SanitizerArgs.h"
  16. #include "llvm/Option/ArgList.h"
  17. #include "llvm/ProfileData/InstrProf.h"
  18. #include "llvm/Support/FileSystem.h"
  19. #include "llvm/Support/Path.h"
  20. #include "llvm/Support/VirtualFileSystem.h"
  21. using namespace clang::driver;
  22. using namespace clang::driver::toolchains;
  23. using namespace clang::driver::tools;
  24. using namespace clang;
  25. using namespace llvm::opt;
  26. using tools::addMultilibFlag;
  27. void fuchsia::Linker::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 toolchains::Fuchsia &ToolChain =
  33. static_cast<const toolchains::Fuchsia &>(getToolChain());
  34. const Driver &D = ToolChain.getDriver();
  35. const llvm::Triple &Triple = ToolChain.getEffectiveTriple();
  36. ArgStringList CmdArgs;
  37. // Silence warning for "clang -g foo.o -o foo"
  38. Args.ClaimAllArgs(options::OPT_g_Group);
  39. // and "clang -emit-llvm foo.o -o foo"
  40. Args.ClaimAllArgs(options::OPT_emit_llvm);
  41. // and for "clang -w foo.o -o foo". Other warning options are already
  42. // handled somewhere else.
  43. Args.ClaimAllArgs(options::OPT_w);
  44. CmdArgs.push_back("-z");
  45. CmdArgs.push_back("max-page-size=4096");
  46. CmdArgs.push_back("-z");
  47. CmdArgs.push_back("now");
  48. const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
  49. if (llvm::sys::path::filename(Exec).equals_insensitive("ld.lld") ||
  50. llvm::sys::path::stem(Exec).equals_insensitive("ld.lld")) {
  51. CmdArgs.push_back("-z");
  52. CmdArgs.push_back("rodynamic");
  53. CmdArgs.push_back("-z");
  54. CmdArgs.push_back("separate-loadable-segments");
  55. CmdArgs.push_back("-z");
  56. CmdArgs.push_back("rel");
  57. CmdArgs.push_back("--pack-dyn-relocs=relr");
  58. }
  59. if (!D.SysRoot.empty())
  60. CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
  61. if (!Args.hasArg(options::OPT_shared) && !Args.hasArg(options::OPT_r))
  62. CmdArgs.push_back("-pie");
  63. if (Args.hasArg(options::OPT_rdynamic))
  64. CmdArgs.push_back("-export-dynamic");
  65. if (Args.hasArg(options::OPT_s))
  66. CmdArgs.push_back("-s");
  67. if (Args.hasArg(options::OPT_r)) {
  68. CmdArgs.push_back("-r");
  69. } else {
  70. CmdArgs.push_back("--build-id");
  71. CmdArgs.push_back("--hash-style=gnu");
  72. }
  73. if (ToolChain.getArch() == llvm::Triple::aarch64) {
  74. CmdArgs.push_back("--execute-only");
  75. std::string CPU = getCPUName(D, Args, Triple);
  76. if (CPU.empty() || CPU == "generic" || CPU == "cortex-a53")
  77. CmdArgs.push_back("--fix-cortex-a53-843419");
  78. }
  79. CmdArgs.push_back("--eh-frame-hdr");
  80. if (Args.hasArg(options::OPT_static))
  81. CmdArgs.push_back("-Bstatic");
  82. else if (Args.hasArg(options::OPT_shared))
  83. CmdArgs.push_back("-shared");
  84. const SanitizerArgs &SanArgs = ToolChain.getSanitizerArgs(Args);
  85. if (!Args.hasArg(options::OPT_shared) && !Args.hasArg(options::OPT_r)) {
  86. std::string Dyld = D.DyldPrefix;
  87. if (SanArgs.needsAsanRt() && SanArgs.needsSharedRt())
  88. Dyld += "asan/";
  89. if (SanArgs.needsHwasanRt() && SanArgs.needsSharedRt())
  90. Dyld += "hwasan/";
  91. if (SanArgs.needsTsanRt() && SanArgs.needsSharedRt())
  92. Dyld += "tsan/";
  93. Dyld += "ld.so.1";
  94. CmdArgs.push_back("-dynamic-linker");
  95. CmdArgs.push_back(Args.MakeArgString(Dyld));
  96. }
  97. if (ToolChain.getArch() == llvm::Triple::riscv64)
  98. CmdArgs.push_back("-X");
  99. CmdArgs.push_back("-o");
  100. CmdArgs.push_back(Output.getFilename());
  101. if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,
  102. options::OPT_r)) {
  103. if (!Args.hasArg(options::OPT_shared)) {
  104. CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("Scrt1.o")));
  105. }
  106. }
  107. Args.AddAllArgs(CmdArgs, options::OPT_L);
  108. Args.AddAllArgs(CmdArgs, options::OPT_u);
  109. ToolChain.AddFilePathLibArgs(Args, CmdArgs);
  110. if (D.isUsingLTO()) {
  111. assert(!Inputs.empty() && "Must have at least one input.");
  112. addLTOOptions(ToolChain, Args, CmdArgs, Output, Inputs[0],
  113. D.getLTOMode() == LTOK_Thin);
  114. }
  115. addLinkerCompressDebugSectionsOption(ToolChain, Args, CmdArgs);
  116. AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
  117. if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs,
  118. options::OPT_r)) {
  119. if (Args.hasArg(options::OPT_static))
  120. CmdArgs.push_back("-Bdynamic");
  121. if (D.CCCIsCXX()) {
  122. if (ToolChain.ShouldLinkCXXStdlib(Args)) {
  123. bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) &&
  124. !Args.hasArg(options::OPT_static);
  125. CmdArgs.push_back("--push-state");
  126. CmdArgs.push_back("--as-needed");
  127. if (OnlyLibstdcxxStatic)
  128. CmdArgs.push_back("-Bstatic");
  129. ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
  130. if (OnlyLibstdcxxStatic)
  131. CmdArgs.push_back("-Bdynamic");
  132. CmdArgs.push_back("-lm");
  133. CmdArgs.push_back("--pop-state");
  134. }
  135. }
  136. // Note that Fuchsia never needs to link in sanitizer runtime deps. Any
  137. // sanitizer runtimes with system dependencies use the `.deplibs` feature
  138. // instead.
  139. addSanitizerRuntimes(ToolChain, Args, CmdArgs);
  140. addXRayRuntime(ToolChain, Args, CmdArgs);
  141. ToolChain.addProfileRTLibs(Args, CmdArgs);
  142. AddRunTimeLibs(ToolChain, D, CmdArgs, Args);
  143. if (Args.hasArg(options::OPT_pthread) ||
  144. Args.hasArg(options::OPT_pthreads))
  145. CmdArgs.push_back("-lpthread");
  146. if (Args.hasArg(options::OPT_fsplit_stack))
  147. CmdArgs.push_back("--wrap=pthread_create");
  148. if (!Args.hasArg(options::OPT_nolibc))
  149. CmdArgs.push_back("-lc");
  150. }
  151. C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
  152. Exec, CmdArgs, Inputs, Output));
  153. }
  154. /// Fuchsia - Fuchsia tool chain which can call as(1) and ld(1) directly.
  155. Fuchsia::Fuchsia(const Driver &D, const llvm::Triple &Triple,
  156. const ArgList &Args)
  157. : ToolChain(D, Triple, Args) {
  158. getProgramPaths().push_back(getDriver().getInstalledDir());
  159. if (getDriver().getInstalledDir() != D.Dir)
  160. getProgramPaths().push_back(D.Dir);
  161. if (!D.SysRoot.empty()) {
  162. SmallString<128> P(D.SysRoot);
  163. llvm::sys::path::append(P, "lib");
  164. getFilePaths().push_back(std::string(P.str()));
  165. }
  166. auto FilePaths = [&](const Multilib &M) -> std::vector<std::string> {
  167. std::vector<std::string> FP;
  168. for (const std::string &Path : getStdlibPaths()) {
  169. SmallString<128> P(Path);
  170. llvm::sys::path::append(P, M.gccSuffix());
  171. FP.push_back(std::string(P.str()));
  172. }
  173. return FP;
  174. };
  175. Multilibs.push_back(Multilib());
  176. // Use the noexcept variant with -fno-exceptions to avoid the extra overhead.
  177. Multilibs.push_back(Multilib("noexcept", {}, {}, 1)
  178. .flag("-fexceptions")
  179. .flag("+fno-exceptions"));
  180. // ASan has higher priority because we always want the instrumentated version.
  181. Multilibs.push_back(Multilib("asan", {}, {}, 2)
  182. .flag("+fsanitize=address"));
  183. // Use the asan+noexcept variant with ASan and -fno-exceptions.
  184. Multilibs.push_back(Multilib("asan+noexcept", {}, {}, 3)
  185. .flag("+fsanitize=address")
  186. .flag("-fexceptions")
  187. .flag("+fno-exceptions"));
  188. // HWASan has higher priority because we always want the instrumentated
  189. // version.
  190. Multilibs.push_back(
  191. Multilib("hwasan", {}, {}, 4).flag("+fsanitize=hwaddress"));
  192. // Use the hwasan+noexcept variant with HWASan and -fno-exceptions.
  193. Multilibs.push_back(Multilib("hwasan+noexcept", {}, {}, 5)
  194. .flag("+fsanitize=hwaddress")
  195. .flag("-fexceptions")
  196. .flag("+fno-exceptions"));
  197. // Use the relative vtables ABI.
  198. // TODO: Remove these multilibs once relative vtables are enabled by default
  199. // for Fuchsia.
  200. Multilibs.push_back(Multilib("relative-vtables", {}, {}, 6)
  201. .flag("+fexperimental-relative-c++-abi-vtables"));
  202. Multilibs.push_back(Multilib("relative-vtables+noexcept", {}, {}, 7)
  203. .flag("+fexperimental-relative-c++-abi-vtables")
  204. .flag("-fexceptions")
  205. .flag("+fno-exceptions"));
  206. Multilibs.push_back(Multilib("relative-vtables+asan", {}, {}, 8)
  207. .flag("+fexperimental-relative-c++-abi-vtables")
  208. .flag("+fsanitize=address"));
  209. Multilibs.push_back(Multilib("relative-vtables+asan+noexcept", {}, {}, 9)
  210. .flag("+fexperimental-relative-c++-abi-vtables")
  211. .flag("+fsanitize=address")
  212. .flag("-fexceptions")
  213. .flag("+fno-exceptions"));
  214. Multilibs.push_back(Multilib("relative-vtables+hwasan", {}, {}, 10)
  215. .flag("+fexperimental-relative-c++-abi-vtables")
  216. .flag("+fsanitize=hwaddress"));
  217. Multilibs.push_back(Multilib("relative-vtables+hwasan+noexcept", {}, {}, 11)
  218. .flag("+fexperimental-relative-c++-abi-vtables")
  219. .flag("+fsanitize=hwaddress")
  220. .flag("-fexceptions")
  221. .flag("+fno-exceptions"));
  222. // Use Itanium C++ ABI for the compat multilib.
  223. Multilibs.push_back(Multilib("compat", {}, {}, 12).flag("+fc++-abi=itanium"));
  224. Multilibs.FilterOut([&](const Multilib &M) {
  225. std::vector<std::string> RD = FilePaths(M);
  226. return llvm::all_of(RD, [&](std::string P) { return !getVFS().exists(P); });
  227. });
  228. Multilib::flags_list Flags;
  229. addMultilibFlag(
  230. Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions, true),
  231. "fexceptions", Flags);
  232. addMultilibFlag(getSanitizerArgs(Args).needsAsanRt(), "fsanitize=address",
  233. Flags);
  234. addMultilibFlag(getSanitizerArgs(Args).needsHwasanRt(), "fsanitize=hwaddress",
  235. Flags);
  236. addMultilibFlag(
  237. Args.hasFlag(options::OPT_fexperimental_relative_cxx_abi_vtables,
  238. options::OPT_fno_experimental_relative_cxx_abi_vtables,
  239. /*default=*/false),
  240. "fexperimental-relative-c++-abi-vtables", Flags);
  241. addMultilibFlag(Args.getLastArgValue(options::OPT_fcxx_abi_EQ) == "itanium",
  242. "fc++-abi=itanium", Flags);
  243. Multilibs.setFilePathsCallback(FilePaths);
  244. if (Multilibs.select(Flags, SelectedMultilib))
  245. if (!SelectedMultilib.isDefault())
  246. if (const auto &PathsCallback = Multilibs.filePathsCallback())
  247. for (const auto &Path : PathsCallback(SelectedMultilib))
  248. // Prepend the multilib path to ensure it takes the precedence.
  249. getFilePaths().insert(getFilePaths().begin(), Path);
  250. }
  251. std::string Fuchsia::ComputeEffectiveClangTriple(const ArgList &Args,
  252. types::ID InputType) const {
  253. llvm::Triple Triple(ComputeLLVMTriple(Args, InputType));
  254. return Triple.str();
  255. }
  256. Tool *Fuchsia::buildLinker() const {
  257. return new tools::fuchsia::Linker(*this);
  258. }
  259. ToolChain::RuntimeLibType Fuchsia::GetRuntimeLibType(
  260. const ArgList &Args) const {
  261. if (Arg *A = Args.getLastArg(clang::driver::options::OPT_rtlib_EQ)) {
  262. StringRef Value = A->getValue();
  263. if (Value != "compiler-rt")
  264. getDriver().Diag(clang::diag::err_drv_invalid_rtlib_name)
  265. << A->getAsString(Args);
  266. }
  267. return ToolChain::RLT_CompilerRT;
  268. }
  269. ToolChain::CXXStdlibType
  270. Fuchsia::GetCXXStdlibType(const ArgList &Args) const {
  271. if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) {
  272. StringRef Value = A->getValue();
  273. if (Value != "libc++")
  274. getDriver().Diag(diag::err_drv_invalid_stdlib_name)
  275. << A->getAsString(Args);
  276. }
  277. return ToolChain::CST_Libcxx;
  278. }
  279. void Fuchsia::addClangTargetOptions(const ArgList &DriverArgs,
  280. ArgStringList &CC1Args,
  281. Action::OffloadKind) const {
  282. if (!DriverArgs.hasFlag(options::OPT_fuse_init_array,
  283. options::OPT_fno_use_init_array, true))
  284. CC1Args.push_back("-fno-use-init-array");
  285. }
  286. void Fuchsia::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
  287. ArgStringList &CC1Args) const {
  288. const Driver &D = getDriver();
  289. if (DriverArgs.hasArg(options::OPT_nostdinc))
  290. return;
  291. if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
  292. SmallString<128> P(D.ResourceDir);
  293. llvm::sys::path::append(P, "include");
  294. addSystemInclude(DriverArgs, CC1Args, P);
  295. }
  296. if (DriverArgs.hasArg(options::OPT_nostdlibinc))
  297. return;
  298. // Check for configure-time C include directories.
  299. StringRef CIncludeDirs(C_INCLUDE_DIRS);
  300. if (CIncludeDirs != "") {
  301. SmallVector<StringRef, 5> dirs;
  302. CIncludeDirs.split(dirs, ":");
  303. for (StringRef dir : dirs) {
  304. StringRef Prefix =
  305. llvm::sys::path::is_absolute(dir) ? "" : StringRef(D.SysRoot);
  306. addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir);
  307. }
  308. return;
  309. }
  310. if (!D.SysRoot.empty()) {
  311. SmallString<128> P(D.SysRoot);
  312. llvm::sys::path::append(P, "include");
  313. addExternCSystemInclude(DriverArgs, CC1Args, P.str());
  314. }
  315. }
  316. void Fuchsia::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
  317. ArgStringList &CC1Args) const {
  318. if (DriverArgs.hasArg(options::OPT_nostdinc, options::OPT_nostdlibinc,
  319. options::OPT_nostdincxx))
  320. return;
  321. const Driver &D = getDriver();
  322. std::string Target = getTripleString();
  323. auto AddCXXIncludePath = [&](StringRef Path) {
  324. std::string Version = detectLibcxxVersion(Path);
  325. if (Version.empty())
  326. return;
  327. // First add the per-target include path.
  328. SmallString<128> TargetDir(Path);
  329. llvm::sys::path::append(TargetDir, Target, "c++", Version);
  330. if (getVFS().exists(TargetDir))
  331. addSystemInclude(DriverArgs, CC1Args, TargetDir);
  332. // Second add the generic one.
  333. SmallString<128> Dir(Path);
  334. llvm::sys::path::append(Dir, "c++", Version);
  335. addSystemInclude(DriverArgs, CC1Args, Dir);
  336. };
  337. switch (GetCXXStdlibType(DriverArgs)) {
  338. case ToolChain::CST_Libcxx: {
  339. SmallString<128> P(D.Dir);
  340. llvm::sys::path::append(P, "..", "include");
  341. AddCXXIncludePath(P);
  342. break;
  343. }
  344. default:
  345. llvm_unreachable("invalid stdlib name");
  346. }
  347. }
  348. void Fuchsia::AddCXXStdlibLibArgs(const ArgList &Args,
  349. ArgStringList &CmdArgs) const {
  350. switch (GetCXXStdlibType(Args)) {
  351. case ToolChain::CST_Libcxx:
  352. CmdArgs.push_back("-lc++");
  353. if (Args.hasArg(options::OPT_fexperimental_library))
  354. CmdArgs.push_back("-lc++experimental");
  355. break;
  356. case ToolChain::CST_Libstdcxx:
  357. llvm_unreachable("invalid stdlib name");
  358. }
  359. }
  360. SanitizerMask Fuchsia::getSupportedSanitizers() const {
  361. SanitizerMask Res = ToolChain::getSupportedSanitizers();
  362. Res |= SanitizerKind::Address;
  363. Res |= SanitizerKind::HWAddress;
  364. Res |= SanitizerKind::PointerCompare;
  365. Res |= SanitizerKind::PointerSubtract;
  366. Res |= SanitizerKind::Fuzzer;
  367. Res |= SanitizerKind::FuzzerNoLink;
  368. Res |= SanitizerKind::Leak;
  369. Res |= SanitizerKind::SafeStack;
  370. Res |= SanitizerKind::Scudo;
  371. Res |= SanitizerKind::Thread;
  372. return Res;
  373. }
  374. SanitizerMask Fuchsia::getDefaultSanitizers() const {
  375. SanitizerMask Res;
  376. switch (getTriple().getArch()) {
  377. case llvm::Triple::aarch64:
  378. case llvm::Triple::riscv64:
  379. Res |= SanitizerKind::ShadowCallStack;
  380. break;
  381. case llvm::Triple::x86_64:
  382. Res |= SanitizerKind::SafeStack;
  383. break;
  384. default:
  385. break;
  386. }
  387. return Res;
  388. }