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