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
21using namespace clang::driver;
22using namespace clang::driver::tools;
23using namespace clang::driver::toolchains;
24using namespace clang;
25using namespace llvm::opt;
26
27void 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
110void 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
347NetBSD::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
398Tool *NetBSD::buildAssembler() const {
399  return new tools::netbsd::Assembler(*this);
400}
401
402Tool *NetBSD::buildLinker() const { return new tools::netbsd::Linker(*this); }
403
404ToolChain::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
430void 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
451void 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
457llvm::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
466SanitizerMask 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
494void 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