1353358Sdim//===-- CrossWindows.cpp - Cross Windows Tool Chain -----------------------===//
2317019Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6317019Sdim//
7317019Sdim//===----------------------------------------------------------------------===//
8317019Sdim
9317019Sdim#include "CrossWindows.h"
10317019Sdim#include "CommonArgs.h"
11317019Sdim#include "clang/Driver/Compilation.h"
12317019Sdim#include "clang/Driver/Driver.h"
13317019Sdim#include "clang/Driver/Options.h"
14317019Sdim#include "clang/Driver/SanitizerArgs.h"
15317019Sdim#include "llvm/Option/ArgList.h"
16317019Sdim#include "llvm/Support/Path.h"
17317019Sdim
18317019Sdimusing namespace clang::driver;
19317019Sdimusing namespace clang::driver::toolchains;
20317019Sdim
21317019Sdimusing llvm::opt::ArgList;
22344779Sdimusing llvm::opt::ArgStringList;
23317019Sdim
24317019Sdimvoid tools::CrossWindows::Assembler::ConstructJob(
25317019Sdim    Compilation &C, const JobAction &JA, const InputInfo &Output,
26317019Sdim    const InputInfoList &Inputs, const ArgList &Args,
27317019Sdim    const char *LinkingOutput) const {
28317019Sdim  claimNoWarnArgs(Args);
29317019Sdim  const auto &TC =
30317019Sdim      static_cast<const toolchains::CrossWindowsToolChain &>(getToolChain());
31317019Sdim  ArgStringList CmdArgs;
32317019Sdim  const char *Exec;
33317019Sdim
34317019Sdim  switch (TC.getArch()) {
35317019Sdim  default:
36317019Sdim    llvm_unreachable("unsupported architecture");
37317019Sdim  case llvm::Triple::arm:
38317019Sdim  case llvm::Triple::thumb:
39327952Sdim  case llvm::Triple::aarch64:
40317019Sdim    break;
41317019Sdim  case llvm::Triple::x86:
42317019Sdim    CmdArgs.push_back("--32");
43317019Sdim    break;
44317019Sdim  case llvm::Triple::x86_64:
45317019Sdim    CmdArgs.push_back("--64");
46317019Sdim    break;
47317019Sdim  }
48317019Sdim
49317019Sdim  Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
50317019Sdim
51317019Sdim  CmdArgs.push_back("-o");
52317019Sdim  CmdArgs.push_back(Output.getFilename());
53317019Sdim
54317019Sdim  for (const auto &Input : Inputs)
55317019Sdim    CmdArgs.push_back(Input.getFilename());
56317019Sdim
57317019Sdim  const std::string Assembler = TC.GetProgramPath("as");
58317019Sdim  Exec = Args.MakeArgString(Assembler);
59317019Sdim
60360784Sdim  C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
61317019Sdim}
62317019Sdim
63317019Sdimvoid tools::CrossWindows::Linker::ConstructJob(
64317019Sdim    Compilation &C, const JobAction &JA, const InputInfo &Output,
65317019Sdim    const InputInfoList &Inputs, const ArgList &Args,
66317019Sdim    const char *LinkingOutput) const {
67317019Sdim  const auto &TC =
68317019Sdim      static_cast<const toolchains::CrossWindowsToolChain &>(getToolChain());
69317019Sdim  const llvm::Triple &T = TC.getTriple();
70317019Sdim  const Driver &D = TC.getDriver();
71317019Sdim  SmallString<128> EntryPoint;
72317019Sdim  ArgStringList CmdArgs;
73317019Sdim  const char *Exec;
74317019Sdim
75317019Sdim  // Silence warning for "clang -g foo.o -o foo"
76317019Sdim  Args.ClaimAllArgs(options::OPT_g_Group);
77317019Sdim  // and "clang -emit-llvm foo.o -o foo"
78317019Sdim  Args.ClaimAllArgs(options::OPT_emit_llvm);
79317019Sdim  // and for "clang -w foo.o -o foo"
80317019Sdim  Args.ClaimAllArgs(options::OPT_w);
81317019Sdim  // Other warning options are already handled somewhere else.
82317019Sdim
83317019Sdim  if (!D.SysRoot.empty())
84317019Sdim    CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
85317019Sdim
86317019Sdim  if (Args.hasArg(options::OPT_pie))
87317019Sdim    CmdArgs.push_back("-pie");
88317019Sdim  if (Args.hasArg(options::OPT_rdynamic))
89317019Sdim    CmdArgs.push_back("-export-dynamic");
90317019Sdim  if (Args.hasArg(options::OPT_s))
91317019Sdim    CmdArgs.push_back("--strip-all");
92317019Sdim
93317019Sdim  CmdArgs.push_back("-m");
94317019Sdim  switch (TC.getArch()) {
95317019Sdim  default:
96317019Sdim    llvm_unreachable("unsupported architecture");
97317019Sdim  case llvm::Triple::arm:
98317019Sdim  case llvm::Triple::thumb:
99317019Sdim    // FIXME: this is incorrect for WinCE
100317019Sdim    CmdArgs.push_back("thumb2pe");
101317019Sdim    break;
102327952Sdim  case llvm::Triple::aarch64:
103327952Sdim    CmdArgs.push_back("arm64pe");
104327952Sdim    break;
105317019Sdim  case llvm::Triple::x86:
106317019Sdim    CmdArgs.push_back("i386pe");
107317019Sdim    EntryPoint.append("_");
108317019Sdim    break;
109317019Sdim  case llvm::Triple::x86_64:
110317019Sdim    CmdArgs.push_back("i386pep");
111317019Sdim    break;
112317019Sdim  }
113317019Sdim
114317019Sdim  if (Args.hasArg(options::OPT_shared)) {
115317019Sdim    switch (T.getArch()) {
116317019Sdim    default:
117317019Sdim      llvm_unreachable("unsupported architecture");
118327952Sdim    case llvm::Triple::aarch64:
119317019Sdim    case llvm::Triple::arm:
120317019Sdim    case llvm::Triple::thumb:
121317019Sdim    case llvm::Triple::x86_64:
122317019Sdim      EntryPoint.append("_DllMainCRTStartup");
123317019Sdim      break;
124317019Sdim    case llvm::Triple::x86:
125317019Sdim      EntryPoint.append("_DllMainCRTStartup@12");
126317019Sdim      break;
127317019Sdim    }
128317019Sdim
129317019Sdim    CmdArgs.push_back("-shared");
130335799Sdim    CmdArgs.push_back(Args.hasArg(options::OPT_static) ? "-Bstatic"
131335799Sdim                                                       : "-Bdynamic");
132317019Sdim
133317019Sdim    CmdArgs.push_back("--enable-auto-image-base");
134317019Sdim
135317019Sdim    CmdArgs.push_back("--entry");
136317019Sdim    CmdArgs.push_back(Args.MakeArgString(EntryPoint));
137317019Sdim  } else {
138317019Sdim    EntryPoint.append("mainCRTStartup");
139317019Sdim
140317019Sdim    CmdArgs.push_back(Args.hasArg(options::OPT_static) ? "-Bstatic"
141317019Sdim                                                       : "-Bdynamic");
142317019Sdim
143317019Sdim    if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
144317019Sdim      CmdArgs.push_back("--entry");
145317019Sdim      CmdArgs.push_back(Args.MakeArgString(EntryPoint));
146317019Sdim    }
147317019Sdim
148317019Sdim    // FIXME: handle subsystem
149317019Sdim  }
150317019Sdim
151317019Sdim  // NOTE: deal with multiple definitions on Windows (e.g. COMDAT)
152317019Sdim  CmdArgs.push_back("--allow-multiple-definition");
153317019Sdim
154317019Sdim  CmdArgs.push_back("-o");
155317019Sdim  CmdArgs.push_back(Output.getFilename());
156317019Sdim
157317019Sdim  if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_rdynamic)) {
158317019Sdim    SmallString<261> ImpLib(Output.getFilename());
159317019Sdim    llvm::sys::path::replace_extension(ImpLib, ".lib");
160317019Sdim
161317019Sdim    CmdArgs.push_back("--out-implib");
162317019Sdim    CmdArgs.push_back(Args.MakeArgString(ImpLib));
163317019Sdim  }
164317019Sdim
165317019Sdim  Args.AddAllArgs(CmdArgs, options::OPT_L);
166317019Sdim  TC.AddFilePathLibArgs(Args, CmdArgs);
167317019Sdim  AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
168317019Sdim
169327952Sdim  if (TC.ShouldLinkCXXStdlib(Args)) {
170317019Sdim    bool StaticCXX = Args.hasArg(options::OPT_static_libstdcxx) &&
171317019Sdim                     !Args.hasArg(options::OPT_static);
172317019Sdim    if (StaticCXX)
173317019Sdim      CmdArgs.push_back("-Bstatic");
174317019Sdim    TC.AddCXXStdlibLibArgs(Args, CmdArgs);
175317019Sdim    if (StaticCXX)
176317019Sdim      CmdArgs.push_back("-Bdynamic");
177317019Sdim  }
178317019Sdim
179317019Sdim  if (!Args.hasArg(options::OPT_nostdlib)) {
180317019Sdim    if (!Args.hasArg(options::OPT_nodefaultlibs)) {
181317019Sdim      // TODO handle /MT[d] /MD[d]
182317019Sdim      CmdArgs.push_back("-lmsvcrt");
183317019Sdim      AddRunTimeLibs(TC, D, CmdArgs, Args);
184317019Sdim    }
185317019Sdim  }
186317019Sdim
187317019Sdim  if (TC.getSanitizerArgs().needsAsanRt()) {
188317019Sdim    // TODO handle /MT[d] /MD[d]
189317019Sdim    if (Args.hasArg(options::OPT_shared)) {
190317019Sdim      CmdArgs.push_back(TC.getCompilerRTArgString(Args, "asan_dll_thunk"));
191317019Sdim    } else {
192317019Sdim      for (const auto &Lib : {"asan_dynamic", "asan_dynamic_runtime_thunk"})
193317019Sdim        CmdArgs.push_back(TC.getCompilerRTArgString(Args, Lib));
194317019Sdim      // Make sure the dynamic runtime thunk is not optimized out at link time
195317019Sdim      // to ensure proper SEH handling.
196317019Sdim      CmdArgs.push_back(Args.MakeArgString("--undefined"));
197317019Sdim      CmdArgs.push_back(Args.MakeArgString(TC.getArch() == llvm::Triple::x86
198317019Sdim                                               ? "___asan_seh_interceptor"
199317019Sdim                                               : "__asan_seh_interceptor"));
200317019Sdim    }
201317019Sdim  }
202317019Sdim
203317019Sdim  Exec = Args.MakeArgString(TC.GetLinkerPath());
204317019Sdim
205360784Sdim  C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
206317019Sdim}
207317019Sdim
208317019SdimCrossWindowsToolChain::CrossWindowsToolChain(const Driver &D,
209317019Sdim                                             const llvm::Triple &T,
210317019Sdim                                             const llvm::opt::ArgList &Args)
211327952Sdim    : Generic_GCC(D, T, Args) {}
212317019Sdim
213322740Sdimbool CrossWindowsToolChain::IsUnwindTablesDefault(const ArgList &Args) const {
214317019Sdim  // FIXME: all non-x86 targets need unwind tables, however, LLVM currently does
215317019Sdim  // not know how to emit them.
216317019Sdim  return getArch() == llvm::Triple::x86_64;
217317019Sdim}
218317019Sdim
219317019Sdimbool CrossWindowsToolChain::isPICDefault() const {
220317019Sdim  return getArch() == llvm::Triple::x86_64;
221317019Sdim}
222317019Sdim
223317019Sdimbool CrossWindowsToolChain::isPIEDefault() const {
224317019Sdim  return getArch() == llvm::Triple::x86_64;
225317019Sdim}
226317019Sdim
227317019Sdimbool CrossWindowsToolChain::isPICDefaultForced() const {
228317019Sdim  return getArch() == llvm::Triple::x86_64;
229317019Sdim}
230317019Sdim
231317019Sdimvoid CrossWindowsToolChain::
232317019SdimAddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
233317019Sdim                          llvm::opt::ArgStringList &CC1Args) const {
234317019Sdim  const Driver &D = getDriver();
235317019Sdim  const std::string &SysRoot = D.SysRoot;
236317019Sdim
237320572Sdim  auto AddSystemAfterIncludes = [&]() {
238320572Sdim    for (const auto &P : DriverArgs.getAllArgValues(options::OPT_isystem_after))
239320572Sdim      addSystemInclude(DriverArgs, CC1Args, P);
240320572Sdim  };
241320572Sdim
242320572Sdim  if (DriverArgs.hasArg(options::OPT_nostdinc)) {
243320572Sdim    AddSystemAfterIncludes();
244317019Sdim    return;
245320572Sdim  }
246317019Sdim
247317019Sdim  addSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/local/include");
248317019Sdim  if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
249317019Sdim    SmallString<128> ResourceDir(D.ResourceDir);
250317019Sdim    llvm::sys::path::append(ResourceDir, "include");
251317019Sdim    addSystemInclude(DriverArgs, CC1Args, ResourceDir);
252317019Sdim  }
253320572Sdim  AddSystemAfterIncludes();
254317019Sdim  addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include");
255317019Sdim}
256317019Sdim
257317019Sdimvoid CrossWindowsToolChain::
258317019SdimAddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs,
259317019Sdim                             llvm::opt::ArgStringList &CC1Args) const {
260317019Sdim  const std::string &SysRoot = getDriver().SysRoot;
261317019Sdim
262320572Sdim  if (DriverArgs.hasArg(options::OPT_nostdinc) ||
263317019Sdim      DriverArgs.hasArg(options::OPT_nostdincxx))
264317019Sdim    return;
265317019Sdim
266327952Sdim  if (GetCXXStdlibType(DriverArgs) == ToolChain::CST_Libcxx)
267317019Sdim    addSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include/c++/v1");
268317019Sdim}
269317019Sdim
270317019Sdimvoid CrossWindowsToolChain::
271317019SdimAddCXXStdlibLibArgs(const llvm::opt::ArgList &DriverArgs,
272317019Sdim                    llvm::opt::ArgStringList &CC1Args) const {
273327952Sdim  if (GetCXXStdlibType(DriverArgs) == ToolChain::CST_Libcxx)
274317019Sdim    CC1Args.push_back("-lc++");
275317019Sdim}
276317019Sdim
277317019Sdimclang::SanitizerMask CrossWindowsToolChain::getSupportedSanitizers() const {
278317019Sdim  SanitizerMask Res = ToolChain::getSupportedSanitizers();
279317019Sdim  Res |= SanitizerKind::Address;
280353358Sdim  Res |= SanitizerKind::PointerCompare;
281353358Sdim  Res |= SanitizerKind::PointerSubtract;
282317019Sdim  return Res;
283317019Sdim}
284317019Sdim
285317019SdimTool *CrossWindowsToolChain::buildLinker() const {
286317019Sdim  return new tools::CrossWindows::Linker(*this);
287317019Sdim}
288317019Sdim
289317019SdimTool *CrossWindowsToolChain::buildAssembler() const {
290317019Sdim  return new tools::CrossWindows::Assembler(*this);
291317019Sdim}
292