Coverage Report

Created: 2024-01-17 10:31

/src/llvm-project/clang/lib/Driver/ToolChains/OpenBSD.cpp
Line
Count
Source (jump to first uncovered line)
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/ARM.h"
11
#include "Arch/Mips.h"
12
#include "Arch/Sparc.h"
13
#include "CommonArgs.h"
14
#include "clang/Config/config.h"
15
#include "clang/Driver/Compilation.h"
16
#include "clang/Driver/Options.h"
17
#include "clang/Driver/SanitizerArgs.h"
18
#include "llvm/Option/ArgList.h"
19
#include "llvm/Support/Path.h"
20
#include "llvm/Support/VirtualFileSystem.h"
21
22
using namespace clang::driver;
23
using namespace clang::driver::tools;
24
using namespace clang::driver::toolchains;
25
using namespace clang;
26
using namespace llvm::opt;
27
28
void openbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
29
                                      const InputInfo &Output,
30
                                      const InputInfoList &Inputs,
31
                                      const ArgList &Args,
32
0
                                      const char *LinkingOutput) const {
33
0
  const auto &ToolChain = static_cast<const OpenBSD &>(getToolChain());
34
0
  const Driver &D = ToolChain.getDriver();
35
0
  const llvm::Triple &Triple = ToolChain.getTriple();
36
0
  ArgStringList CmdArgs;
37
38
0
  claimNoWarnArgs(Args);
39
40
0
  switch (ToolChain.getArch()) {
41
0
  case llvm::Triple::x86:
42
    // When building 32-bit code on OpenBSD/amd64, we have to explicitly
43
    // instruct as in the base system to assemble 32-bit code.
44
0
    CmdArgs.push_back("--32");
45
0
    break;
46
47
0
  case llvm::Triple::arm: {
48
0
    StringRef MArch, MCPU;
49
0
    arm::getARMArchCPUFromArgs(Args, MArch, MCPU, /*FromAs*/ true);
50
0
    std::string Arch = arm::getARMTargetCPU(MCPU, MArch, Triple);
51
0
    CmdArgs.push_back(Args.MakeArgString("-mcpu=" + Arch));
52
0
    break;
53
0
  }
54
55
0
  case llvm::Triple::ppc:
56
0
    CmdArgs.push_back("-mppc");
57
0
    CmdArgs.push_back("-many");
58
0
    break;
59
60
0
  case llvm::Triple::sparcv9: {
61
0
    CmdArgs.push_back("-64");
62
0
    std::string CPU = getCPUName(D, Args, Triple);
63
0
    CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, Triple));
64
0
    AddAssemblerKPIC(ToolChain, Args, CmdArgs);
65
0
    break;
66
0
  }
67
68
0
  case llvm::Triple::mips64:
69
0
  case llvm::Triple::mips64el: {
70
0
    StringRef CPUName;
71
0
    StringRef ABIName;
72
0
    mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName);
73
74
0
    CmdArgs.push_back("-march");
75
0
    CmdArgs.push_back(CPUName.data());
76
77
0
    CmdArgs.push_back("-mabi");
78
0
    CmdArgs.push_back(mips::getGnuCompatibleMipsABIName(ABIName).data());
79
80
0
    if (Triple.isLittleEndian())
81
0
      CmdArgs.push_back("-EL");
82
0
    else
83
0
      CmdArgs.push_back("-EB");
84
85
0
    AddAssemblerKPIC(ToolChain, Args, CmdArgs);
86
0
    break;
87
0
  }
88
89
0
  default:
90
0
    break;
91
0
  }
92
93
0
  Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
94
95
0
  CmdArgs.push_back("-o");
96
0
  CmdArgs.push_back(Output.getFilename());
97
98
0
  for (const auto &II : Inputs)
99
0
    CmdArgs.push_back(II.getFilename());
100
101
0
  const char *Exec = Args.MakeArgString(ToolChain.GetProgramPath("as"));
102
0
  C.addCommand(std::make_unique<Command>(JA, *this,
103
0
                                         ResponseFileSupport::AtFileCurCP(),
104
0
                                         Exec, CmdArgs, Inputs, Output));
105
0
}
106
107
void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
108
                                   const InputInfo &Output,
109
                                   const InputInfoList &Inputs,
110
                                   const ArgList &Args,
