1//===--- NaCl.cpp - Native Client 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 "NaCl.h"
10#include "clang/Driver/CommonArgs.h"
11#include "clang/Driver/Compilation.h"
12#include "clang/Driver/Driver.h"
13#include "clang/Driver/InputInfo.h"
14#include "clang/Driver/Options.h"
15#include "llvm/Option/ArgList.h"
16#include "llvm/Support/Path.h"
17
18using namespace clang::driver;
19using namespace clang::driver::tools;
20using namespace clang::driver::toolchains;
21using namespace clang;
22using namespace llvm::opt;
23
24// NaCl ARM assembly (inline or standalone) can be written with a set of macros
25// for the various SFI requirements like register masking. The assembly tool
26// inserts the file containing the macros as an input into all the assembly
27// jobs.
28void nacltools::AssemblerARM::ConstructJob(Compilation &C, const JobAction &JA,
29 const InputInfo &Output,
30 const InputInfoList &Inputs,
31 const ArgList &Args,
32 const char *LinkingOutput) const {
33 const auto &ToolChain = static_cast<const NaClToolChain &>(getToolChain());
34 InputInfo NaClMacros(types::TY_PP_Asm, ToolChain.GetNaClArmMacrosPath(),
35 "nacl-arm-macros.s");
36 InputInfoList NewInputs;
37 NewInputs.push_back(Elt: NaClMacros);
38 NewInputs.append(in_start: Inputs.begin(), in_end: Inputs.end());
39 gnutools::Assembler::ConstructJob(C, JA, Output, Inputs: NewInputs, TCArgs: Args,
40 LinkingOutput);
41}
42
43// This is quite similar to gnutools::Linker::ConstructJob with changes that
44// we use static by default, do not yet support sanitizers or LTO, and a few
45// others. Eventually we can support more of that and hopefully migrate back
46// to gnutools::Linker.
47void nacltools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
48 const InputInfo &Output,
49 const InputInfoList &Inputs,
50 const ArgList &Args,
51 const char *LinkingOutput) const {
52
53 const auto &ToolChain = static_cast<const NaClToolChain &>(getToolChain());
54 const Driver &D = ToolChain.getDriver();
55 const llvm::Triple::ArchType Arch = ToolChain.getArch();
56 const bool IsStatic =
57 !Args.hasArg(options::OPT_dynamic) && !Args.hasArg(options::OPT_shared);
58
59 ArgStringList CmdArgs;
60
61 // Silence warning for "clang -g foo.o -o foo"
62 Args.ClaimAllArgs(options::OPT_g_Group);
63 // and "clang -emit-llvm foo.o -o foo"
64 Args.ClaimAllArgs(options::OPT_emit_llvm);
65 // and for "clang -w foo.o -o foo". Other warning options are already
66 // handled somewhere else.
67 Args.ClaimAllArgs(options::OPT_w);
68
69 if (!D.SysRoot.empty())
70 CmdArgs.push_back(Elt: Args.MakeArgString(Str: "--sysroot=" + D.SysRoot));
71
72 if (Args.hasArg(options::OPT_rdynamic))
73 CmdArgs.push_back(Elt: "-export-dynamic");
74
75 if (Args.hasArg(options::OPT_s))
76 CmdArgs.push_back(Elt: "-s");
77
78 // NaClToolChain doesn't have ExtraOpts like Linux; the only relevant flag
79 // from there is --build-id, which we do want.
80 CmdArgs.push_back(Elt: "--build-id");
81
82 if (!IsStatic)
83 CmdArgs.push_back(Elt: "--eh-frame-hdr");
84
85 CmdArgs.push_back(Elt: "-m");
86 if (Arch == llvm::Triple::x86)
87 CmdArgs.push_back(Elt: "elf_i386_nacl");
88 else if (Arch == llvm::Triple::arm)
89 CmdArgs.push_back(Elt: "armelf_nacl");
90 else if (Arch == llvm::Triple::x86_64)
91 CmdArgs.push_back(Elt: "elf_x86_64_nacl");
92 else if (Arch == llvm::Triple::mipsel)
93 CmdArgs.push_back(Elt: "mipselelf_nacl");
94 else
95 D.Diag(diag::DiagID: err_target_unsupported_arch) << ToolChain.getArchName()
96 << "Native Client";
97
98 if (IsStatic)
99 CmdArgs.push_back(Elt: "-static");
100 else if (Args.hasArg(options::OPT_shared))
101 CmdArgs.push_back(Elt: "-shared");
102
103 CmdArgs.push_back(Elt: "-o");
104 CmdArgs.push_back(Elt: Output.getFilename());
105 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
106 if (!Args.hasArg(options::OPT_shared))
107 CmdArgs.push_back(Elt: Args.MakeArgString(Str: ToolChain.GetFilePath(Name: "crt1.o")));
108 CmdArgs.push_back(Elt: Args.MakeArgString(Str: ToolChain.GetFilePath(Name: "crti.o")));
109
110 const char *crtbegin;
111 if (IsStatic)
112 crtbegin = "crtbeginT.o";
113 else if (Args.hasArg(options::OPT_shared))
114 crtbegin = "crtbeginS.o";
115 else
116 crtbegin = "crtbegin.o";
117 CmdArgs.push_back(Elt: Args.MakeArgString(Str: ToolChain.GetFilePath(Name: crtbegin)));
118 }
119
120 Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_u});
121
122 ToolChain.AddFilePathLibArgs(Args, CmdArgs);
123
124 if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle))
125 CmdArgs.push_back(Elt: "--no-demangle");
126
127 AddLinkerInputs(TC: ToolChain, Inputs, Args, CmdArgs, JA);
128
129 if (D.CCCIsCXX() &&
130 !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
131 if (ToolChain.ShouldLinkCXXStdlib(Args)) {
132 bool OnlyLibstdcxxStatic =
133 Args.hasArg(options::OPT_static_libstdcxx) && !IsStatic;
134 if (OnlyLibstdcxxStatic)
135 CmdArgs.push_back(Elt: "-Bstatic");
136 ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
137 if (OnlyLibstdcxxStatic)
138 CmdArgs.push_back(Elt: "-Bdynamic");
139 }
140 CmdArgs.push_back(Elt: "-lm");
141 }
142
143 if (!Args.hasArg(options::OPT_nostdlib)) {
144 if (!Args.hasArg(options::OPT_nodefaultlibs)) {
145 // Always use groups, since it has no effect on dynamic libraries.
146 CmdArgs.push_back(Elt: "--start-group");
147 CmdArgs.push_back(Elt: "-lc");
148 // NaCl's libc++ currently requires libpthread, so just always include it
149 // in the group for C++.
150 if (Args.hasArg(options::OPT_pthread) ||
151 Args.hasArg(options::OPT_pthreads) || D.CCCIsCXX()) {
152 // Gold, used by Mips, handles nested groups differently than ld, and
153 // without '-lnacl' it prefers symbols from libpthread.a over libnacl.a,
154 // which is not a desired behaviour here.
155 // See https://sourceware.org/ml/binutils/2015-03/msg00034.html
156 if (getToolChain().getArch() == llvm::Triple::mipsel)
157 CmdArgs.push_back(Elt: "-lnacl");
158
159 CmdArgs.push_back(Elt: "-lpthread");
160 }
161
162 CmdArgs.push_back(Elt: "-lgcc");
163 CmdArgs.push_back(Elt: "--as-needed");
164 if (IsStatic)
165 CmdArgs.push_back(Elt: "-lgcc_eh");
166 else
167 CmdArgs.push_back(Elt: "-lgcc_s");
168 CmdArgs.push_back(Elt: "--no-as-needed");
169
170 // Mips needs to create and use pnacl_legacy library that contains
171 // definitions from bitcode/pnaclmm.c and definitions for
172 // __nacl_tp_tls_offset() and __nacl_tp_tdb_offset().
173 if (getToolChain().getArch() == llvm::Triple::mipsel)
174 CmdArgs.push_back(Elt: "-lpnacl_legacy");
175
176 CmdArgs.push_back(Elt: "--end-group");
177 }
178
179 if (!Args.hasArg(options::OPT_nostartfiles)) {
180 const char *crtend;
181 if (Args.hasArg(options::OPT_shared))
182 crtend = "crtendS.o";
183 else
184 crtend = "crtend.o";
185
186 CmdArgs.push_back(Elt: Args.MakeArgString(Str: ToolChain.GetFilePath(Name: crtend)));
187 CmdArgs.push_back(Elt: Args.MakeArgString(Str: ToolChain.GetFilePath(Name: "crtn.o")));
188 }
189 }
190
191 const char *Exec = Args.MakeArgString(Str: ToolChain.GetLinkerPath());
192 C.addCommand(C: std::make_unique<Command>(args: JA, args: *this,
193 args: ResponseFileSupport::AtFileCurCP(),
194 args&: Exec, args&: CmdArgs, args: Inputs, args: Output));
195}
196
197/// NaCl Toolchain
198NaClToolChain::NaClToolChain(const Driver &D, const llvm::Triple &Triple,
199 const ArgList &Args)
200 : Generic_ELF(D, Triple, Args) {
201
202 // Remove paths added by Generic_GCC. NaCl Toolchain cannot use the
203 // default paths, and must instead only use the paths provided
204 // with this toolchain based on architecture.
205 path_list &file_paths = getFilePaths();
206 path_list &prog_paths = getProgramPaths();
207
208 file_paths.clear();
209 prog_paths.clear();
210
211 // Path for library files (libc.a, ...)
212 std::string FilePath(getDriver().Dir + "/../");
213
214 // Path for tools (clang, ld, etc..)
215 std::string ProgPath(getDriver().Dir + "/../");
216
217 // Path for toolchain libraries (libgcc.a, ...)
218 std::string ToolPath(getDriver().ResourceDir + "/lib/");
219
220 switch (Triple.getArch()) {
221 case llvm::Triple::x86:
222 file_paths.push_back(Elt: FilePath + "x86_64-nacl/lib32");
223 file_paths.push_back(Elt: FilePath + "i686-nacl/usr/lib");
224 prog_paths.push_back(Elt: ProgPath + "x86_64-nacl/bin");
225 file_paths.push_back(Elt: ToolPath + "i686-nacl");
226 break;
227 case llvm::Triple::x86_64:
228 file_paths.push_back(Elt: FilePath + "x86_64-nacl/lib");
229 file_paths.push_back(Elt: FilePath + "x86_64-nacl/usr/lib");
230 prog_paths.push_back(Elt: ProgPath + "x86_64-nacl/bin");
231 file_paths.push_back(Elt: ToolPath + "x86_64-nacl");
232 break;
233 case llvm::Triple::arm:
234 file_paths.push_back(Elt: FilePath + "arm-nacl/lib");
235 file_paths.push_back(Elt: FilePath + "arm-nacl/usr/lib");
236 prog_paths.push_back(Elt: ProgPath + "arm-nacl/bin");
237 file_paths.push_back(Elt: ToolPath + "arm-nacl");
238 break;
239 case llvm::Triple::mipsel:
240 file_paths.push_back(Elt: FilePath + "mipsel-nacl/lib");
241 file_paths.push_back(Elt: FilePath + "mipsel-nacl/usr/lib");
242 prog_paths.push_back(Elt: ProgPath + "bin");
243 file_paths.push_back(Elt: ToolPath + "mipsel-nacl");
244 break;
245 default:
246 break;
247 }
248
249 NaClArmMacrosPath = GetFilePath(Name: "nacl-arm-macros.s");
250}
251
252void NaClToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
253 ArgStringList &CC1Args) const {
254 const Driver &D = getDriver();
255 if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc))
256 return;
257
258 if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
259 SmallString<128> P(D.ResourceDir);
260 llvm::sys::path::append(path&: P, a: "include");
261 addSystemInclude(DriverArgs, CC1Args, Path: P.str());
262 }
263
264 if (DriverArgs.hasArg(options::OPT_nostdlibinc))
265 return;
266
267 SmallString<128> P(D.Dir + "/../");
268 switch (getTriple().getArch()) {
269 case llvm::Triple::x86:
270 // x86 is special because multilib style uses x86_64-nacl/include for libc
271 // headers but the SDK wants i686-nacl/usr/include. The other architectures
272 // have the same substring.
273 llvm::sys::path::append(path&: P, a: "i686-nacl/usr/include");
274 addSystemInclude(DriverArgs, CC1Args, Path: P.str());
275 llvm::sys::path::remove_filename(path&: P);
276 llvm::sys::path::remove_filename(path&: P);
277 llvm::sys::path::remove_filename(path&: P);
278 llvm::sys::path::append(path&: P, a: "x86_64-nacl/include");
279 addSystemInclude(DriverArgs, CC1Args, Path: P.str());
280 return;
281 case llvm::Triple::arm:
282 llvm::sys::path::append(path&: P, a: "arm-nacl/usr/include");
283 break;
284 case llvm::Triple::x86_64:
285 llvm::sys::path::append(path&: P, a: "x86_64-nacl/usr/include");
286 break;
287 case llvm::Triple::mipsel:
288 llvm::sys::path::append(path&: P, a: "mipsel-nacl/usr/include");
289 break;
290 default:
291 return;
292 }
293
294 addSystemInclude(DriverArgs, CC1Args, Path: P.str());
295 llvm::sys::path::remove_filename(path&: P);
296 llvm::sys::path::remove_filename(path&: P);
297 llvm::sys::path::append(path&: P, a: "include");
298 addSystemInclude(DriverArgs, CC1Args, Path: P.str());
299}
300
301void NaClToolChain::AddCXXStdlibLibArgs(const ArgList &Args,
302 ArgStringList &CmdArgs) const {
303 // Check for -stdlib= flags. We only support libc++ but this consumes the arg
304 // if the value is libc++, and emits an error for other values.
305 GetCXXStdlibType(Args);
306 CmdArgs.push_back(Elt: "-lc++");
307 if (Args.hasArg(options::OPT_fexperimental_library))
308 CmdArgs.push_back(Elt: "-lc++experimental");
309}
310
311void NaClToolChain::addLibCxxIncludePaths(
312 const llvm::opt::ArgList &DriverArgs,
313 llvm::opt::ArgStringList &CC1Args) const {
314 const Driver &D = getDriver();
315
316 SmallString<128> P(D.Dir + "/../");
317 switch (getTriple().getArch()) {
318 default:
319 break;
320 case llvm::Triple::arm:
321 llvm::sys::path::append(path&: P, a: "arm-nacl/include/c++/v1");
322 addSystemInclude(DriverArgs, CC1Args, Path: P.str());
323 break;
324 case llvm::Triple::x86:
325 llvm::sys::path::append(path&: P, a: "x86_64-nacl/include/c++/v1");
326 addSystemInclude(DriverArgs, CC1Args, Path: P.str());
327 break;
328 case llvm::Triple::x86_64:
329 llvm::sys::path::append(path&: P, a: "x86_64-nacl/include/c++/v1");
330 addSystemInclude(DriverArgs, CC1Args, Path: P.str());
331 break;
332 case llvm::Triple::mipsel:
333 llvm::sys::path::append(path&: P, a: "mipsel-nacl/include/c++/v1");
334 addSystemInclude(DriverArgs, CC1Args, Path: P.str());
335 break;
336 }
337}
338
339ToolChain::CXXStdlibType
340NaClToolChain::GetCXXStdlibType(const ArgList &Args) const {
341 if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) {
342 StringRef Value = A->getValue();
343 if (Value == "libc++")
344 return ToolChain::CST_Libcxx;
345 getDriver().Diag(clang::diag::DiagID: err_drv_invalid_stdlib_name)
346 << A->getAsString(Args);
347 }
348
349 return ToolChain::CST_Libcxx;
350}
351
352std::string
353NaClToolChain::ComputeEffectiveClangTriple(const ArgList &Args,
354 types::ID InputType) const {
355 llvm::Triple TheTriple(ComputeLLVMTriple(Args, InputType));
356 if (TheTriple.getArch() == llvm::Triple::arm &&
357 TheTriple.getEnvironment() == llvm::Triple::UnknownEnvironment)
358 TheTriple.setEnvironment(llvm::Triple::GNUEABIHF);
359 return TheTriple.getTriple();
360}
361
362Tool *NaClToolChain::buildLinker() const {
363 return new tools::nacltools::Linker(*this);
364}
365
366Tool *NaClToolChain::buildAssembler() const {
367 if (getTriple().getArch() == llvm::Triple::arm)
368 return new tools::nacltools::AssemblerARM(*this);
369 return new tools::gnutools::Assembler(*this);
370}
371

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of clang/lib/Driver/ToolChains/NaCl.cpp