1 | //===-- CrossWindows.cpp - Cross Windows Tool Chain -----------------------===// |
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 "CrossWindows.h" |
10 | #include "CommonArgs.h" |
11 | #include "clang/Driver/Compilation.h" |
12 | #include "clang/Driver/Driver.h" |
13 | #include "clang/Driver/Options.h" |
14 | #include "clang/Driver/SanitizerArgs.h" |
15 | #include "llvm/Option/ArgList.h" |
16 | #include "llvm/Support/Path.h" |
17 | |
18 | using namespace clang::driver; |
19 | using namespace clang::driver::toolchains; |
20 | |
21 | using llvm::opt::ArgList; |
22 | using llvm::opt::ArgStringList; |
23 | |
24 | void tools::CrossWindows::Assembler::ConstructJob( |
25 | Compilation &C, const JobAction &JA, const InputInfo &Output, |
26 | const InputInfoList &Inputs, const ArgList &Args, |
27 | const char *LinkingOutput) const { |
28 | claimNoWarnArgs(Args); |
29 | const auto &TC = |
30 | static_cast<const toolchains::CrossWindowsToolChain &>(getToolChain()); |
31 | ArgStringList CmdArgs; |
32 | const char *Exec; |
33 | |
34 | switch (TC.getArch()) { |
35 | default: |
36 | llvm_unreachable("unsupported architecture" ); |
37 | case llvm::Triple::arm: |
38 | case llvm::Triple::thumb: |
39 | case llvm::Triple::aarch64: |
40 | break; |
41 | case llvm::Triple::x86: |
42 | CmdArgs.push_back(Elt: "--32" ); |
43 | break; |
44 | case llvm::Triple::x86_64: |
45 | CmdArgs.push_back(Elt: "--64" ); |
46 | break; |
47 | } |
48 | |
49 | Args.AddAllArgValues(Output&: CmdArgs, options::Id0: OPT_Wa_COMMA, options::Id1: OPT_Xassembler); |
50 | |
51 | CmdArgs.push_back(Elt: "-o" ); |
52 | CmdArgs.push_back(Elt: Output.getFilename()); |
53 | |
54 | for (const auto &Input : Inputs) |
55 | CmdArgs.push_back(Elt: Input.getFilename()); |
56 | |
57 | const std::string Assembler = TC.GetProgramPath(Name: "as" ); |
58 | Exec = Args.MakeArgString(Str: Assembler); |
59 | |
60 | C.addCommand(C: std::make_unique<Command>(args: JA, args: *this, args: ResponseFileSupport::None(), |
61 | args&: Exec, args&: CmdArgs, args: Inputs, args: Output)); |
62 | } |
63 | |
64 | void tools::CrossWindows::Linker::ConstructJob( |
65 | Compilation &C, const JobAction &JA, const InputInfo &Output, |
66 | const InputInfoList &Inputs, const ArgList &Args, |
67 | const char *LinkingOutput) const { |
68 | const auto &TC = |
69 | static_cast<const toolchains::CrossWindowsToolChain &>(getToolChain()); |
70 | const llvm::Triple &T = TC.getTriple(); |
71 | const Driver &D = TC.getDriver(); |
72 | SmallString<128> EntryPoint; |
73 | ArgStringList CmdArgs; |
74 | const char *Exec; |
75 | |
76 | // Silence warning for "clang -g foo.o -o foo" |
77 | Args.ClaimAllArgs(options::OPT_g_Group); |
78 | // and "clang -emit-llvm foo.o -o foo" |
79 | Args.ClaimAllArgs(options::OPT_emit_llvm); |
80 | // and for "clang -w foo.o -o foo" |
81 | Args.ClaimAllArgs(options::OPT_w); |
82 | // Other warning options are already handled somewhere else. |
83 | |
84 | if (!D.SysRoot.empty()) |
85 | CmdArgs.push_back(Elt: Args.MakeArgString(Str: "--sysroot=" + D.SysRoot)); |
86 | |
87 | if (Args.hasArg(options::OPT_pie)) |
88 | CmdArgs.push_back(Elt: "-pie" ); |
89 | if (Args.hasArg(options::OPT_rdynamic)) |
90 | CmdArgs.push_back(Elt: "-export-dynamic" ); |
91 | if (Args.hasArg(options::OPT_s)) |
92 | CmdArgs.push_back(Elt: "--strip-all" ); |
93 | |
94 | CmdArgs.push_back(Elt: "-m" ); |
95 | switch (TC.getArch()) { |
96 | default: |
97 | D.Diag(diag::DiagID: err_target_unknown_triple) << TC.getEffectiveTriple().str(); |
98 | break; |
99 | case llvm::Triple::arm: |
100 | case llvm::Triple::thumb: |
101 | // FIXME: this is incorrect for WinCE |
102 | CmdArgs.push_back(Elt: "thumb2pe" ); |
103 | break; |
104 | case llvm::Triple::aarch64: |
105 | CmdArgs.push_back(Elt: "arm64pe" ); |
106 | break; |
107 | case llvm::Triple::x86: |
108 | CmdArgs.push_back(Elt: "i386pe" ); |
109 | EntryPoint.append(RHS: "_" ); |
110 | break; |
111 | case llvm::Triple::x86_64: |
112 | CmdArgs.push_back(Elt: "i386pep" ); |
113 | break; |
114 | } |
115 | |
116 | if (Args.hasArg(options::OPT_shared)) { |
117 | switch (T.getArch()) { |
118 | default: |
119 | llvm_unreachable("unsupported architecture" ); |
120 | case llvm::Triple::aarch64: |
121 | case llvm::Triple::arm: |
122 | case llvm::Triple::thumb: |
123 | case llvm::Triple::x86_64: |
124 | EntryPoint.append(RHS: "_DllMainCRTStartup" ); |
125 | break; |
126 | case llvm::Triple::x86: |
127 | EntryPoint.append(RHS: "_DllMainCRTStartup@12" ); |
128 | break; |
129 | } |
130 | |
131 | CmdArgs.push_back(Elt: "-shared" ); |
132 | CmdArgs.push_back(Elt: Args.hasArg(options::OPT_static) ? "-Bstatic" |
133 | : "-Bdynamic" ); |
134 | |
135 | CmdArgs.push_back(Elt: "--enable-auto-image-base" ); |
136 | |
137 | CmdArgs.push_back(Elt: "--entry" ); |
138 | CmdArgs.push_back(Elt: Args.MakeArgString(Str: EntryPoint)); |
139 | } else { |
140 | EntryPoint.append(RHS: "mainCRTStartup" ); |
141 | |
142 | CmdArgs.push_back(Elt: Args.hasArg(options::OPT_static) ? "-Bstatic" |
143 | : "-Bdynamic" ); |
144 | |
145 | if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { |
146 | CmdArgs.push_back(Elt: "--entry" ); |
147 | CmdArgs.push_back(Elt: Args.MakeArgString(Str: EntryPoint)); |
148 | } |
149 | |
150 | // FIXME: handle subsystem |
151 | } |
152 | |
153 | // NOTE: deal with multiple definitions on Windows (e.g. COMDAT) |
154 | CmdArgs.push_back(Elt: "--allow-multiple-definition" ); |
155 | |
156 | CmdArgs.push_back(Elt: "-o" ); |
157 | CmdArgs.push_back(Elt: Output.getFilename()); |
158 | |
159 | if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_rdynamic)) { |
160 | SmallString<261> ImpLib(Output.getFilename()); |
161 | llvm::sys::path::replace_extension(path&: ImpLib, extension: ".lib" ); |
162 | |
163 | CmdArgs.push_back(Elt: "--out-implib" ); |
164 | CmdArgs.push_back(Elt: Args.MakeArgString(Str: ImpLib)); |
165 | } |
166 | |
167 | Args.AddAllArgs(Output&: CmdArgs, options::Id0: OPT_L); |
168 | TC.AddFilePathLibArgs(Args, CmdArgs); |
169 | AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA); |
170 | |
171 | if (TC.ShouldLinkCXXStdlib(Args)) { |
172 | bool StaticCXX = Args.hasArg(options::OPT_static_libstdcxx) && |
173 | !Args.hasArg(options::OPT_static); |
174 | if (StaticCXX) |
175 | CmdArgs.push_back(Elt: "-Bstatic" ); |
176 | TC.AddCXXStdlibLibArgs(Args, CmdArgs); |
177 | if (StaticCXX) |
178 | CmdArgs.push_back(Elt: "-Bdynamic" ); |
179 | } |
180 | |
181 | if (!Args.hasArg(options::OPT_nostdlib)) { |
182 | if (!Args.hasArg(options::OPT_nodefaultlibs)) { |
183 | // TODO handle /MT[d] /MD[d] |
184 | CmdArgs.push_back(Elt: "-lmsvcrt" ); |
185 | AddRunTimeLibs(TC, D, CmdArgs, Args); |
186 | } |
187 | } |
188 | |
189 | if (TC.getSanitizerArgs(JobArgs: Args).needsAsanRt()) { |
190 | // TODO handle /MT[d] /MD[d] |
191 | if (Args.hasArg(options::OPT_shared)) { |
192 | CmdArgs.push_back(Elt: TC.getCompilerRTArgString(Args, Component: "asan_dll_thunk" )); |
193 | } else { |
194 | for (const auto &Lib : {"asan_dynamic" , "asan_dynamic_runtime_thunk" }) |
195 | CmdArgs.push_back(Elt: TC.getCompilerRTArgString(Args, Component: Lib)); |
196 | // Make sure the dynamic runtime thunk is not optimized out at link time |
197 | // to ensure proper SEH handling. |
198 | CmdArgs.push_back(Elt: Args.MakeArgString(Str: "--undefined" )); |
199 | CmdArgs.push_back(Elt: Args.MakeArgString(Str: TC.getArch() == llvm::Triple::x86 |
200 | ? "___asan_seh_interceptor" |
201 | : "__asan_seh_interceptor" )); |
202 | } |
203 | } |
204 | |
205 | Exec = Args.MakeArgString(Str: TC.GetLinkerPath()); |
206 | |
207 | C.addCommand(C: std::make_unique<Command>(args: JA, args: *this, |
208 | args: ResponseFileSupport::AtFileUTF8(), |
209 | args&: Exec, args&: CmdArgs, args: Inputs, args: Output)); |
210 | } |
211 | |
212 | CrossWindowsToolChain::CrossWindowsToolChain(const Driver &D, |
213 | const llvm::Triple &T, |
214 | const llvm::opt::ArgList &Args) |
215 | : Generic_GCC(D, T, Args) {} |
216 | |
217 | ToolChain::UnwindTableLevel |
218 | CrossWindowsToolChain::getDefaultUnwindTableLevel(const ArgList &Args) const { |
219 | // FIXME: all non-x86 targets need unwind tables, however, LLVM currently does |
220 | // not know how to emit them. |
221 | return getArch() == llvm::Triple::x86_64 ? UnwindTableLevel::Asynchronous : UnwindTableLevel::None; |
222 | } |
223 | |
224 | bool CrossWindowsToolChain::isPICDefault() const { |
225 | return getArch() == llvm::Triple::x86_64; |
226 | } |
227 | |
228 | bool CrossWindowsToolChain::isPIEDefault(const llvm::opt::ArgList &Args) const { |
229 | return getArch() == llvm::Triple::x86_64; |
230 | } |
231 | |
232 | bool CrossWindowsToolChain::isPICDefaultForced() const { |
233 | return getArch() == llvm::Triple::x86_64; |
234 | } |
235 | |
236 | void CrossWindowsToolChain:: |
237 | AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, |
238 | llvm::opt::ArgStringList &CC1Args) const { |
239 | const Driver &D = getDriver(); |
240 | const std::string &SysRoot = D.SysRoot; |
241 | |
242 | auto AddSystemAfterIncludes = [&]() { |
243 | for (const auto &P : DriverArgs.getAllArgValues(options::OPT_isystem_after)) |
244 | addSystemInclude(DriverArgs, CC1Args, P); |
245 | }; |
246 | |
247 | if (DriverArgs.hasArg(options::OPT_nostdinc)) { |
248 | AddSystemAfterIncludes(); |
249 | return; |
250 | } |
251 | |
252 | addSystemInclude(DriverArgs, CC1Args, Path: SysRoot + "/usr/local/include" ); |
253 | if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { |
254 | SmallString<128> ResourceDir(D.ResourceDir); |
255 | llvm::sys::path::append(path&: ResourceDir, a: "include" ); |
256 | addSystemInclude(DriverArgs, CC1Args, Path: ResourceDir); |
257 | } |
258 | AddSystemAfterIncludes(); |
259 | addExternCSystemInclude(DriverArgs, CC1Args, Path: SysRoot + "/usr/include" ); |
260 | } |
261 | |
262 | void CrossWindowsToolChain:: |
263 | AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs, |
264 | llvm::opt::ArgStringList &CC1Args) const { |
265 | const std::string &SysRoot = getDriver().SysRoot; |
266 | |
267 | if (DriverArgs.hasArg(options::OPT_nostdinc) || |
268 | DriverArgs.hasArg(options::OPT_nostdincxx)) |
269 | return; |
270 | |
271 | if (GetCXXStdlibType(Args: DriverArgs) == ToolChain::CST_Libcxx) |
272 | addSystemInclude(DriverArgs, CC1Args, Path: SysRoot + "/usr/include/c++/v1" ); |
273 | } |
274 | |
275 | void CrossWindowsToolChain:: |
276 | AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, |
277 | llvm::opt::ArgStringList &CmdArgs) const { |
278 | if (GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) { |
279 | CmdArgs.push_back(Elt: "-lc++" ); |
280 | if (Args.hasArg(options::OPT_fexperimental_library)) |
281 | CmdArgs.push_back(Elt: "-lc++experimental" ); |
282 | } |
283 | } |
284 | |
285 | clang::SanitizerMask CrossWindowsToolChain::getSupportedSanitizers() const { |
286 | SanitizerMask Res = ToolChain::getSupportedSanitizers(); |
287 | Res |= SanitizerKind::Address; |
288 | Res |= SanitizerKind::PointerCompare; |
289 | Res |= SanitizerKind::PointerSubtract; |
290 | return Res; |
291 | } |
292 | |
293 | Tool *CrossWindowsToolChain::buildLinker() const { |
294 | return new tools::CrossWindows::Linker(*this); |
295 | } |
296 | |
297 | Tool *CrossWindowsToolChain::buildAssembler() const { |
298 | return new tools::CrossWindows::Assembler(*this); |
299 | } |
300 | |