111
0
                                   const char *LinkingOutput) const {
112
0
  const auto &ToolChain = static_cast<const OpenBSD &>(getToolChain());
113
0
  const Driver &D = ToolChain.getDriver();
114
0
  const llvm::Triple::ArchType Arch = ToolChain.getArch();
115
0
  const bool Static = Args.hasArg(options::OPT_static);
116
0
  const bool Shared = Args.hasArg(options::OPT_shared);
117
0
  const bool Profiling = Args.hasArg(options::OPT_pg);
118
0
  const bool Pie = Args.hasArg(options::OPT_pie);
119
0
  const bool Nopie = Args.hasArg(options::OPT_no_pie, options::OPT_nopie);
120
0
  const bool Relocatable = Args.hasArg(options::OPT_r);
121
0
  ArgStringList CmdArgs;
122
123
  // Silence warning for "clang -g foo.o -o foo"
124
0
  Args.ClaimAllArgs(options::OPT_g_Group);
125
  // and "clang -emit-llvm foo.o -o foo"
126
0
  Args.ClaimAllArgs(options::OPT_emit_llvm);
127
  // and for "clang -w foo.o -o foo". Other warning options are already
128
  // handled somewhere else.
129
0
  Args.ClaimAllArgs(options::OPT_w);
130
131
0
  if (!D.SysRoot.empty())
132
0
    CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
133
134
0
  if (Arch == llvm::Triple::mips64)
135
0
    CmdArgs.push_back("-EB");
136
0
  else if (Arch == llvm::Triple::mips64el)
137
0
    CmdArgs.push_back("-EL");
138
139
0
  if (!Args.hasArg(options::OPT_nostdlib) && !Shared && !Relocatable) {
140
0
    CmdArgs.push_back("-e");
141
0
    CmdArgs.push_back("__start");
142
0
  }
143
144
0
  CmdArgs.push_back("--eh-frame-hdr");
145
0
  if (Static) {
146
0
    CmdArgs.push_back("-Bstatic");
147
0
  } else {
148
0
    if (Args.hasArg(options::OPT_rdynamic))
149
0
      CmdArgs.push_back("-export-dynamic");
150
0
    if (Shared) {
151
0
      CmdArgs.push_back("-shared");
152
0
    } else if (!Relocatable) {
153
0
      CmdArgs.push_back("-dynamic-linker");
154
0
      CmdArgs.push_back("/usr/libexec/ld.so");
155
0
    }
156
0
  }
157
158
0
  if (Pie)
159
0
    CmdArgs.push_back("-pie");
160
0
  if (Nopie || Profiling)
161
0
    CmdArgs.push_back("-nopie");
162
163
0
  if (Arch == llvm::Triple::riscv64)
164
0
    CmdArgs.push_back("-X");
165
166
0
  assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
167
0
  if (Output.isFilename()) {
168
0
    CmdArgs.push_back("-o");
169
0
    CmdArgs.push_back(Output.getFilename());
170
0
  }
171
172
0
  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,
173
0
                   options::OPT_r)) {
174
0
    const char *crt0 = nullptr;
175
0
    const char *crtbegin = nullptr;
176
0
    if (!Shared) {
177
0
      if (Profiling)
178
0
        crt0 = "gcrt0.o";
179
0
      else if (Static && !Nopie)
180
0
        crt0 = "rcrt0.o";
181
0
      else
182
0
        crt0 = "crt0.o";
183
0
      crtbegin = "crtbegin.o";
184
0
    } else {
185
0
      crtbegin = "crtbeginS.o";
186
0
    }
187
188
0
    if (crt0)
189
0
      CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt0)));
190
0
    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin)));
191
0
  }
192
193
0
  Args.AddAllArgs(CmdArgs, options::OPT_L);
194
0
  ToolChain.AddFilePathLibArgs(Args, CmdArgs);
195
0
  Args.addAllArgs(CmdArgs, {options::OPT_T_Group, options::OPT_s,
196
0
                            options::OPT_t, options::OPT_r});
197
198
0
  if (D.isUsingLTO()) {
199
0
    assert(!Inputs.empty() && "Must have at least one input.");
200
    // Find the first filename InputInfo object.
201
0
    auto Input = llvm::find_if(
202
0
        Inputs, [](const InputInfo &II) -> bool { return II.isFilename(); });
203
0
    if (Input == Inputs.end())
204
      // For a very rare case, all of the inputs to the linker are
205
      // InputArg. If that happens, just use the first InputInfo.
206
0
      Input = Inputs.begin();
207
208
0
    addLTOOptions(ToolChain, Args, CmdArgs, Output, *Input,
209
0
                  D.getLTOMode() == LTOK_Thin);
210
0
  }
