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