1//===--- OpenBSD.cpp - OpenBSD 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 "OpenBSD.h"
10#include "Arch/Mips.h"
11#include "Arch/Sparc.h"
12#include "CommonArgs.h"
13#include "clang/Config/config.h"
14#include "clang/Driver/Compilation.h"
15#include "clang/Driver/Options.h"
16#include "clang/Driver/SanitizerArgs.h"
17#include "llvm/Option/ArgList.h"
18#include "llvm/Support/Path.h"
19
20using namespace clang::driver;
21using namespace clang::driver::tools;
22using namespace clang::driver::toolchains;
23using namespace clang;
24using namespace llvm::opt;
25
26void openbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
27                                      const InputInfo &Output,
28                                      const InputInfoList &Inputs,
29                                      const ArgList &Args,
30                                      const char *LinkingOutput) const {
31  claimNoWarnArgs(Args);
32  ArgStringList CmdArgs;
33
34  switch (getToolChain().getArch()) {
35  case llvm::Triple::x86:
36    // When building 32-bit code on OpenBSD/amd64, we have to explicitly
37    // instruct as in the base system to assemble 32-bit code.
38    CmdArgs.push_back("--32");
39    break;
40
41  case llvm::Triple::ppc:
42    CmdArgs.push_back("-mppc");
43    CmdArgs.push_back("-many");
44    break;
45
46  case llvm::Triple::sparcv9: {
47    CmdArgs.push_back("-64");
48    std::string CPU = getCPUName(Args, getToolChain().getTriple());
49    CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple()));
50    AddAssemblerKPIC(getToolChain(), Args, CmdArgs);
51    break;
52  }
53
54  case llvm::Triple::mips64:
55  case llvm::Triple::mips64el: {
56    StringRef CPUName;
57    StringRef ABIName;
58    mips::getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName);
59
60    CmdArgs.push_back("-mabi");
61    CmdArgs.push_back(mips::getGnuCompatibleMipsABIName(ABIName).data());
62
63    if (getToolChain().getTriple().isLittleEndian())
64      CmdArgs.push_back("-EL");
65    else
66      CmdArgs.push_back("-EB");
67
68    AddAssemblerKPIC(getToolChain(), Args, CmdArgs);
69    break;
70  }
71
72  default:
73    break;
74  }
75
76  Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
77
78  CmdArgs.push_back("-o");
79  CmdArgs.push_back(Output.getFilename());
80
81  for (const auto &II : Inputs)
82    CmdArgs.push_back(II.getFilename());
83
84  const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
85  C.addCommand(std::make_unique<Command>(JA, *this,
86                                         ResponseFileSupport::AtFileCurCP(),
87                                         Exec, CmdArgs, Inputs, Output));
88}
89
90void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
91                                   const InputInfo &Output,
92                                   const InputInfoList &Inputs,
93                                   const ArgList &Args,
94                                   const char *LinkingOutput) const {
95  const toolchains::OpenBSD &ToolChain =
96      static_cast<const toolchains::OpenBSD &>(getToolChain());
97  const Driver &D = getToolChain().getDriver();
98  ArgStringList CmdArgs;
99
100  // Silence warning for "clang -g foo.o -o foo"
101  Args.ClaimAllArgs(options::OPT_g_Group);
102  // and "clang -emit-llvm foo.o -o foo"
103  Args.ClaimAllArgs(options::OPT_emit_llvm);
104  // and for "clang -w foo.o -o foo". Other warning options are already
105  // handled somewhere else.
106  Args.ClaimAllArgs(options::OPT_w);
107
108  if (ToolChain.getArch() == llvm::Triple::mips64)
109    CmdArgs.push_back("-EB");
110  else if (ToolChain.getArch() == llvm::Triple::mips64el)
111    CmdArgs.push_back("-EL");
112
113  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_shared)) {
114    CmdArgs.push_back("-e");
115    CmdArgs.push_back("__start");
116  }
117
118  CmdArgs.push_back("--eh-frame-hdr");
119  if (Args.hasArg(options::OPT_static)) {
120    CmdArgs.push_back("-Bstatic");
121  } else {
122    if (Args.hasArg(options::OPT_rdynamic))
123      CmdArgs.push_back("-export-dynamic");
124    CmdArgs.push_back("-Bdynamic");
125    if (Args.hasArg(options::OPT_shared)) {
126      CmdArgs.push_back("-shared");
127    } else {
128      CmdArgs.push_back("-dynamic-linker");
129      CmdArgs.push_back("/usr/libexec/ld.so");
130    }
131  }
132
133  if (Args.hasArg(options::OPT_pie))
134    CmdArgs.push_back("-pie");
135  if (Args.hasArg(options::OPT_nopie) || Args.hasArg(options::OPT_pg))
136    CmdArgs.push_back("-nopie");
137
138  if (Output.isFilename()) {
139    CmdArgs.push_back("-o");
140    CmdArgs.push_back(Output.getFilename());
141  } else {
142    assert(Output.isNothing() && "Invalid output.");
143  }
144
145  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
146    const char *crt0 = nullptr;
147    const char *crtbegin = nullptr;
148    if (!Args.hasArg(options::OPT_shared)) {
149      if (Args.hasArg(options::OPT_pg))
150        crt0 = "gcrt0.o";
151      else if (Args.hasArg(options::OPT_static) &&
152               !Args.hasArg(options::OPT_nopie))
153        crt0 = "rcrt0.o";
154      else
155        crt0 = "crt0.o";
156      crtbegin = "crtbegin.o";
157    } else {
158      crtbegin = "crtbeginS.o";
159    }
160
161    if (crt0)
162      CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt0)));
163    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin)));
164  }
165
166  Args.AddAllArgs(CmdArgs, options::OPT_L);
167  ToolChain.AddFilePathLibArgs(Args, CmdArgs);
168  Args.AddAllArgs(CmdArgs, {options::OPT_T_Group, options::OPT_e,
169                            options::OPT_s, options::OPT_t,
170                            options::OPT_Z_Flag, options::OPT_r});
171
172  bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs);
173  bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs);
174  AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
175
176  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
177    if (D.CCCIsCXX()) {
178      if (ToolChain.ShouldLinkCXXStdlib(Args))
179        ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
180      if (Args.hasArg(options::OPT_pg))
181        CmdArgs.push_back("-lm_p");
182      else
183        CmdArgs.push_back("-lm");
184    }
185    if (NeedsSanitizerDeps) {
186      CmdArgs.push_back(ToolChain.getCompilerRTArgString(Args, "builtins"));
187      linkSanitizerRuntimeDeps(ToolChain, CmdArgs);
188    }
189    if (NeedsXRayDeps) {
190      CmdArgs.push_back(ToolChain.getCompilerRTArgString(Args, "builtins"));
191      linkXRayRuntimeDeps(ToolChain, CmdArgs);
192    }
193    // FIXME: For some reason GCC passes -lgcc before adding
194    // the default system libraries. Just mimic this for now.
195    CmdArgs.push_back("-lcompiler_rt");
196
197    if (Args.hasArg(options::OPT_pthread)) {
198      if (!Args.hasArg(options::OPT_shared) && Args.hasArg(options::OPT_pg))
199        CmdArgs.push_back("-lpthread_p");
200      else
201        CmdArgs.push_back("-lpthread");
202    }
203
204    if (!Args.hasArg(options::OPT_shared)) {
205      if (Args.hasArg(options::OPT_pg))
206        CmdArgs.push_back("-lc_p");
207      else
208        CmdArgs.push_back("-lc");
209    }
210
211    CmdArgs.push_back("-lcompiler_rt");
212  }
213
214  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
215    const char *crtend = nullptr;
216    if (!Args.hasArg(options::OPT_shared))
217      crtend = "crtend.o";
218    else
219      crtend = "crtendS.o";
220
221    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend)));
222  }
223
224  const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
225  C.addCommand(std::make_unique<Command>(JA, *this,
226                                         ResponseFileSupport::AtFileCurCP(),
227                                         Exec, CmdArgs, Inputs, Output));
228}
229
230SanitizerMask OpenBSD::getSupportedSanitizers() const {
231  const bool IsX86 = getTriple().getArch() == llvm::Triple::x86;
232  const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64;
233
234  // For future use, only UBsan at the moment
235  SanitizerMask Res = ToolChain::getSupportedSanitizers();
236
237  if (IsX86 || IsX86_64) {
238    Res |= SanitizerKind::Vptr;
239    Res |= SanitizerKind::Fuzzer;
240    Res |= SanitizerKind::FuzzerNoLink;
241  }
242
243  return Res;
244}
245
246/// OpenBSD - OpenBSD tool chain which can call as(1) and ld(1) directly.
247
248OpenBSD::OpenBSD(const Driver &D, const llvm::Triple &Triple,
249                 const ArgList &Args)
250    : Generic_ELF(D, Triple, Args) {
251  getFilePaths().push_back(getDriver().SysRoot + "/usr/lib");
252}
253
254void OpenBSD::AddClangSystemIncludeArgs(
255    const llvm::opt::ArgList &DriverArgs,
256    llvm::opt::ArgStringList &CC1Args) const {
257  const Driver &D = getDriver();
258
259  if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc))
260    return;
261
262  if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
263    SmallString<128> Dir(D.ResourceDir);
264    llvm::sys::path::append(Dir, "include");
265    addSystemInclude(DriverArgs, CC1Args, Dir.str());
266  }
267
268  if (DriverArgs.hasArg(options::OPT_nostdlibinc))
269    return;
270
271  // Check for configure-time C include directories.
272  StringRef CIncludeDirs(C_INCLUDE_DIRS);
273  if (CIncludeDirs != "") {
274    SmallVector<StringRef, 5> dirs;
275    CIncludeDirs.split(dirs, ":");
276    for (StringRef dir : dirs) {
277      StringRef Prefix =
278          llvm::sys::path::is_absolute(dir) ? StringRef(D.SysRoot) : "";
279      addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir);
280    }
281    return;
282  }
283
284  addExternCSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/usr/include");
285}
286
287void OpenBSD::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
288                                    llvm::opt::ArgStringList &CC1Args) const {
289  addSystemInclude(DriverArgs, CC1Args,
290                   getDriver().SysRoot + "/usr/include/c++/v1");
291}
292
293void OpenBSD::AddCXXStdlibLibArgs(const ArgList &Args,
294                                  ArgStringList &CmdArgs) const {
295  bool Profiling = Args.hasArg(options::OPT_pg);
296
297  CmdArgs.push_back(Profiling ? "-lc++_p" : "-lc++");
298  CmdArgs.push_back(Profiling ? "-lc++abi_p" : "-lc++abi");
299  CmdArgs.push_back(Profiling ? "-lpthread_p" : "-lpthread");
300}
301
302std::string OpenBSD::getCompilerRT(const ArgList &Args,
303                                   StringRef Component,
304                                   FileType Type) const {
305  SmallString<128> Path(getDriver().SysRoot);
306  llvm::sys::path::append(Path, "/usr/lib/libcompiler_rt.a");
307  return std::string(Path.str());
308}
309
310Tool *OpenBSD::buildAssembler() const {
311  return new tools::openbsd::Assembler(*this);
312}
313
314Tool *OpenBSD::buildLinker() const { return new tools::openbsd::Linker(*this); }
315
316bool OpenBSD::HasNativeLLVMSupport() const { return true; }
317