211
212
0
  bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs);
213
0
  bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs);
214
0
  AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
215
216
0
  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs,
217
0
                   options::OPT_r)) {
218
    // Use the static OpenMP runtime with -static-openmp
219
0
    bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && !Static;
220
0
    addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP);
221
222
0
    if (D.CCCIsCXX()) {
223
0
      if (ToolChain.ShouldLinkCXXStdlib(Args))
224
0
        ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
225
0
      if (Profiling)
226
0
        CmdArgs.push_back("-lm_p");
227
0
      else
228
0
        CmdArgs.push_back("-lm");
229
0
    }
230
231
    // Silence warnings when linking C code with a C++ '-stdlib' argument.
232
0
    Args.ClaimAllArgs(options::OPT_stdlib_EQ);
233
234
    // Additional linker set-up and flags for Fortran. This is required in order
235
    // to generate executables. As Fortran runtime depends on the C runtime,
236
    // these dependencies need to be listed before the C runtime below (i.e.
237
    // AddRunTimeLibs).
238
0
    if (D.IsFlangMode()) {
239
0
      addFortranRuntimeLibraryPath(ToolChain, Args, CmdArgs);
240
0
      addFortranRuntimeLibs(ToolChain, Args, CmdArgs);
241
0
      if (Profiling)
242
0
        CmdArgs.push_back("-lm_p");
243
0
      else
244
0
        CmdArgs.push_back("-lm");
245
0
    }
246
247
0
    if (NeedsSanitizerDeps) {
248
0
      CmdArgs.push_back(ToolChain.getCompilerRTArgString(Args, "builtins"));
249
0
      linkSanitizerRuntimeDeps(ToolChain, Args, CmdArgs);
250
0
    }
251
0
    if (NeedsXRayDeps) {
252
0
      CmdArgs.push_back(ToolChain.getCompilerRTArgString(Args, "builtins"));
253
0
      linkXRayRuntimeDeps(ToolChain, Args, CmdArgs);
254
0
    }
255
    // FIXME: For some reason GCC passes -lgcc before adding
256
    // the default system libraries. Just mimic this for now.
257
0
    CmdArgs.push_back("-lcompiler_rt");
258
259
0
    if (Args.hasArg(options::OPT_pthread)) {
260
0
      if (!Shared && Profiling)
261
0
        CmdArgs.push_back("-lpthread_p");
262
0
      else
263
0
        CmdArgs.push_back("-lpthread");
264
0
    }
265
266
0
    if (!Shared) {
267
0
      if (Profiling)
268
0
        CmdArgs.push_back("-lc_p");
269
0
      else
270
0
        CmdArgs.push_back("-lc");
271
0
    }
272
273
0
    CmdArgs.push_back("-lcompiler_rt");
274
0
  }
275
276
0
  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,
277
0
                   options::OPT_r)) {
278
0
    const char *crtend = nullptr;
279
0
    if (!Shared)
280
0
      crtend = "crtend.o";
281
0
    else
282
0
      crtend = "crtendS.o";
283
284
0
    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend)));
285
0
  }
286
287
0
  ToolChain.addProfileRTLibs(Args, CmdArgs);
288
289
0
  const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
290
0
  C.addCommand(std::make_unique<Command>(JA, *this,
291
0
                                         ResponseFileSupport::AtFileCurCP(),
292
0
                                         Exec, CmdArgs, Inputs, Output));
293
0
}
294
295
0
SanitizerMask OpenBSD::getSupportedSanitizers() const {
296
0
  const bool IsX86 = getTriple().getArch() == llvm::Triple::x86;
297
0
  const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64;
298
0
  SanitizerMask Res = ToolChain::getSupportedSanitizers();
299
0
  if (IsX86 || IsX86_64) {
300
0
    Res |= SanitizerKind::Vptr;
301
0
    Res |= SanitizerKind::Fuzzer;
302
0
    Res |= SanitizerKind::FuzzerNoLink;
303
0
  }
304
0
  if (IsX86_64) {
305
0
    Res |= SanitizerKind::KernelAddress;
306
0
  }
307
0
  return Res;
308
0
}
309
310
/// OpenBSD - OpenBSD tool chain which can call as(1) and ld(1) directly.
311
312
OpenBSD::OpenBSD(const Driver &D, const llvm::Triple &Triple,
313
                 const ArgList &Args)
