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