1//===---- Serenity.cpp - SerenityOS ToolChain Implementation ----*- 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 "Serenity.h"
10#include "clang/Config/config.h"
11#include "clang/Driver/CommonArgs.h"
12#include "clang/Driver/Compilation.h"
13#include "clang/Driver/Driver.h"
14#include "clang/Driver/SanitizerArgs.h"
15#include "clang/Options/Options.h"
16#include "llvm/Option/ArgList.h"
17#include "llvm/Support/VirtualFileSystem.h"
18#include <string>
19
20using namespace clang::driver;
21using namespace clang::driver::toolchains;
22using namespace clang;
23using namespace llvm::opt;
24
25void tools::serenity::Linker::ConstructJob(Compilation &C, const JobAction &JA,
26 const InputInfo &Output,
27 const InputInfoList &Inputs,
28 const ArgList &Args,
29 const char *LinkingOutput) const {
30 const auto &TC = static_cast<Generic_ELF const &>(getToolChain());
31 const auto &D = TC.getDriver();
32 const bool IsShared = Args.hasArg(Ids: options::OPT_shared);
33 const bool IsStatic =
34 Args.hasArg(Ids: options::OPT_static) && !Args.hasArg(Ids: options::OPT_static_pie);
35 const bool IsStaticPIE = Args.hasArg(Ids: options::OPT_static_pie);
36 ArgStringList CmdArgs;
37
38 if (!D.SysRoot.empty())
39 CmdArgs.push_back(Elt: Args.MakeArgString(Str: "--sysroot=" + D.SysRoot));
40
41 if (IsShared)
42 CmdArgs.push_back(Elt: "-shared");
43
44 if (IsStaticPIE) {
45 CmdArgs.push_back(Elt: "-static");
46 CmdArgs.push_back(Elt: "-pie");
47 CmdArgs.push_back(Elt: "--no-dynamic-linker");
48 CmdArgs.push_back(Elt: "-z");
49 CmdArgs.push_back(Elt: "text");
50 } else if (IsStatic) {
51 CmdArgs.push_back(Elt: "-static");
52 } else if (!Args.hasArg(Ids: options::OPT_r)) {
53 if (Args.hasArg(Ids: options::OPT_rdynamic))
54 CmdArgs.push_back(Elt: "-export-dynamic");
55 if (!IsShared) {
56 Arg *A = Args.getLastArg(Ids: options::OPT_pie, Ids: options::OPT_no_pie);
57 bool IsPIE =
58 A ? A->getOption().matches(ID: options::OPT_pie) : TC.isPIEDefault(Args);
59 if (IsPIE)
60 CmdArgs.push_back(Elt: "-pie");
61 CmdArgs.push_back(Elt: "-dynamic-linker");
62 CmdArgs.push_back(Elt: Args.MakeArgString(Str: TC.getDynamicLinker(Args)));
63 }
64 }
65
66 CmdArgs.push_back(Elt: "--eh-frame-hdr");
67
68 assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
69 if (Output.isFilename()) {
70 CmdArgs.push_back(Elt: "-o");
71 CmdArgs.push_back(Elt: Output.getFilename());
72 }
73
74 CmdArgs.push_back(Elt: "-z");
75 CmdArgs.push_back(Elt: "pack-relative-relocs");
76
77 bool HasNoStdLib = Args.hasArg(Ids: options::OPT_nostdlib, Ids: options::OPT_r);
78 bool HasNoStdLibXX = Args.hasArg(Ids: options::OPT_nostdlibxx);
79 bool HasNoLibC = Args.hasArg(Ids: options::OPT_nolibc);
80 bool HasNoStartFiles = Args.hasArg(Ids: options::OPT_nostartfiles);
81 bool HasNoDefaultLibs = Args.hasArg(Ids: options::OPT_nodefaultlibs);
82
83 bool ShouldLinkStartFiles = !HasNoStartFiles && !HasNoStdLib;
84 bool ShouldLinkCompilerRuntime = !HasNoDefaultLibs && !HasNoStdLib;
85 bool ShouldLinkLibC = !HasNoLibC && !HasNoStdLib && !HasNoDefaultLibs;
86 bool ShouldLinkLibCXX =
87 D.CCCIsCXX() && !HasNoStdLibXX && !HasNoStdLib && !HasNoDefaultLibs;
88
89 if (ShouldLinkStartFiles) {
90 if (!IsShared)
91 CmdArgs.push_back(Elt: Args.MakeArgString(Str: TC.GetFilePath(Name: "crt0.o")));
92
93 std::string crtbegin_path;
94 if (TC.GetRuntimeLibType(Args) == ToolChain::RLT_CompilerRT) {
95 std::string crtbegin =
96 TC.getCompilerRT(Args, Component: "crtbegin", Type: ToolChain::FT_Object);
97 if (TC.getVFS().exists(Path: crtbegin))
98 crtbegin_path = crtbegin;
99 }
100 if (crtbegin_path.empty())
101 crtbegin_path = TC.GetFilePath(Name: "crtbeginS.o");
102 CmdArgs.push_back(Elt: Args.MakeArgString(Str: crtbegin_path));
103 }
104
105 Args.addAllArgs(Output&: CmdArgs, Ids: {options::OPT_L, options::OPT_u});
106
107 TC.AddFilePathLibArgs(Args, CmdArgs);
108
109 if (auto LTO = TC.getLTOMode(Args); LTO != LTOK_None)
110 addLTOOptions(ToolChain: TC, Args, CmdArgs, Output, Inputs, IsThinLTO: LTO == LTOK_Thin);
111
112 Args.addAllArgs(Output&: CmdArgs, Ids: {options::OPT_T_Group, options::OPT_s,
113 options::OPT_t, options::OPT_r});
114
115 addLinkerCompressDebugSectionsOption(TC, Args, CmdArgs);
116
117 AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
118
119 if (ShouldLinkCompilerRuntime) {
120 AddRunTimeLibs(TC, D, CmdArgs, Args);
121
122 // We supply our own sanitizer runtimes that output errors to the
123 // Kernel debug log as well as stderr.
124 // FIXME: Properly port clang/gcc sanitizers and use those instead.
125 const SanitizerArgs &Sanitize = TC.getSanitizerArgs(JobArgs: Args);
126 if (Sanitize.needsUbsanRt())
127 CmdArgs.push_back(Elt: "-lubsan");
128 }
129
130 if (ShouldLinkLibCXX) {
131 bool OnlyLibstdcxxStatic = Args.hasArg(Ids: options::OPT_static_libstdcxx) &&
132 !Args.hasArg(Ids: options::OPT_static);
133 CmdArgs.push_back(Elt: "--push-state");
134 CmdArgs.push_back(Elt: "--as-needed");
135 if (OnlyLibstdcxxStatic)
136 CmdArgs.push_back(Elt: "-Bstatic");
137 TC.AddCXXStdlibLibArgs(Args, CmdArgs);
138 if (OnlyLibstdcxxStatic)
139 CmdArgs.push_back(Elt: "-Bdynamic");
140 CmdArgs.push_back(Elt: "--pop-state");
141 }
142
143 // Silence warnings when linking C code with a C++ '-stdlib' argument.
144 Args.ClaimAllArgs(Id0: options::OPT_stdlib_EQ);
145
146 if (ShouldLinkLibC)
147 CmdArgs.push_back(Elt: "-lc");
148
149 if (ShouldLinkStartFiles) {
150 std::string crtend_path;
151 if (TC.GetRuntimeLibType(Args) == ToolChain::RLT_CompilerRT) {
152 std::string crtend =
153 TC.getCompilerRT(Args, Component: "crtend", Type: ToolChain::FT_Object);
154 if (TC.getVFS().exists(Path: crtend))
155 crtend_path = crtend;
156 }
157 if (crtend_path.empty())
158 crtend_path = TC.GetFilePath(Name: "crtendS.o");
159 CmdArgs.push_back(Elt: Args.MakeArgString(Str: crtend_path));
160 }
161
162 const char *Exec = Args.MakeArgString(Str: TC.GetLinkerPath());
163 C.addCommand(Cmd: std::make_unique<Command>(args: JA, args: *this,
164 args: ResponseFileSupport::AtFileCurCP(),
165 args&: Exec, args&: CmdArgs, args: Inputs, args: Output));
166}
167
168SanitizerMask
169Serenity::getSupportedSanitizers(BoundArch BA,
170 Action::OffloadKind DeviceOffloadKind) const {
171 return ToolChain::getSupportedSanitizers(BA, DeviceOffloadKind) |
172 SanitizerKind::KernelAddress;
173}
174
175Serenity::Serenity(const Driver &D, const llvm::Triple &Triple,
176 const ArgList &Args)
177 : Generic_ELF(D, Triple, Args) {
178 getFilePaths().push_back(Elt: concat(Path: getDriver().SysRoot, A: "/usr/lib"));
179}
180
181Tool *Serenity::buildLinker() const {
182 return new tools::serenity::Linker(*this);
183}
184
185void Serenity::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
186 ArgStringList &CC1Args) const {
187 const Driver &D = getDriver();
188
189 if (DriverArgs.hasArg(Ids: options::OPT_nostdinc))
190 return;
191
192 if (!DriverArgs.hasArg(Ids: options::OPT_nobuiltininc))
193 addSystemInclude(DriverArgs, CC1Args, Path: concat(Path: D.ResourceDir, A: "/include"));
194
195 if (DriverArgs.hasArg(Ids: options::OPT_nostdlibinc))
196 return;
197
198 addSystemInclude(DriverArgs, CC1Args, Path: concat(Path: D.SysRoot, A: "/usr/include"));
199}
200