1//===--- Solaris.cpp - Solaris 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 "Solaris.h"
10#include "Gnu.h"
11#include "clang/Basic/LangStandard.h"
12#include "clang/Config/config.h"
13#include "clang/Driver/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 "clang/Driver/ToolChain.h"
19#include "llvm/ADT/StringSwitch.h"
20#include "llvm/Option/ArgList.h"
21#include "llvm/Support/FileSystem.h"
22#include "llvm/Support/Path.h"
23
24using namespace clang::driver;
25using namespace clang::driver::tools;
26using namespace clang::driver::toolchains;
27using namespace clang;
28using namespace llvm::opt;
29
30void solaris::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
31 const InputInfo &Output,
32 const InputInfoList &Inputs,
33 const ArgList &Args,
34 const char *LinkingOutput) const {
35 // Just call the Gnu version, which enforces gas on Solaris.
36 gnutools::Assembler::ConstructJob(C, JA, Output, Inputs, TCArgs: Args, LinkingOutput);
37}
38
39bool solaris::isLinkerGnuLd(const ToolChain &TC, const ArgList &Args) {
40 // Only used if targetting Solaris.
41 const Arg *A = Args.getLastArg(options::OPT_fuse_ld_EQ);
42 StringRef UseLinker = A ? A->getValue() : CLANG_DEFAULT_LINKER;
43 return UseLinker == "bfd" || UseLinker == "gld";
44}
45
46static bool getPIE(const ArgList &Args, const ToolChain &TC) {
47 if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_static) ||
48 Args.hasArg(options::OPT_r))
49 return false;
50
51 return Args.hasFlag(options::OPT_pie, options::OPT_no_pie,
52 TC.isPIEDefault(Args));
53}
54
55// FIXME: Need to handle CLANG_DEFAULT_LINKER here?
56std::string solaris::Linker::getLinkerPath(const ArgList &Args) const {
57 const ToolChain &ToolChain = getToolChain();
58 if (const Arg *A = Args.getLastArg(options::OPT_fuse_ld_EQ)) {
59 StringRef UseLinker = A->getValue();
60 if (!UseLinker.empty()) {
61 if (llvm::sys::path::is_absolute(path: UseLinker) &&
62 llvm::sys::fs::can_execute(Path: UseLinker))
63 return std::string(UseLinker);
64
65 // Accept 'bfd' and 'gld' as aliases for the GNU linker.
66 if (UseLinker == "bfd" || UseLinker == "gld")
67 // FIXME: Could also use /usr/bin/gld here.
68 return "/usr/gnu/bin/ld";
69
70 // Accept 'ld' as alias for the default linker
71 if (UseLinker != "ld")
72 ToolChain.getDriver().Diag(diag::DiagID: err_drv_invalid_linker_name)
73 << A->getAsString(Args);
74 }
75 }
76
77 // getDefaultLinker() always returns an absolute path.
78 return ToolChain.getDefaultLinker();
79}
80
81void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA,
82 const InputInfo &Output,
83 const InputInfoList &Inputs,
84 const ArgList &Args,
85 const char *LinkingOutput) const {
86 const auto &ToolChain = static_cast<const Solaris &>(getToolChain());
87 const Driver &D = ToolChain.getDriver();
88 const llvm::Triple::ArchType Arch = ToolChain.getArch();
89 const bool IsPIE = getPIE(Args, TC: ToolChain);
90 const bool LinkerIsGnuLd = isLinkerGnuLd(TC: ToolChain, Args);
91 ArgStringList CmdArgs;
92
93 // Demangle C++ names in errors. GNU ld already defaults to --demangle.
94 if (!LinkerIsGnuLd)
95 CmdArgs.push_back(Elt: "-C");
96
97 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_shared,
98 options::OPT_r)) {
99 CmdArgs.push_back(Elt: "-e");
100 CmdArgs.push_back(Elt: "_start");
101 }
102
103 if (IsPIE) {
104 if (LinkerIsGnuLd) {
105 CmdArgs.push_back(Elt: "-pie");
106 } else {
107 CmdArgs.push_back(Elt: "-z");
108 CmdArgs.push_back(Elt: "type=pie");
109 }
110 }
111
112 if (Args.hasArg(options::OPT_static)) {
113 CmdArgs.push_back(Elt: "-Bstatic");
114 CmdArgs.push_back(Elt: "-dn");
115 } else {
116 if (!Args.hasArg(options::OPT_r) && Args.hasArg(options::OPT_shared))
117 CmdArgs.push_back(Elt: "-shared");
118
119 // libpthread has been folded into libc since Solaris 10, no need to do
120 // anything for pthreads. Claim argument to avoid warning.
121 Args.ClaimAllArgs(options::OPT_pthread);
122 Args.ClaimAllArgs(options::OPT_pthreads);
123 }
124
125 if (LinkerIsGnuLd) {
126 // Set the correct linker emulation for 32- and 64-bit Solaris.
127 switch (Arch) {
128 case llvm::Triple::x86:
129 CmdArgs.push_back(Elt: "-m");
130 CmdArgs.push_back(Elt: "elf_i386_sol2");
131 break;
132 case llvm::Triple::x86_64:
133 CmdArgs.push_back(Elt: "-m");
134 CmdArgs.push_back(Elt: "elf_x86_64_sol2");
135 break;
136 case llvm::Triple::sparc:
137 CmdArgs.push_back(Elt: "-m");
138 CmdArgs.push_back(Elt: "elf32_sparc_sol2");
139 break;
140 case llvm::Triple::sparcv9:
141 CmdArgs.push_back(Elt: "-m");
142 CmdArgs.push_back(Elt: "elf64_sparc_sol2");
143 break;
144 default:
145 break;
146 }
147
148 if (Args.hasArg(options::OPT_rdynamic))
149 CmdArgs.push_back(Elt: "-export-dynamic");
150
151 CmdArgs.push_back(Elt: "--eh-frame-hdr");
152 } else {
153 // -rdynamic is a no-op with Solaris ld. Claim argument to avoid warning.
154 Args.ClaimAllArgs(options::OPT_rdynamic);
155 }
156
157 assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
158 if (Output.isFilename()) {
159 CmdArgs.push_back(Elt: "-o");
160 CmdArgs.push_back(Elt: Output.getFilename());
161 }
162
163 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,
164 options::OPT_r)) {
165 if (!Args.hasArg(options::OPT_shared))
166 CmdArgs.push_back(Elt: Args.MakeArgString(Str: ToolChain.GetFilePath(Name: "crt1.o")));
167
168 CmdArgs.push_back(Elt: Args.MakeArgString(Str: ToolChain.GetFilePath(Name: "crti.o")));
169
170 const Arg *Std = Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi);
171 bool HaveAnsi = false;
172 const LangStandard *LangStd = nullptr;
173 if (Std) {
174 HaveAnsi = Std->getOption().matches(options::ID: OPT_ansi);
175 if (!HaveAnsi)
176 LangStd = LangStandard::getLangStandardForName(Name: Std->getValue());
177 }
178
179 const char *values_X = "values-Xa.o";
180 // Use values-Xc.o for -ansi, -std=c*, -std=iso9899:199409.
181 if (HaveAnsi || (LangStd && !LangStd->isGNUMode()))
182 values_X = "values-Xc.o";
183 CmdArgs.push_back(Elt: Args.MakeArgString(Str: ToolChain.GetFilePath(Name: values_X)));
184
185 const char *values_xpg = "values-xpg6.o";
186 // Use values-xpg4.o for -std=c90, -std=gnu90, -std=iso9899:199409.
187 if (LangStd && LangStd->getLanguage() == Language::C && !LangStd->isC99())
188 values_xpg = "values-xpg4.o";
189 CmdArgs.push_back(Elt: Args.MakeArgString(Str: ToolChain.GetFilePath(Name: values_xpg)));
190
191 const char *crtbegin = nullptr;
192 if (Args.hasArg(options::OPT_shared) || IsPIE)
193 crtbegin = "crtbeginS.o";
194 else
195 crtbegin = "crtbegin.o";
196 CmdArgs.push_back(Elt: Args.MakeArgString(Str: ToolChain.GetFilePath(Name: crtbegin)));
197 // Add crtfastmath.o if available and fast math is enabled.
198 ToolChain.addFastMathRuntimeIfAvailable(Args, CmdArgs);
199 }
200
201 ToolChain.AddFilePathLibArgs(Args, CmdArgs);
202
203 Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group});
204
205 bool NeedsSanitizerDeps = addSanitizerRuntimes(TC: ToolChain, Args, CmdArgs);
206 AddLinkerInputs(TC: ToolChain, Inputs, Args, CmdArgs, JA);
207
208 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs,
209 options::OPT_r)) {
210 // Use the static OpenMP runtime with -static-openmp
211 bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) &&
212 !Args.hasArg(options::OPT_static);
213 addOpenMPRuntime(C, CmdArgs, TC: ToolChain, Args, ForceStaticHostRuntime: StaticOpenMP);
214
215 if (D.CCCIsCXX()) {
216 if (ToolChain.ShouldLinkCXXStdlib(Args))
217 ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
218 CmdArgs.push_back(Elt: "-lm");
219 }
220 // Silence warnings when linking C code with a C++ '-stdlib' argument.
221 Args.ClaimAllArgs(options::OPT_stdlib_EQ);
222 // Additional linker set-up and flags for Fortran. This is required in order
223 // to generate executables. As Fortran runtime depends on the C runtime,
224 // these dependencies need to be listed before the C runtime below.
225 if (D.IsFlangMode() &&
226 !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
227 ToolChain.addFortranRuntimeLibraryPath(Args, CmdArgs);
228 ToolChain.addFortranRuntimeLibs(Args, CmdArgs);
229 CmdArgs.push_back(Elt: "-lm");
230 }
231 if (Args.hasArg(options::OPT_fstack_protector) ||
232 Args.hasArg(options::OPT_fstack_protector_strong) ||
233 Args.hasArg(options::OPT_fstack_protector_all)) {
234 // Explicitly link ssp libraries, not folded into Solaris libc.
235 CmdArgs.push_back(Elt: "-lssp_nonshared");
236 CmdArgs.push_back(Elt: "-lssp");
237 }
238 // LLVM support for atomics on 32-bit SPARC V8+ is incomplete, so
239 // forcibly link with libatomic as a workaround.
240 if (Arch == llvm::Triple::sparc) {
241 addAsNeededOption(TC: ToolChain, Args, CmdArgs, as_needed: true);
242 CmdArgs.push_back(Elt: "-latomic");
243 addAsNeededOption(TC: ToolChain, Args, CmdArgs, as_needed: false);
244 }
245
246 AddRunTimeLibs(TC: ToolChain, D, CmdArgs, Args);
247 CmdArgs.push_back(Elt: "-lc");
248
249 const SanitizerArgs &SA = ToolChain.getSanitizerArgs(JobArgs: Args);
250 if (NeedsSanitizerDeps) {
251 linkSanitizerRuntimeDeps(TC: ToolChain, Args, CmdArgs);
252
253 // Work around Solaris/amd64 ld bug when calling __tls_get_addr directly.
254 // However, ld -z relax=transtls is available since Solaris 11.2, but not
255 // in Illumos.
256 if (Arch == llvm::Triple::x86_64 &&
257 (SA.needsAsanRt() || SA.needsStatsRt() ||
258 (SA.needsUbsanRt() && !SA.requiresMinimalRuntime())) &&
259 !LinkerIsGnuLd) {
260 CmdArgs.push_back(Elt: "-z");
261 CmdArgs.push_back(Elt: "relax=transtls");
262 }
263 }
264 // Avoid AsanInitInternal cycle, Issue #64126.
265 if (SA.needsSharedRt() && SA.needsAsanRt()) {
266 CmdArgs.push_back(Elt: "-z");
267 CmdArgs.push_back(Elt: "now");
268 }
269 }
270
271 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,
272 options::OPT_r)) {
273 const char *crtend = nullptr;
274 if (Args.hasArg(options::OPT_shared) || IsPIE)
275 crtend = "crtendS.o";
276 else
277 crtend = "crtend.o";
278 CmdArgs.push_back(Elt: Args.MakeArgString(Str: ToolChain.GetFilePath(Name: crtend)));
279 CmdArgs.push_back(Elt: Args.MakeArgString(Str: ToolChain.GetFilePath(Name: "crtn.o")));
280 }
281
282 ToolChain.addProfileRTLibs(Args, CmdArgs);
283
284 const char *Exec = Args.MakeArgString(Str: getLinkerPath(Args));
285 C.addCommand(C: std::make_unique<Command>(args: JA, args: *this, args: ResponseFileSupport::None(),
286 args&: Exec, args&: CmdArgs, args: Inputs, args: Output));
287}
288
289static StringRef getSolarisLibSuffix(const llvm::Triple &Triple) {
290 switch (Triple.getArch()) {
291 case llvm::Triple::x86:
292 case llvm::Triple::sparc:
293 default:
294 break;
295 case llvm::Triple::x86_64:
296 return "/amd64";
297 case llvm::Triple::sparcv9:
298 return "/sparcv9";
299 }
300 return "";
301}
302
303/// Solaris - Solaris tool chain which can call as(1) and ld(1) directly.
304
305Solaris::Solaris(const Driver &D, const llvm::Triple &Triple,
306 const ArgList &Args)
307 : Generic_ELF(D, Triple, Args) {
308
309 GCCInstallation.init(TargetTriple: Triple, Args);
310
311 StringRef LibSuffix = getSolarisLibSuffix(Triple);
312 path_list &Paths = getFilePaths();
313 if (GCCInstallation.isValid()) {
314 // On Solaris gcc uses both an architecture-specific path with triple in it
315 // as well as a more generic lib path (+arch suffix).
316 addPathIfExists(D,
317 Path: GCCInstallation.getInstallPath() +
318 GCCInstallation.getMultilib().gccSuffix(),
319 Paths);
320 addPathIfExists(D, Path: GCCInstallation.getParentLibPath() + LibSuffix, Paths);
321 }
322
323 // If we are currently running Clang inside of the requested system root,
324 // add its parent library path to those searched.
325 if (StringRef(D.Dir).starts_with(Prefix: D.SysRoot))
326 addPathIfExists(D, Path: D.Dir + "/../lib", Paths);
327
328 addPathIfExists(D, Path: D.SysRoot + "/usr/lib" + LibSuffix, Paths);
329}
330
331SanitizerMask Solaris::getSupportedSanitizers() const {
332 const bool IsSparc = getTriple().getArch() == llvm::Triple::sparc;
333 const bool IsX86 = getTriple().getArch() == llvm::Triple::x86;
334 SanitizerMask Res = ToolChain::getSupportedSanitizers();
335 // FIXME: Omit SparcV9 and X86_64 until 64-bit support is figured out.
336 if (IsSparc || IsX86) {
337 Res |= SanitizerKind::Address;
338 Res |= SanitizerKind::PointerCompare;
339 Res |= SanitizerKind::PointerSubtract;
340 }
341 Res |= SanitizerKind::SafeStack;
342 Res |= SanitizerKind::Vptr;
343 return Res;
344}
345
346const char *Solaris::getDefaultLinker() const {
347 // FIXME: Only handle Solaris ld and GNU ld here.
348 return llvm::StringSwitch<const char *>(CLANG_DEFAULT_LINKER)
349 .Cases(S0: "bfd", S1: "gld", Value: "/usr/gnu/bin/ld")
350 .Default(Value: "/usr/bin/ld");
351}
352
353Tool *Solaris::buildAssembler() const {
354 return new tools::solaris::Assembler(*this);
355}
356
357Tool *Solaris::buildLinker() const { return new tools::solaris::Linker(*this); }
358
359void Solaris::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
360 ArgStringList &CC1Args) const {
361 const Driver &D = getDriver();
362
363 if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc))
364 return;
365
366 if (!DriverArgs.hasArg(options::OPT_nostdlibinc))
367 addSystemInclude(DriverArgs, CC1Args, Path: D.SysRoot + "/usr/local/include");
368
369 if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
370 SmallString<128> P(D.ResourceDir);
371 llvm::sys::path::append(path&: P, a: "include");
372 addSystemInclude(DriverArgs, CC1Args, Path: P);
373 }
374
375 if (DriverArgs.hasArg(options::OPT_nostdlibinc))
376 return;
377
378 // Check for configure-time C include directories.
379 StringRef CIncludeDirs(C_INCLUDE_DIRS);
380 if (CIncludeDirs != "") {
381 SmallVector<StringRef, 5> dirs;
382 CIncludeDirs.split(A&: dirs, Separator: ":");
383 for (StringRef dir : dirs) {
384 StringRef Prefix =
385 llvm::sys::path::is_absolute(path: dir) ? "" : StringRef(D.SysRoot);
386 addExternCSystemInclude(DriverArgs, CC1Args, Path: Prefix + dir);
387 }
388 return;
389 }
390
391 // Add include directories specific to the selected multilib set and multilib.
392 if (GCCInstallation.isValid()) {
393 const MultilibSet::IncludeDirsFunc &Callback =
394 Multilibs.includeDirsCallback();
395 if (Callback) {
396 for (const auto &Path : Callback(GCCInstallation.getMultilib()))
397 addExternCSystemIncludeIfExists(
398 DriverArgs, CC1Args, Path: GCCInstallation.getInstallPath() + Path);
399 }
400 }
401
402 addExternCSystemInclude(DriverArgs, CC1Args, Path: D.SysRoot + "/usr/include");
403}
404
405void Solaris::addLibStdCxxIncludePaths(
406 const llvm::opt::ArgList &DriverArgs,
407 llvm::opt::ArgStringList &CC1Args) const {
408 // We need a detected GCC installation on Solaris (similar to Linux)
409 // to provide libstdc++'s headers.
410 if (!GCCInstallation.isValid())
411 return;
412
413 // By default, look for the C++ headers in an include directory adjacent to
414 // the lib directory of the GCC installation.
415 // On Solaris this usually looks like /usr/gcc/X.Y/include/c++/X.Y.Z
416 StringRef LibDir = GCCInstallation.getParentLibPath();
417 StringRef TripleStr = GCCInstallation.getTriple().str();
418 const Multilib &Multilib = GCCInstallation.getMultilib();
419 const GCCVersion &Version = GCCInstallation.getVersion();
420
421 // The primary search for libstdc++ supports multiarch variants.
422 addLibStdCXXIncludePaths(IncludeDir: LibDir.str() + "/../include/c++/" + Version.Text,
423 Triple: TripleStr, IncludeSuffix: Multilib.includeSuffix(), DriverArgs,
424 CC1Args);
425}
426

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of clang/lib/Driver/ToolChains/Solaris.cpp