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("--32");
43     break;
44   case llvm::Triple::x86_64:
45     CmdArgs.push_back("--64");
46     break;
47   }
48 
49   Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
50 
51   CmdArgs.push_back("-o");
52   CmdArgs.push_back(Output.getFilename());
53 
54   for (const auto &Input : Inputs)
55     CmdArgs.push_back(Input.getFilename());
56 
57   const std::string Assembler = TC.GetProgramPath("as");
58   Exec = Args.MakeArgString(Assembler);
59 
60   C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
61                                          Exec, CmdArgs, Inputs, 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(Args.MakeArgString("--sysroot=" + D.SysRoot));
86 
87   if (Args.hasArg(options::OPT_pie))
88     CmdArgs.push_back("-pie");
89   if (Args.hasArg(options::OPT_rdynamic))
90     CmdArgs.push_back("-export-dynamic");
91   if (Args.hasArg(options::OPT_s))
92     CmdArgs.push_back("--strip-all");
93 
94   CmdArgs.push_back("-m");
95   switch (TC.getArch()) {
96   default:
97     D.Diag(diag::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("thumb2pe");
103     break;
104   case llvm::Triple::aarch64:
105     CmdArgs.push_back("arm64pe");
106     break;
107   case llvm::Triple::x86:
108     CmdArgs.push_back("i386pe");
109     EntryPoint.append("_");
110     break;
111   case llvm::Triple::x86_64:
112     CmdArgs.push_back("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("_DllMainCRTStartup");
125       break;
126     case llvm::Triple::x86:
127       EntryPoint.append("_DllMainCRTStartup@12");
128       break;
129     }
130 
131     CmdArgs.push_back("-shared");
132     CmdArgs.push_back(Args.hasArg(options::OPT_static) ? "-Bstatic"
133                                                        : "-Bdynamic");
134 
135     CmdArgs.push_back("--enable-auto-image-base");
136 
137     CmdArgs.push_back("--entry");
138     CmdArgs.push_back(Args.MakeArgString(EntryPoint));
139   } else {
140     EntryPoint.append("mainCRTStartup");
141 
142     CmdArgs.push_back(Args.hasArg(options::OPT_static) ? "-Bstatic"
143                                                        : "-Bdynamic");
144 
145     if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
146       CmdArgs.push_back("--entry");
147       CmdArgs.push_back(Args.MakeArgString(EntryPoint));
148     }
149 
150     // FIXME: handle subsystem
151   }
152 
153   // NOTE: deal with multiple definitions on Windows (e.g. COMDAT)
154   CmdArgs.push_back("--allow-multiple-definition");
155 
156   CmdArgs.push_back("-o");
157   CmdArgs.push_back(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(ImpLib, ".lib");
162 
163     CmdArgs.push_back("--out-implib");
164     CmdArgs.push_back(Args.MakeArgString(ImpLib));
165   }
166 
167   Args.AddAllArgs(CmdArgs, options::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("-Bstatic");
176     TC.AddCXXStdlibLibArgs(Args, CmdArgs);
177     if (StaticCXX)
178       CmdArgs.push_back("-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("-lmsvcrt");
185       AddRunTimeLibs(TC, D, CmdArgs, Args);
186     }
187   }
188 
189   if (TC.getSanitizerArgs(Args).needsAsanRt()) {
190     // TODO handle /MT[d] /MD[d]
191     if (Args.hasArg(options::OPT_shared)) {
192       CmdArgs.push_back(TC.getCompilerRTArgString(Args, "asan_dll_thunk"));
193     } else {
194       for (const auto &Lib : {"asan_dynamic", "asan_dynamic_runtime_thunk"})
195         CmdArgs.push_back(TC.getCompilerRTArgString(Args, 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(Args.MakeArgString("--undefined"));
199       CmdArgs.push_back(Args.MakeArgString(TC.getArch() == llvm::Triple::x86
200                                                ? "___asan_seh_interceptor"
201                                                : "__asan_seh_interceptor"));
202     }
203   }
204 
205   Exec = Args.MakeArgString(TC.GetLinkerPath());
206 
207   C.addCommand(std::make_unique<Command>(JA, *this,
208                                          ResponseFileSupport::AtFileUTF8(),
209                                          Exec, CmdArgs, Inputs, 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, SysRoot + "/usr/local/include");
253   if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
254     SmallString<128> ResourceDir(D.ResourceDir);
255     llvm::sys::path::append(ResourceDir, "include");
256     addSystemInclude(DriverArgs, CC1Args, ResourceDir);
257   }
258   AddSystemAfterIncludes();
259   addExternCSystemInclude(DriverArgs, CC1Args, 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(DriverArgs) == ToolChain::CST_Libcxx)
272     addSystemInclude(DriverArgs, CC1Args, 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("-lc++");
280     if (Args.hasArg(options::OPT_fexperimental_library))
281       CmdArgs.push_back("-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