314
0
    : Generic_ELF(D, Triple, Args) {
315
0
  getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib"));
316
0
}
317
318
void OpenBSD::AddClangSystemIncludeArgs(
319
    const llvm::opt::ArgList &DriverArgs,
320
0
    llvm::opt::ArgStringList &CC1Args) const {
321
0
  const Driver &D = getDriver();
322
323
0
  if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc))
324
0
    return;
325
326
0
  if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
327
0
    SmallString<128> Dir(D.ResourceDir);
328
0
    llvm::sys::path::append(Dir, "include");
329
0
    addSystemInclude(DriverArgs, CC1Args, Dir.str());
330
0
  }
331
332
0
  if (DriverArgs.hasArg(options::OPT_nostdlibinc))
333
0
    return;
334
335
  // Check for configure-time C include directories.
336
0
  StringRef CIncludeDirs(C_INCLUDE_DIRS);
337
0
  if (CIncludeDirs != "") {
338
0
    SmallVector<StringRef, 5> dirs;
339
0
    CIncludeDirs.split(dirs, ":");
340
0
    for (StringRef dir : dirs) {
341
0
      StringRef Prefix =
342
0
          llvm::sys::path::is_absolute(dir) ? StringRef(D.SysRoot) : "";
343
0
      addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir);
344
0
    }
345
0
    return;
346
0
  }
347
348
0
  addExternCSystemInclude(DriverArgs, CC1Args,
349
0
                          concat(D.SysRoot, "/usr/include"));
350
0
}
351
352
void OpenBSD::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
353
0
                                    llvm::opt::ArgStringList &CC1Args) const {
354
0
  addSystemInclude(DriverArgs, CC1Args,
355
0
                   concat(getDriver().SysRoot, "/usr/include/c++/v1"));
356
0
}
357
358
void OpenBSD::AddCXXStdlibLibArgs(const ArgList &Args,
359
0
                                  ArgStringList &CmdArgs) const {
360
0
  bool Profiling = Args.hasArg(options::OPT_pg);
361
362
0
  CmdArgs.push_back(Profiling ? "-lc++_p" : "-lc++");
363
0
  if (Args.hasArg(options::OPT_fexperimental_library))
364
0
    CmdArgs.push_back("-lc++experimental");
365
0
  CmdArgs.push_back(Profiling ? "-lc++abi_p" : "-lc++abi");
366
0
  CmdArgs.push_back(Profiling ? "-lpthread_p" : "-lpthread");
367
0
}
368
369
std::string OpenBSD::getCompilerRT(const ArgList &Args, StringRef Component,
370
0
                                   FileType Type) const {
371
0
  if (Component == "builtins") {
372
0
    SmallString<128> Path(getDriver().SysRoot);
373
0
    llvm::sys::path::append(Path, "/usr/lib/libcompiler_rt.a");
374
0
    return std::string(Path.str());
375
0
  }
376
0
  SmallString<128> P(getDriver().ResourceDir);
377
0
  std::string CRTBasename =
378
0
      buildCompilerRTBasename(Args, Component, Type, /*AddArch=*/false);
379
0
  llvm::sys::path::append(P, "lib", CRTBasename);
380
  // Checks if this is the base system case which uses a different location.
381
0
  if (getVFS().exists(P))
382
0
    return std::string(P.str());
383
0
  return ToolChain::getCompilerRT(Args, Component, Type);
384
0
}
385
386
0
Tool *OpenBSD::buildAssembler() const {
387
0
  return new tools::openbsd::Assembler(*this);
388
0
}
389
390
0
Tool *OpenBSD::buildLinker() const { return new tools::openbsd::Linker(*this); }
391
392
0
bool OpenBSD::HasNativeLLVMSupport() const { return true; }
393
394
ToolChain::UnwindTableLevel
395
0
OpenBSD::getDefaultUnwindTableLevel(const ArgList &Args) const {
396
0
  switch (getArch()) {
397
0
  case llvm::Triple::arm:
398
0
    return UnwindTableLevel::None;
399
0
  default:
400
0
    return UnwindTableLevel::Asynchronous;
401
0
  }
402
0
}