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