1 //===--- Fuchsia.cpp - Fuchsia ToolChain Implementations --------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
10 #include "CommonArgs.h"
11 #include "clang/Config/config.h"
12 #include "clang/Driver/Compilation.h"
13 #include "clang/Driver/Driver.h"
14 #include "clang/Driver/DriverDiagnostic.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"
23 using namespace clang::driver
;
24 using namespace clang::driver::toolchains
;
25 using namespace clang::driver::tools
;
26 using namespace clang
;
27 using namespace llvm::opt
;
29 using tools::addMultilibFlag
;
31 void fuchsia::Linker::ConstructJob(Compilation
&C
, const JobAction
&JA
,
32 const InputInfo
&Output
,
33 const InputInfoList
&Inputs
,
35 const char *LinkingOutput
) const {
36 const toolchains::Fuchsia
&ToolChain
=
37 static_cast<const toolchains::Fuchsia
&>(getToolChain());
38 const Driver
&D
= ToolChain
.getDriver();
40 const llvm::Triple
&Triple
= ToolChain
.getEffectiveTriple();
42 ArgStringList CmdArgs
;
44 // Silence warning for "clang -g foo.o -o foo"
45 Args
.ClaimAllArgs(options::OPT_g_Group
);
46 // and "clang -emit-llvm foo.o -o foo"
47 Args
.ClaimAllArgs(options::OPT_emit_llvm
);
48 // and for "clang -w foo.o -o foo". Other warning options are already
49 // handled somewhere else.
50 Args
.ClaimAllArgs(options::OPT_w
);
52 CmdArgs
.push_back("-z");
53 CmdArgs
.push_back("max-page-size=4096");
55 CmdArgs
.push_back("-z");
56 CmdArgs
.push_back("now");
58 const char *Exec
= Args
.MakeArgString(ToolChain
.GetLinkerPath());
59 if (llvm::sys::path::filename(Exec
).equals_insensitive("ld.lld") ||
60 llvm::sys::path::stem(Exec
).equals_insensitive("ld.lld")) {
61 CmdArgs
.push_back("-z");
62 CmdArgs
.push_back("rodynamic");
63 CmdArgs
.push_back("-z");
64 CmdArgs
.push_back("separate-loadable-segments");
65 CmdArgs
.push_back("-z");
66 CmdArgs
.push_back("rel");
67 CmdArgs
.push_back("--pack-dyn-relocs=relr");
70 if (!D
.SysRoot
.empty())
71 CmdArgs
.push_back(Args
.MakeArgString("--sysroot=" + D
.SysRoot
));
73 if (!Args
.hasArg(options::OPT_shared
) && !Args
.hasArg(options::OPT_r
))
74 CmdArgs
.push_back("-pie");
76 if (Args
.hasArg(options::OPT_rdynamic
))
77 CmdArgs
.push_back("-export-dynamic");
79 if (Args
.hasArg(options::OPT_s
))
80 CmdArgs
.push_back("-s");
82 if (Args
.hasArg(options::OPT_r
)) {
83 CmdArgs
.push_back("-r");
85 CmdArgs
.push_back("--build-id");
86 CmdArgs
.push_back("--hash-style=gnu");
89 if (ToolChain
.getArch() == llvm::Triple::aarch64
) {
90 std::string CPU
= getCPUName(D
, Args
, Triple
);
91 if (CPU
.empty() || CPU
== "generic" || CPU
== "cortex-a53")
92 CmdArgs
.push_back("--fix-cortex-a53-843419");
95 CmdArgs
.push_back("--eh-frame-hdr");
97 if (Args
.hasArg(options::OPT_static
))
98 CmdArgs
.push_back("-Bstatic");
99 else if (Args
.hasArg(options::OPT_shared
))
100 CmdArgs
.push_back("-shared");
102 const SanitizerArgs
&SanArgs
= ToolChain
.getSanitizerArgs(Args
);
104 if (!Args
.hasArg(options::OPT_shared
) && !Args
.hasArg(options::OPT_r
)) {
105 std::string Dyld
= D
.DyldPrefix
;
106 if (SanArgs
.needsAsanRt() && SanArgs
.needsSharedRt())
108 if (SanArgs
.needsHwasanRt() && SanArgs
.needsSharedRt())
110 if (SanArgs
.needsTsanRt() && SanArgs
.needsSharedRt())
113 CmdArgs
.push_back("-dynamic-linker");
114 CmdArgs
.push_back(Args
.MakeArgString(Dyld
));
117 if (ToolChain
.getArch() == llvm::Triple::riscv64
)
118 CmdArgs
.push_back("-X");
120 CmdArgs
.push_back("-o");
121 CmdArgs
.push_back(Output
.getFilename());
123 if (!Args
.hasArg(options::OPT_nostdlib
, options::OPT_nostartfiles
,
125 if (!Args
.hasArg(options::OPT_shared
)) {
126 CmdArgs
.push_back(Args
.MakeArgString(ToolChain
.GetFilePath("Scrt1.o")));
130 Args
.AddAllArgs(CmdArgs
, options::OPT_L
);
131 Args
.AddAllArgs(CmdArgs
, options::OPT_u
);
133 ToolChain
.AddFilePathLibArgs(Args
, CmdArgs
);
135 if (D
.isUsingLTO()) {
136 assert(!Inputs
.empty() && "Must have at least one input.");
137 addLTOOptions(ToolChain
, Args
, CmdArgs
, Output
, Inputs
[0],
138 D
.getLTOMode() == LTOK_Thin
);
141 addLinkerCompressDebugSectionsOption(ToolChain
, Args
, CmdArgs
);
142 AddLinkerInputs(ToolChain
, Inputs
, Args
, CmdArgs
, JA
);
144 if (!Args
.hasArg(options::OPT_nostdlib
, options::OPT_nodefaultlibs
,
146 if (Args
.hasArg(options::OPT_static
))
147 CmdArgs
.push_back("-Bdynamic");
150 if (ToolChain
.ShouldLinkCXXStdlib(Args
)) {
151 bool OnlyLibstdcxxStatic
= Args
.hasArg(options::OPT_static_libstdcxx
) &&
152 !Args
.hasArg(options::OPT_static
);
153 CmdArgs
.push_back("--push-state");
154 CmdArgs
.push_back("--as-needed");
155 if (OnlyLibstdcxxStatic
)
156 CmdArgs
.push_back("-Bstatic");
157 ToolChain
.AddCXXStdlibLibArgs(Args
, CmdArgs
);
158 if (OnlyLibstdcxxStatic
)
159 CmdArgs
.push_back("-Bdynamic");
160 CmdArgs
.push_back("-lm");
161 CmdArgs
.push_back("--pop-state");
165 // Note that Fuchsia never needs to link in sanitizer runtime deps. Any
166 // sanitizer runtimes with system dependencies use the `.deplibs` feature
168 addSanitizerRuntimes(ToolChain
, Args
, CmdArgs
);
170 addXRayRuntime(ToolChain
, Args
, CmdArgs
);
172 ToolChain
.addProfileRTLibs(Args
, CmdArgs
);
174 AddRunTimeLibs(ToolChain
, D
, CmdArgs
, Args
);
176 if (Args
.hasArg(options::OPT_pthread
) ||
177 Args
.hasArg(options::OPT_pthreads
))
178 CmdArgs
.push_back("-lpthread");
180 if (Args
.hasArg(options::OPT_fsplit_stack
))
181 CmdArgs
.push_back("--wrap=pthread_create");
183 if (!Args
.hasArg(options::OPT_nolibc
))
184 CmdArgs
.push_back("-lc");
187 C
.addCommand(std::make_unique
<Command
>(JA
, *this, ResponseFileSupport::None(),
188 Exec
, CmdArgs
, Inputs
, Output
));
191 /// Fuchsia - Fuchsia tool chain which can call as(1) and ld(1) directly.
193 Fuchsia::Fuchsia(const Driver
&D
, const llvm::Triple
&Triple
,
195 : ToolChain(D
, Triple
, Args
) {
196 getProgramPaths().push_back(getDriver().getInstalledDir());
197 if (getDriver().getInstalledDir() != D
.Dir
)
198 getProgramPaths().push_back(D
.Dir
);
200 if (!D
.SysRoot
.empty()) {
201 SmallString
<128> P(D
.SysRoot
);
202 llvm::sys::path::append(P
, "lib");
203 getFilePaths().push_back(std::string(P
.str()));
206 auto FilePaths
= [&](const Multilib
&M
) -> std::vector
<std::string
> {
207 std::vector
<std::string
> FP
;
208 for (const std::string
&Path
: getStdlibPaths()) {
209 SmallString
<128> P(Path
);
210 llvm::sys::path::append(P
, M
.gccSuffix());
211 FP
.push_back(std::string(P
.str()));
216 Multilibs
.push_back(Multilib());
217 // Use the noexcept variant with -fno-exceptions to avoid the extra overhead.
218 Multilibs
.push_back(Multilib("noexcept", {}, {}, 1)
219 .flag("-fexceptions")
220 .flag("+fno-exceptions"));
221 // ASan has higher priority because we always want the instrumentated version.
222 Multilibs
.push_back(Multilib("asan", {}, {}, 2)
223 .flag("+fsanitize=address"));
224 // Use the asan+noexcept variant with ASan and -fno-exceptions.
225 Multilibs
.push_back(Multilib("asan+noexcept", {}, {}, 3)
226 .flag("+fsanitize=address")
227 .flag("-fexceptions")
228 .flag("+fno-exceptions"));
229 // HWASan has higher priority because we always want the instrumentated
232 Multilib("hwasan", {}, {}, 4).flag("+fsanitize=hwaddress"));
233 // Use the hwasan+noexcept variant with HWASan and -fno-exceptions.
234 Multilibs
.push_back(Multilib("hwasan+noexcept", {}, {}, 5)
235 .flag("+fsanitize=hwaddress")
236 .flag("-fexceptions")
237 .flag("+fno-exceptions"));
238 // Use the relative vtables ABI.
239 // TODO: Remove these multilibs once relative vtables are enabled by default
241 Multilibs
.push_back(Multilib("relative-vtables", {}, {}, 6)
242 .flag("+fexperimental-relative-c++-abi-vtables"));
243 Multilibs
.push_back(Multilib("relative-vtables+noexcept", {}, {}, 7)
244 .flag("+fexperimental-relative-c++-abi-vtables")
245 .flag("-fexceptions")
246 .flag("+fno-exceptions"));
247 Multilibs
.push_back(Multilib("relative-vtables+asan", {}, {}, 8)
248 .flag("+fexperimental-relative-c++-abi-vtables")
249 .flag("+fsanitize=address"));
250 Multilibs
.push_back(Multilib("relative-vtables+asan+noexcept", {}, {}, 9)
251 .flag("+fexperimental-relative-c++-abi-vtables")
252 .flag("+fsanitize=address")
253 .flag("-fexceptions")
254 .flag("+fno-exceptions"));
255 Multilibs
.push_back(Multilib("relative-vtables+hwasan", {}, {}, 10)
256 .flag("+fexperimental-relative-c++-abi-vtables")
257 .flag("+fsanitize=hwaddress"));
258 Multilibs
.push_back(Multilib("relative-vtables+hwasan+noexcept", {}, {}, 11)
259 .flag("+fexperimental-relative-c++-abi-vtables")
260 .flag("+fsanitize=hwaddress")
261 .flag("-fexceptions")
262 .flag("+fno-exceptions"));
263 // Use Itanium C++ ABI for the compat multilib.
264 Multilibs
.push_back(Multilib("compat", {}, {}, 12).flag("+fc++-abi=itanium"));
266 Multilibs
.FilterOut([&](const Multilib
&M
) {
267 std::vector
<std::string
> RD
= FilePaths(M
);
268 return llvm::all_of(RD
, [&](std::string P
) { return !getVFS().exists(P
); });
271 Multilib::flags_list Flags
;
273 Args
.hasFlag(options::OPT_fexceptions
, options::OPT_fno_exceptions
, true),
274 "fexceptions", Flags
);
275 addMultilibFlag(getSanitizerArgs(Args
).needsAsanRt(), "fsanitize=address",
277 addMultilibFlag(getSanitizerArgs(Args
).needsHwasanRt(), "fsanitize=hwaddress",
281 Args
.hasFlag(options::OPT_fexperimental_relative_cxx_abi_vtables
,
282 options::OPT_fno_experimental_relative_cxx_abi_vtables
,
284 "fexperimental-relative-c++-abi-vtables", Flags
);
285 addMultilibFlag(Args
.getLastArgValue(options::OPT_fcxx_abi_EQ
) == "itanium",
286 "fc++-abi=itanium", Flags
);
288 Multilibs
.setFilePathsCallback(FilePaths
);
290 if (Multilibs
.select(Flags
, SelectedMultilib
))
291 if (!SelectedMultilib
.isDefault())
292 if (const auto &PathsCallback
= Multilibs
.filePathsCallback())
293 for (const auto &Path
: PathsCallback(SelectedMultilib
))
294 // Prepend the multilib path to ensure it takes the precedence.
295 getFilePaths().insert(getFilePaths().begin(), Path
);
298 std::string
Fuchsia::ComputeEffectiveClangTriple(const ArgList
&Args
,
299 types::ID InputType
) const {
300 llvm::Triple
Triple(ComputeLLVMTriple(Args
, InputType
));
304 Tool
*Fuchsia::buildLinker() const {
305 return new tools::fuchsia::Linker(*this);
308 ToolChain::RuntimeLibType
Fuchsia::GetRuntimeLibType(
309 const ArgList
&Args
) const {
310 if (Arg
*A
= Args
.getLastArg(clang::driver::options::OPT_rtlib_EQ
)) {
311 StringRef Value
= A
->getValue();
312 if (Value
!= "compiler-rt")
313 getDriver().Diag(clang::diag::err_drv_invalid_rtlib_name
)
314 << A
->getAsString(Args
);
317 return ToolChain::RLT_CompilerRT
;
320 ToolChain::CXXStdlibType
321 Fuchsia::GetCXXStdlibType(const ArgList
&Args
) const {
322 if (Arg
*A
= Args
.getLastArg(options::OPT_stdlib_EQ
)) {
323 StringRef Value
= A
->getValue();
324 if (Value
!= "libc++")
325 getDriver().Diag(diag::err_drv_invalid_stdlib_name
)
326 << A
->getAsString(Args
);
329 return ToolChain::CST_Libcxx
;
332 void Fuchsia::addClangTargetOptions(const ArgList
&DriverArgs
,
333 ArgStringList
&CC1Args
,
334 Action::OffloadKind
) const {
335 if (!DriverArgs
.hasFlag(options::OPT_fuse_init_array
,
336 options::OPT_fno_use_init_array
, true))
337 CC1Args
.push_back("-fno-use-init-array");
340 void Fuchsia::AddClangSystemIncludeArgs(const ArgList
&DriverArgs
,
341 ArgStringList
&CC1Args
) const {
342 const Driver
&D
= getDriver();
344 if (DriverArgs
.hasArg(options::OPT_nostdinc
))
347 if (!DriverArgs
.hasArg(options::OPT_nobuiltininc
)) {
348 SmallString
<128> P(D
.ResourceDir
);
349 llvm::sys::path::append(P
, "include");
350 addSystemInclude(DriverArgs
, CC1Args
, P
);
353 if (DriverArgs
.hasArg(options::OPT_nostdlibinc
))
356 // Check for configure-time C include directories.
357 StringRef
CIncludeDirs(C_INCLUDE_DIRS
);
358 if (CIncludeDirs
!= "") {
359 SmallVector
<StringRef
, 5> dirs
;
360 CIncludeDirs
.split(dirs
, ":");
361 for (StringRef dir
: dirs
) {
363 llvm::sys::path::is_absolute(dir
) ? "" : StringRef(D
.SysRoot
);
364 addExternCSystemInclude(DriverArgs
, CC1Args
, Prefix
+ dir
);
369 if (!D
.SysRoot
.empty()) {
370 SmallString
<128> P(D
.SysRoot
);
371 llvm::sys::path::append(P
, "include");
372 addExternCSystemInclude(DriverArgs
, CC1Args
, P
.str());
376 void Fuchsia::AddClangCXXStdlibIncludeArgs(const ArgList
&DriverArgs
,
377 ArgStringList
&CC1Args
) const {
378 if (DriverArgs
.hasArg(options::OPT_nostdlibinc
) ||
379 DriverArgs
.hasArg(options::OPT_nostdincxx
))
382 const Driver
&D
= getDriver();
383 std::string Target
= getTripleString();
385 auto AddCXXIncludePath
= [&](StringRef Path
) {
386 std::string Version
= detectLibcxxVersion(Path
);
390 // First add the per-target include path.
391 SmallString
<128> TargetDir(Path
);
392 llvm::sys::path::append(TargetDir
, Target
, "c++", Version
);
393 if (getVFS().exists(TargetDir
))
394 addSystemInclude(DriverArgs
, CC1Args
, TargetDir
);
396 // Second add the generic one.
397 SmallString
<128> Dir(Path
);
398 llvm::sys::path::append(Dir
, "c++", Version
);
399 addSystemInclude(DriverArgs
, CC1Args
, Dir
);
402 switch (GetCXXStdlibType(DriverArgs
)) {
403 case ToolChain::CST_Libcxx
: {
404 SmallString
<128> P(D
.Dir
);
405 llvm::sys::path::append(P
, "..", "include");
406 AddCXXIncludePath(P
);
411 llvm_unreachable("invalid stdlib name");
415 void Fuchsia::AddCXXStdlibLibArgs(const ArgList
&Args
,
416 ArgStringList
&CmdArgs
) const {
417 switch (GetCXXStdlibType(Args
)) {
418 case ToolChain::CST_Libcxx
:
419 CmdArgs
.push_back("-lc++");
420 if (Args
.hasArg(options::OPT_fexperimental_library
))
421 CmdArgs
.push_back("-lc++experimental");
424 case ToolChain::CST_Libstdcxx
:
425 llvm_unreachable("invalid stdlib name");
429 SanitizerMask
Fuchsia::getSupportedSanitizers() const {
430 SanitizerMask Res
= ToolChain::getSupportedSanitizers();
431 Res
|= SanitizerKind::Address
;
432 Res
|= SanitizerKind::HWAddress
;
433 Res
|= SanitizerKind::PointerCompare
;
434 Res
|= SanitizerKind::PointerSubtract
;
435 Res
|= SanitizerKind::Fuzzer
;
436 Res
|= SanitizerKind::FuzzerNoLink
;
437 Res
|= SanitizerKind::Leak
;
438 Res
|= SanitizerKind::SafeStack
;
439 Res
|= SanitizerKind::Scudo
;
440 Res
|= SanitizerKind::Thread
;
444 SanitizerMask
Fuchsia::getDefaultSanitizers() const {
446 switch (getTriple().getArch()) {
447 case llvm::Triple::aarch64
:
448 Res
|= SanitizerKind::ShadowCallStack
;
450 case llvm::Triple::x86_64
:
451 Res
|= SanitizerKind::SafeStack
;
454 // TODO: Enable SafeStack on RISC-V once tested.