xref: /freebsd/contrib/llvm-project/clang/lib/Driver/ToolChains/NetBSD.cpp (revision 06e20d1babecec1f45ffda513f55a8db5f1c0f56)
1 //===--- NetBSD.cpp - NetBSD 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 "NetBSD.h"
10 #include "Arch/ARM.h"
11 #include "Arch/Mips.h"
12 #include "Arch/Sparc.h"
13 #include "CommonArgs.h"
14 #include "clang/Driver/Compilation.h"
15 #include "clang/Driver/Driver.h"
16 #include "clang/Driver/Options.h"
17 #include "clang/Driver/SanitizerArgs.h"
18 #include "llvm/Option/ArgList.h"
19 #include "llvm/Support/VirtualFileSystem.h"
20 
21 using namespace clang::driver;
22 using namespace clang::driver::tools;
23 using namespace clang::driver::toolchains;
24 using namespace clang;
25 using namespace llvm::opt;
26 
27 void netbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
28                                      const InputInfo &Output,
29                                      const InputInfoList &Inputs,
30                                      const ArgList &Args,
31                                      const char *LinkingOutput) const {
32   claimNoWarnArgs(Args);
33   ArgStringList CmdArgs;
34 
35   // GNU as needs different flags for creating the correct output format
36   // on architectures with different ABIs or optional feature sets.
37   switch (getToolChain().getArch()) {
38   case llvm::Triple::x86:
39     CmdArgs.push_back("--32");
40     break;
41   case llvm::Triple::arm:
42   case llvm::Triple::armeb:
43   case llvm::Triple::thumb:
44   case llvm::Triple::thumbeb: {
45     StringRef MArch, MCPU;
46     arm::getARMArchCPUFromArgs(Args, MArch, MCPU, /*FromAs*/ true);
47     std::string Arch =
48         arm::getARMTargetCPU(MCPU, MArch, getToolChain().getTriple());
49     CmdArgs.push_back(Args.MakeArgString("-mcpu=" + Arch));
50     break;
51   }
52 
53   case llvm::Triple::mips:
54   case llvm::Triple::mipsel:
55   case llvm::Triple::mips64:
56   case llvm::Triple::mips64el: {
57     StringRef CPUName;
58     StringRef ABIName;
59     mips::getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName);
60 
61     CmdArgs.push_back("-march");
62     CmdArgs.push_back(CPUName.data());
63 
64     CmdArgs.push_back("-mabi");
65     CmdArgs.push_back(mips::getGnuCompatibleMipsABIName(ABIName).data());
66 
67     if (getToolChain().getTriple().isLittleEndian())
68       CmdArgs.push_back("-EL");
69     else
70       CmdArgs.push_back("-EB");
71 
72     AddAssemblerKPIC(getToolChain(), Args, CmdArgs);
73     break;
74   }
75 
76   case llvm::Triple::sparc:
77   case llvm::Triple::sparcel: {
78     CmdArgs.push_back("-32");
79     std::string CPU = getCPUName(Args, getToolChain().getTriple());
80     CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple()));
81     AddAssemblerKPIC(getToolChain(), Args, CmdArgs);
82     break;
83   }
84 
85   case llvm::Triple::sparcv9: {
86     CmdArgs.push_back("-64");
87     std::string CPU = getCPUName(Args, getToolChain().getTriple());
88     CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple()));
89     AddAssemblerKPIC(getToolChain(), Args, CmdArgs);
90     break;
91   }
92 
93   default:
94     break;
95   }
96 
97   Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
98 
99   CmdArgs.push_back("-o");
100   CmdArgs.push_back(Output.getFilename());
101 
102   for (const auto &II : Inputs)
103     CmdArgs.push_back(II.getFilename());
104 
105   const char *Exec = Args.MakeArgString((getToolChain().GetProgramPath("as")));
106   C.addCommand(std::make_unique<Command>(
107       JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs));
108 }
109 
110 void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
111                                   const InputInfo &Output,
112                                   const InputInfoList &Inputs,
113                                   const ArgList &Args,
114                                   const char *LinkingOutput) const {
115   const toolchains::NetBSD &ToolChain =
116     static_cast<const toolchains::NetBSD &>(getToolChain());
117   const Driver &D = ToolChain.getDriver();
118   ArgStringList CmdArgs;
119 
120   if (!D.SysRoot.empty())
121     CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
122 
123   CmdArgs.push_back("--eh-frame-hdr");
124   if (Args.hasArg(options::OPT_static)) {
125     CmdArgs.push_back("-Bstatic");
126     if (Args.hasArg(options::OPT_pie)) {
127       Args.AddAllArgs(CmdArgs, options::OPT_pie);
128       CmdArgs.push_back("--no-dynamic-linker");
129     }
130   } else {
131     if (Args.hasArg(options::OPT_rdynamic))
132       CmdArgs.push_back("-export-dynamic");
133     if (Args.hasArg(options::OPT_shared)) {
134       CmdArgs.push_back("-Bshareable");
135     } else {
136       Args.AddAllArgs(CmdArgs, options::OPT_pie);
137       CmdArgs.push_back("-dynamic-linker");
138       CmdArgs.push_back("/libexec/ld.elf_so");
139     }
140   }
141 
142   // Many NetBSD architectures support more than one ABI.
143   // Determine the correct emulation for ld.
144   switch (ToolChain.getArch()) {
145   case llvm::Triple::x86:
146     CmdArgs.push_back("-m");
147     CmdArgs.push_back("elf_i386");
148     break;
149   case llvm::Triple::arm:
150   case llvm::Triple::thumb:
151     CmdArgs.push_back("-m");
152     switch (ToolChain.getTriple().getEnvironment()) {
153     case llvm::Triple::EABI:
154     case llvm::Triple::GNUEABI:
155       CmdArgs.push_back("armelf_nbsd_eabi");
156       break;
157     case llvm::Triple::EABIHF:
158     case llvm::Triple::GNUEABIHF:
159       CmdArgs.push_back("armelf_nbsd_eabihf");
160       break;
161     default:
162       CmdArgs.push_back("armelf_nbsd");
163       break;
164     }
165     break;
166   case llvm::Triple::armeb:
167   case llvm::Triple::thumbeb:
168     arm::appendBE8LinkFlag(Args, CmdArgs, ToolChain.getEffectiveTriple());
169     CmdArgs.push_back("-m");
170     switch (ToolChain.getTriple().getEnvironment()) {
171     case llvm::Triple::EABI:
172     case llvm::Triple::GNUEABI:
173       CmdArgs.push_back("armelfb_nbsd_eabi");
174       break;
175     case llvm::Triple::EABIHF:
176     case llvm::Triple::GNUEABIHF:
177       CmdArgs.push_back("armelfb_nbsd_eabihf");
178       break;
179     default:
180       CmdArgs.push_back("armelfb_nbsd");
181       break;
182     }
183     break;
184   case llvm::Triple::mips64:
185   case llvm::Triple::mips64el:
186     if (mips::hasMipsAbiArg(Args, "32")) {
187       CmdArgs.push_back("-m");
188       if (ToolChain.getArch() == llvm::Triple::mips64)
189         CmdArgs.push_back("elf32btsmip");
190       else
191         CmdArgs.push_back("elf32ltsmip");
192     } else if (mips::hasMipsAbiArg(Args, "64")) {
193       CmdArgs.push_back("-m");
194       if (ToolChain.getArch() == llvm::Triple::mips64)
195         CmdArgs.push_back("elf64btsmip");
196       else
197         CmdArgs.push_back("elf64ltsmip");
198     }
199     break;
200   case llvm::Triple::ppc:
201     CmdArgs.push_back("-m");
202     CmdArgs.push_back("elf32ppc_nbsd");
203     break;
204 
205   case llvm::Triple::ppc64:
206   case llvm::Triple::ppc64le:
207     CmdArgs.push_back("-m");
208     CmdArgs.push_back("elf64ppc");
209     break;
210 
211   case llvm::Triple::sparc:
212     CmdArgs.push_back("-m");
213     CmdArgs.push_back("elf32_sparc");
214     break;
215 
216   case llvm::Triple::sparcv9:
217     CmdArgs.push_back("-m");
218     CmdArgs.push_back("elf64_sparc");
219     break;
220 
221   default:
222     break;
223   }
224 
225   if (Output.isFilename()) {
226     CmdArgs.push_back("-o");
227     CmdArgs.push_back(Output.getFilename());
228   } else {
229     assert(Output.isNothing() && "Invalid output.");
230   }
231 
232   if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
233     if (!Args.hasArg(options::OPT_shared)) {
234       CmdArgs.push_back(
235           Args.MakeArgString(ToolChain.GetFilePath("crt0.o")));
236     }
237     CmdArgs.push_back(
238         Args.MakeArgString(ToolChain.GetFilePath("crti.o")));
239     if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) {
240       CmdArgs.push_back(
241           Args.MakeArgString(ToolChain.GetFilePath("crtbeginS.o")));
242     } else {
243       CmdArgs.push_back(
244           Args.MakeArgString(ToolChain.GetFilePath("crtbegin.o")));
245     }
246   }
247 
248   Args.AddAllArgs(CmdArgs, options::OPT_L);
249   Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
250   Args.AddAllArgs(CmdArgs, options::OPT_e);
251   Args.AddAllArgs(CmdArgs, options::OPT_s);
252   Args.AddAllArgs(CmdArgs, options::OPT_t);
253   Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag);
254   Args.AddAllArgs(CmdArgs, options::OPT_r);
255 
256   bool NeedsSanitizerDeps = addSanitizerRuntimes(getToolChain(), Args, CmdArgs);
257   bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs);
258   AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
259 
260   const SanitizerArgs &SanArgs = ToolChain.getSanitizerArgs();
261   if (SanArgs.needsSharedRt()) {
262     CmdArgs.push_back("-rpath");
263     CmdArgs.push_back(Args.MakeArgString(
264         ToolChain.getCompilerRTPath().c_str()));
265   }
266 
267   unsigned Major, Minor, Micro;
268   ToolChain.getTriple().getOSVersion(Major, Minor, Micro);
269   bool useLibgcc = true;
270   if (Major >= 7 || Major == 0) {
271     switch (ToolChain.getArch()) {
272     case llvm::Triple::aarch64:
273     case llvm::Triple::aarch64_be:
274     case llvm::Triple::arm:
275     case llvm::Triple::armeb:
276     case llvm::Triple::thumb:
277     case llvm::Triple::thumbeb:
278     case llvm::Triple::ppc:
279     case llvm::Triple::ppc64:
280     case llvm::Triple::ppc64le:
281     case llvm::Triple::sparc:
282     case llvm::Triple::sparcv9:
283     case llvm::Triple::x86:
284     case llvm::Triple::x86_64:
285       useLibgcc = false;
286       break;
287     default:
288       break;
289     }
290   }
291 
292   if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
293     // Use the static OpenMP runtime with -static-openmp
294     bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) &&
295                         !Args.hasArg(options::OPT_static);
296     addOpenMPRuntime(CmdArgs, getToolChain(), Args, StaticOpenMP);
297 
298     if (D.CCCIsCXX()) {
299       if (ToolChain.ShouldLinkCXXStdlib(Args))
300         ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
301       CmdArgs.push_back("-lm");
302     }
303     if (NeedsSanitizerDeps)
304       linkSanitizerRuntimeDeps(getToolChain(), CmdArgs);
305     if (NeedsXRayDeps)
306       linkXRayRuntimeDeps(ToolChain, CmdArgs);
307     if (Args.hasArg(options::OPT_pthread))
308       CmdArgs.push_back("-lpthread");
309     CmdArgs.push_back("-lc");
310 
311     if (useLibgcc) {
312       if (Args.hasArg(options::OPT_static)) {
313         // libgcc_eh depends on libc, so resolve as much as possible,
314         // pull in any new requirements from libc and then get the rest
315         // of libgcc.
316         CmdArgs.push_back("-lgcc_eh");
317         CmdArgs.push_back("-lc");
318         CmdArgs.push_back("-lgcc");
319       } else {
320         CmdArgs.push_back("-lgcc");
321         CmdArgs.push_back("--as-needed");
322         CmdArgs.push_back("-lgcc_s");
323         CmdArgs.push_back("--no-as-needed");
324       }
325     }
326   }
327 
328   if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
329     if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie))
330       CmdArgs.push_back(
331           Args.MakeArgString(ToolChain.GetFilePath("crtendS.o")));
332     else
333       CmdArgs.push_back(
334           Args.MakeArgString(ToolChain.GetFilePath("crtend.o")));
335     CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o")));
336   }
337 
338   ToolChain.addProfileRTLibs(Args, CmdArgs);
339 
340   const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
341   C.addCommand(std::make_unique<Command>(
342       JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs));
343 }
344 
345 /// NetBSD - NetBSD tool chain which can call as(1) and ld(1) directly.
346 
347 NetBSD::NetBSD(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
348     : Generic_ELF(D, Triple, Args) {
349   if (!Args.hasArg(options::OPT_nostdlib)) {
350     // When targeting a 32-bit platform, try the special directory used on
351     // 64-bit hosts, and only fall back to the main library directory if that
352     // doesn't work.
353     // FIXME: It'd be nicer to test if this directory exists, but I'm not sure
354     // what all logic is needed to emulate the '=' prefix here.
355     switch (Triple.getArch()) {
356     case llvm::Triple::x86:
357       getFilePaths().push_back("=/usr/lib/i386");
358       break;
359     case llvm::Triple::arm:
360     case llvm::Triple::armeb:
361     case llvm::Triple::thumb:
362     case llvm::Triple::thumbeb:
363       switch (Triple.getEnvironment()) {
364       case llvm::Triple::EABI:
365       case llvm::Triple::GNUEABI:
366         getFilePaths().push_back("=/usr/lib/eabi");
367         break;
368       case llvm::Triple::EABIHF:
369       case llvm::Triple::GNUEABIHF:
370         getFilePaths().push_back("=/usr/lib/eabihf");
371         break;
372       default:
373         getFilePaths().push_back("=/usr/lib/oabi");
374         break;
375       }
376       break;
377     case llvm::Triple::mips64:
378     case llvm::Triple::mips64el:
379       if (tools::mips::hasMipsAbiArg(Args, "o32"))
380         getFilePaths().push_back("=/usr/lib/o32");
381       else if (tools::mips::hasMipsAbiArg(Args, "64"))
382         getFilePaths().push_back("=/usr/lib/64");
383       break;
384     case llvm::Triple::ppc:
385       getFilePaths().push_back("=/usr/lib/powerpc");
386       break;
387     case llvm::Triple::sparc:
388       getFilePaths().push_back("=/usr/lib/sparc");
389       break;
390     default:
391       break;
392     }
393 
394     getFilePaths().push_back("=/usr/lib");
395   }
396 }
397 
398 Tool *NetBSD::buildAssembler() const {
399   return new tools::netbsd::Assembler(*this);
400 }
401 
402 Tool *NetBSD::buildLinker() const { return new tools::netbsd::Linker(*this); }
403 
404 ToolChain::CXXStdlibType NetBSD::GetDefaultCXXStdlibType() const {
405   unsigned Major, Minor, Micro;
406   getTriple().getOSVersion(Major, Minor, Micro);
407   if (Major >= 7 || Major == 0) {
408     switch (getArch()) {
409     case llvm::Triple::aarch64:
410     case llvm::Triple::aarch64_be:
411     case llvm::Triple::arm:
412     case llvm::Triple::armeb:
413     case llvm::Triple::thumb:
414     case llvm::Triple::thumbeb:
415     case llvm::Triple::ppc:
416     case llvm::Triple::ppc64:
417     case llvm::Triple::ppc64le:
418     case llvm::Triple::sparc:
419     case llvm::Triple::sparcv9:
420     case llvm::Triple::x86:
421     case llvm::Triple::x86_64:
422       return ToolChain::CST_Libcxx;
423     default:
424       break;
425     }
426   }
427   return ToolChain::CST_Libstdcxx;
428 }
429 
430 void NetBSD::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
431                                    llvm::opt::ArgStringList &CC1Args) const {
432   const std::string Candidates[] = {
433     // directory relative to build tree
434     getDriver().Dir + "/../include/c++/v1",
435     // system install with full upstream path
436     getDriver().SysRoot + "/usr/include/c++/v1",
437     // system install from src
438     getDriver().SysRoot + "/usr/include/c++",
439   };
440 
441   for (const auto &IncludePath : Candidates) {
442     if (!getVFS().exists(IncludePath + "/__config"))
443       continue;
444 
445     // Use the first candidate that looks valid.
446     addSystemInclude(DriverArgs, CC1Args, IncludePath);
447     return;
448   }
449 }
450 
451 void NetBSD::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
452                                       llvm::opt::ArgStringList &CC1Args) const {
453   addLibStdCXXIncludePaths(getDriver().SysRoot, "/usr/include/g++", "", "", "",
454                            "", DriverArgs, CC1Args);
455 }
456 
457 llvm::ExceptionHandling NetBSD::GetExceptionModel(const ArgList &Args) const {
458   // NetBSD uses Dwarf exceptions on ARM.
459   llvm::Triple::ArchType TArch = getTriple().getArch();
460   if (TArch == llvm::Triple::arm || TArch == llvm::Triple::armeb ||
461       TArch == llvm::Triple::thumb || TArch == llvm::Triple::thumbeb)
462     return llvm::ExceptionHandling::DwarfCFI;
463   return llvm::ExceptionHandling::None;
464 }
465 
466 SanitizerMask NetBSD::getSupportedSanitizers() const {
467   const bool IsX86 = getTriple().getArch() == llvm::Triple::x86;
468   const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64;
469   SanitizerMask Res = ToolChain::getSupportedSanitizers();
470   if (IsX86 || IsX86_64) {
471     Res |= SanitizerKind::Address;
472     Res |= SanitizerKind::PointerCompare;
473     Res |= SanitizerKind::PointerSubtract;
474     Res |= SanitizerKind::Function;
475     Res |= SanitizerKind::Leak;
476     Res |= SanitizerKind::SafeStack;
477     Res |= SanitizerKind::Scudo;
478     Res |= SanitizerKind::Vptr;
479   }
480   if (IsX86_64) {
481     Res |= SanitizerKind::DataFlow;
482     Res |= SanitizerKind::Fuzzer;
483     Res |= SanitizerKind::FuzzerNoLink;
484     Res |= SanitizerKind::HWAddress;
485     Res |= SanitizerKind::KernelAddress;
486     Res |= SanitizerKind::KernelHWAddress;
487     Res |= SanitizerKind::KernelMemory;
488     Res |= SanitizerKind::Memory;
489     Res |= SanitizerKind::Thread;
490   }
491   return Res;
492 }
493 
494 void NetBSD::addClangTargetOptions(const ArgList &DriverArgs,
495                                    ArgStringList &CC1Args,
496                                    Action::OffloadKind) const {
497   const SanitizerArgs &SanArgs = getSanitizerArgs();
498   if (SanArgs.hasAnySanitizer())
499     CC1Args.push_back("-D_REENTRANT");
500 
501   unsigned Major, Minor, Micro;
502   getTriple().getOSVersion(Major, Minor, Micro);
503   bool UseInitArrayDefault =
504     Major >= 9 || Major == 0 ||
505     getTriple().getArch() == llvm::Triple::aarch64 ||
506     getTriple().getArch() == llvm::Triple::aarch64_be ||
507     getTriple().getArch() == llvm::Triple::arm ||
508     getTriple().getArch() == llvm::Triple::armeb;
509 
510   if (!DriverArgs.hasFlag(options::OPT_fuse_init_array,
511                           options::OPT_fno_use_init_array, UseInitArrayDefault))
512     CC1Args.push_back("-fno-use-init-array");
513 }
514