106f32e7eSjoerg //===-- CrossWindows.cpp - Cross Windows Tool Chain -----------------------===//
206f32e7eSjoerg //
306f32e7eSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406f32e7eSjoerg // See https://llvm.org/LICENSE.txt for license information.
506f32e7eSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606f32e7eSjoerg //
706f32e7eSjoerg //===----------------------------------------------------------------------===//
806f32e7eSjoerg 
906f32e7eSjoerg #include "CrossWindows.h"
1006f32e7eSjoerg #include "CommonArgs.h"
1106f32e7eSjoerg #include "clang/Driver/Compilation.h"
1206f32e7eSjoerg #include "clang/Driver/Driver.h"
1306f32e7eSjoerg #include "clang/Driver/Options.h"
1406f32e7eSjoerg #include "clang/Driver/SanitizerArgs.h"
1506f32e7eSjoerg #include "llvm/Option/ArgList.h"
1606f32e7eSjoerg #include "llvm/Support/Path.h"
1706f32e7eSjoerg 
1806f32e7eSjoerg using namespace clang::driver;
1906f32e7eSjoerg using namespace clang::driver::toolchains;
2006f32e7eSjoerg 
2106f32e7eSjoerg using llvm::opt::ArgList;
2206f32e7eSjoerg using llvm::opt::ArgStringList;
2306f32e7eSjoerg 
ConstructJob(Compilation & C,const JobAction & JA,const InputInfo & Output,const InputInfoList & Inputs,const ArgList & Args,const char * LinkingOutput) const2406f32e7eSjoerg void tools::CrossWindows::Assembler::ConstructJob(
2506f32e7eSjoerg     Compilation &C, const JobAction &JA, const InputInfo &Output,
2606f32e7eSjoerg     const InputInfoList &Inputs, const ArgList &Args,
2706f32e7eSjoerg     const char *LinkingOutput) const {
2806f32e7eSjoerg   claimNoWarnArgs(Args);
2906f32e7eSjoerg   const auto &TC =
3006f32e7eSjoerg       static_cast<const toolchains::CrossWindowsToolChain &>(getToolChain());
3106f32e7eSjoerg   ArgStringList CmdArgs;
3206f32e7eSjoerg   const char *Exec;
3306f32e7eSjoerg 
3406f32e7eSjoerg   switch (TC.getArch()) {
3506f32e7eSjoerg   default:
3606f32e7eSjoerg     llvm_unreachable("unsupported architecture");
3706f32e7eSjoerg   case llvm::Triple::arm:
3806f32e7eSjoerg   case llvm::Triple::thumb:
3906f32e7eSjoerg   case llvm::Triple::aarch64:
4006f32e7eSjoerg     break;
4106f32e7eSjoerg   case llvm::Triple::x86:
4206f32e7eSjoerg     CmdArgs.push_back("--32");
4306f32e7eSjoerg     break;
4406f32e7eSjoerg   case llvm::Triple::x86_64:
4506f32e7eSjoerg     CmdArgs.push_back("--64");
4606f32e7eSjoerg     break;
4706f32e7eSjoerg   }
4806f32e7eSjoerg 
4906f32e7eSjoerg   Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
5006f32e7eSjoerg 
5106f32e7eSjoerg   CmdArgs.push_back("-o");
5206f32e7eSjoerg   CmdArgs.push_back(Output.getFilename());
5306f32e7eSjoerg 
5406f32e7eSjoerg   for (const auto &Input : Inputs)
5506f32e7eSjoerg     CmdArgs.push_back(Input.getFilename());
5606f32e7eSjoerg 
5706f32e7eSjoerg   const std::string Assembler = TC.GetProgramPath("as");
5806f32e7eSjoerg   Exec = Args.MakeArgString(Assembler);
5906f32e7eSjoerg 
60*13fbcb42Sjoerg   C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
61*13fbcb42Sjoerg                                          Exec, CmdArgs, Inputs, Output));
6206f32e7eSjoerg }
6306f32e7eSjoerg 
ConstructJob(Compilation & C,const JobAction & JA,const InputInfo & Output,const InputInfoList & Inputs,const ArgList & Args,const char * LinkingOutput) const6406f32e7eSjoerg void tools::CrossWindows::Linker::ConstructJob(
6506f32e7eSjoerg     Compilation &C, const JobAction &JA, const InputInfo &Output,
6606f32e7eSjoerg     const InputInfoList &Inputs, const ArgList &Args,
6706f32e7eSjoerg     const char *LinkingOutput) const {
6806f32e7eSjoerg   const auto &TC =
6906f32e7eSjoerg       static_cast<const toolchains::CrossWindowsToolChain &>(getToolChain());
7006f32e7eSjoerg   const llvm::Triple &T = TC.getTriple();
7106f32e7eSjoerg   const Driver &D = TC.getDriver();
7206f32e7eSjoerg   SmallString<128> EntryPoint;
7306f32e7eSjoerg   ArgStringList CmdArgs;
7406f32e7eSjoerg   const char *Exec;
7506f32e7eSjoerg 
7606f32e7eSjoerg   // Silence warning for "clang -g foo.o -o foo"
7706f32e7eSjoerg   Args.ClaimAllArgs(options::OPT_g_Group);
7806f32e7eSjoerg   // and "clang -emit-llvm foo.o -o foo"
7906f32e7eSjoerg   Args.ClaimAllArgs(options::OPT_emit_llvm);
8006f32e7eSjoerg   // and for "clang -w foo.o -o foo"
8106f32e7eSjoerg   Args.ClaimAllArgs(options::OPT_w);
8206f32e7eSjoerg   // Other warning options are already handled somewhere else.
8306f32e7eSjoerg 
8406f32e7eSjoerg   if (!D.SysRoot.empty())
8506f32e7eSjoerg     CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
8606f32e7eSjoerg 
8706f32e7eSjoerg   if (Args.hasArg(options::OPT_pie))
8806f32e7eSjoerg     CmdArgs.push_back("-pie");
8906f32e7eSjoerg   if (Args.hasArg(options::OPT_rdynamic))
9006f32e7eSjoerg     CmdArgs.push_back("-export-dynamic");
9106f32e7eSjoerg   if (Args.hasArg(options::OPT_s))
9206f32e7eSjoerg     CmdArgs.push_back("--strip-all");
9306f32e7eSjoerg 
9406f32e7eSjoerg   CmdArgs.push_back("-m");
9506f32e7eSjoerg   switch (TC.getArch()) {
9606f32e7eSjoerg   default:
9706f32e7eSjoerg     llvm_unreachable("unsupported architecture");
9806f32e7eSjoerg   case llvm::Triple::arm:
9906f32e7eSjoerg   case llvm::Triple::thumb:
10006f32e7eSjoerg     // FIXME: this is incorrect for WinCE
10106f32e7eSjoerg     CmdArgs.push_back("thumb2pe");
10206f32e7eSjoerg     break;
10306f32e7eSjoerg   case llvm::Triple::aarch64:
10406f32e7eSjoerg     CmdArgs.push_back("arm64pe");
10506f32e7eSjoerg     break;
10606f32e7eSjoerg   case llvm::Triple::x86:
10706f32e7eSjoerg     CmdArgs.push_back("i386pe");
10806f32e7eSjoerg     EntryPoint.append("_");
10906f32e7eSjoerg     break;
11006f32e7eSjoerg   case llvm::Triple::x86_64:
11106f32e7eSjoerg     CmdArgs.push_back("i386pep");
11206f32e7eSjoerg     break;
11306f32e7eSjoerg   }
11406f32e7eSjoerg 
11506f32e7eSjoerg   if (Args.hasArg(options::OPT_shared)) {
11606f32e7eSjoerg     switch (T.getArch()) {
11706f32e7eSjoerg     default:
11806f32e7eSjoerg       llvm_unreachable("unsupported architecture");
11906f32e7eSjoerg     case llvm::Triple::aarch64:
12006f32e7eSjoerg     case llvm::Triple::arm:
12106f32e7eSjoerg     case llvm::Triple::thumb:
12206f32e7eSjoerg     case llvm::Triple::x86_64:
12306f32e7eSjoerg       EntryPoint.append("_DllMainCRTStartup");
12406f32e7eSjoerg       break;
12506f32e7eSjoerg     case llvm::Triple::x86:
12606f32e7eSjoerg       EntryPoint.append("_DllMainCRTStartup@12");
12706f32e7eSjoerg       break;
12806f32e7eSjoerg     }
12906f32e7eSjoerg 
13006f32e7eSjoerg     CmdArgs.push_back("-shared");
13106f32e7eSjoerg     CmdArgs.push_back(Args.hasArg(options::OPT_static) ? "-Bstatic"
13206f32e7eSjoerg                                                        : "-Bdynamic");
13306f32e7eSjoerg 
13406f32e7eSjoerg     CmdArgs.push_back("--enable-auto-image-base");
13506f32e7eSjoerg 
13606f32e7eSjoerg     CmdArgs.push_back("--entry");
13706f32e7eSjoerg     CmdArgs.push_back(Args.MakeArgString(EntryPoint));
13806f32e7eSjoerg   } else {
13906f32e7eSjoerg     EntryPoint.append("mainCRTStartup");
14006f32e7eSjoerg 
14106f32e7eSjoerg     CmdArgs.push_back(Args.hasArg(options::OPT_static) ? "-Bstatic"
14206f32e7eSjoerg                                                        : "-Bdynamic");
14306f32e7eSjoerg 
14406f32e7eSjoerg     if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
14506f32e7eSjoerg       CmdArgs.push_back("--entry");
14606f32e7eSjoerg       CmdArgs.push_back(Args.MakeArgString(EntryPoint));
14706f32e7eSjoerg     }
14806f32e7eSjoerg 
14906f32e7eSjoerg     // FIXME: handle subsystem
15006f32e7eSjoerg   }
15106f32e7eSjoerg 
15206f32e7eSjoerg   // NOTE: deal with multiple definitions on Windows (e.g. COMDAT)
15306f32e7eSjoerg   CmdArgs.push_back("--allow-multiple-definition");
15406f32e7eSjoerg 
15506f32e7eSjoerg   CmdArgs.push_back("-o");
15606f32e7eSjoerg   CmdArgs.push_back(Output.getFilename());
15706f32e7eSjoerg 
15806f32e7eSjoerg   if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_rdynamic)) {
15906f32e7eSjoerg     SmallString<261> ImpLib(Output.getFilename());
16006f32e7eSjoerg     llvm::sys::path::replace_extension(ImpLib, ".lib");
16106f32e7eSjoerg 
16206f32e7eSjoerg     CmdArgs.push_back("--out-implib");
16306f32e7eSjoerg     CmdArgs.push_back(Args.MakeArgString(ImpLib));
16406f32e7eSjoerg   }
16506f32e7eSjoerg 
16606f32e7eSjoerg   Args.AddAllArgs(CmdArgs, options::OPT_L);
16706f32e7eSjoerg   TC.AddFilePathLibArgs(Args, CmdArgs);
16806f32e7eSjoerg   AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
16906f32e7eSjoerg 
17006f32e7eSjoerg   if (TC.ShouldLinkCXXStdlib(Args)) {
17106f32e7eSjoerg     bool StaticCXX = Args.hasArg(options::OPT_static_libstdcxx) &&
17206f32e7eSjoerg                      !Args.hasArg(options::OPT_static);
17306f32e7eSjoerg     if (StaticCXX)
17406f32e7eSjoerg       CmdArgs.push_back("-Bstatic");
17506f32e7eSjoerg     TC.AddCXXStdlibLibArgs(Args, CmdArgs);
17606f32e7eSjoerg     if (StaticCXX)
17706f32e7eSjoerg       CmdArgs.push_back("-Bdynamic");
17806f32e7eSjoerg   }
17906f32e7eSjoerg 
18006f32e7eSjoerg   if (!Args.hasArg(options::OPT_nostdlib)) {
18106f32e7eSjoerg     if (!Args.hasArg(options::OPT_nodefaultlibs)) {
18206f32e7eSjoerg       // TODO handle /MT[d] /MD[d]
18306f32e7eSjoerg       CmdArgs.push_back("-lmsvcrt");
18406f32e7eSjoerg       AddRunTimeLibs(TC, D, CmdArgs, Args);
18506f32e7eSjoerg     }
18606f32e7eSjoerg   }
18706f32e7eSjoerg 
18806f32e7eSjoerg   if (TC.getSanitizerArgs().needsAsanRt()) {
18906f32e7eSjoerg     // TODO handle /MT[d] /MD[d]
19006f32e7eSjoerg     if (Args.hasArg(options::OPT_shared)) {
19106f32e7eSjoerg       CmdArgs.push_back(TC.getCompilerRTArgString(Args, "asan_dll_thunk"));
19206f32e7eSjoerg     } else {
19306f32e7eSjoerg       for (const auto &Lib : {"asan_dynamic", "asan_dynamic_runtime_thunk"})
19406f32e7eSjoerg         CmdArgs.push_back(TC.getCompilerRTArgString(Args, Lib));
19506f32e7eSjoerg       // Make sure the dynamic runtime thunk is not optimized out at link time
19606f32e7eSjoerg       // to ensure proper SEH handling.
19706f32e7eSjoerg       CmdArgs.push_back(Args.MakeArgString("--undefined"));
19806f32e7eSjoerg       CmdArgs.push_back(Args.MakeArgString(TC.getArch() == llvm::Triple::x86
19906f32e7eSjoerg                                                ? "___asan_seh_interceptor"
20006f32e7eSjoerg                                                : "__asan_seh_interceptor"));
20106f32e7eSjoerg     }
20206f32e7eSjoerg   }
20306f32e7eSjoerg 
20406f32e7eSjoerg   Exec = Args.MakeArgString(TC.GetLinkerPath());
20506f32e7eSjoerg 
206*13fbcb42Sjoerg   C.addCommand(std::make_unique<Command>(JA, *this,
207*13fbcb42Sjoerg                                          ResponseFileSupport::AtFileUTF8(),
208*13fbcb42Sjoerg                                          Exec, CmdArgs, Inputs, Output));
20906f32e7eSjoerg }
21006f32e7eSjoerg 
CrossWindowsToolChain(const Driver & D,const llvm::Triple & T,const llvm::opt::ArgList & Args)21106f32e7eSjoerg CrossWindowsToolChain::CrossWindowsToolChain(const Driver &D,
21206f32e7eSjoerg                                              const llvm::Triple &T,
21306f32e7eSjoerg                                              const llvm::opt::ArgList &Args)
21406f32e7eSjoerg     : Generic_GCC(D, T, Args) {}
21506f32e7eSjoerg 
IsUnwindTablesDefault(const ArgList & Args) const21606f32e7eSjoerg bool CrossWindowsToolChain::IsUnwindTablesDefault(const ArgList &Args) const {
21706f32e7eSjoerg   // FIXME: all non-x86 targets need unwind tables, however, LLVM currently does
21806f32e7eSjoerg   // not know how to emit them.
21906f32e7eSjoerg   return getArch() == llvm::Triple::x86_64;
22006f32e7eSjoerg }
22106f32e7eSjoerg 
isPICDefault() const22206f32e7eSjoerg bool CrossWindowsToolChain::isPICDefault() const {
22306f32e7eSjoerg   return getArch() == llvm::Triple::x86_64;
22406f32e7eSjoerg }
22506f32e7eSjoerg 
isPIEDefault() const22606f32e7eSjoerg bool CrossWindowsToolChain::isPIEDefault() const {
22706f32e7eSjoerg   return getArch() == llvm::Triple::x86_64;
22806f32e7eSjoerg }
22906f32e7eSjoerg 
isPICDefaultForced() const23006f32e7eSjoerg bool CrossWindowsToolChain::isPICDefaultForced() const {
23106f32e7eSjoerg   return getArch() == llvm::Triple::x86_64;
23206f32e7eSjoerg }
23306f32e7eSjoerg 
23406f32e7eSjoerg void CrossWindowsToolChain::
AddClangSystemIncludeArgs(const llvm::opt::ArgList & DriverArgs,llvm::opt::ArgStringList & CC1Args) const23506f32e7eSjoerg AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
23606f32e7eSjoerg                           llvm::opt::ArgStringList &CC1Args) const {
23706f32e7eSjoerg   const Driver &D = getDriver();
23806f32e7eSjoerg   const std::string &SysRoot = D.SysRoot;
23906f32e7eSjoerg 
24006f32e7eSjoerg   auto AddSystemAfterIncludes = [&]() {
24106f32e7eSjoerg     for (const auto &P : DriverArgs.getAllArgValues(options::OPT_isystem_after))
24206f32e7eSjoerg       addSystemInclude(DriverArgs, CC1Args, P);
24306f32e7eSjoerg   };
24406f32e7eSjoerg 
24506f32e7eSjoerg   if (DriverArgs.hasArg(options::OPT_nostdinc)) {
24606f32e7eSjoerg     AddSystemAfterIncludes();
24706f32e7eSjoerg     return;
24806f32e7eSjoerg   }
24906f32e7eSjoerg 
25006f32e7eSjoerg   addSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/local/include");
25106f32e7eSjoerg   if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
25206f32e7eSjoerg     SmallString<128> ResourceDir(D.ResourceDir);
25306f32e7eSjoerg     llvm::sys::path::append(ResourceDir, "include");
25406f32e7eSjoerg     addSystemInclude(DriverArgs, CC1Args, ResourceDir);
25506f32e7eSjoerg   }
25606f32e7eSjoerg   AddSystemAfterIncludes();
25706f32e7eSjoerg   addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include");
25806f32e7eSjoerg }
25906f32e7eSjoerg 
26006f32e7eSjoerg void CrossWindowsToolChain::
AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList & DriverArgs,llvm::opt::ArgStringList & CC1Args) const26106f32e7eSjoerg AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs,
26206f32e7eSjoerg                              llvm::opt::ArgStringList &CC1Args) const {
26306f32e7eSjoerg   const std::string &SysRoot = getDriver().SysRoot;
26406f32e7eSjoerg 
26506f32e7eSjoerg   if (DriverArgs.hasArg(options::OPT_nostdinc) ||
26606f32e7eSjoerg       DriverArgs.hasArg(options::OPT_nostdincxx))
26706f32e7eSjoerg     return;
26806f32e7eSjoerg 
26906f32e7eSjoerg   if (GetCXXStdlibType(DriverArgs) == ToolChain::CST_Libcxx)
27006f32e7eSjoerg     addSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include/c++/v1");
27106f32e7eSjoerg }
27206f32e7eSjoerg 
27306f32e7eSjoerg void CrossWindowsToolChain::
AddCXXStdlibLibArgs(const llvm::opt::ArgList & Args,llvm::opt::ArgStringList & CmdArgs) const274*13fbcb42Sjoerg AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
275*13fbcb42Sjoerg                     llvm::opt::ArgStringList &CmdArgs) const {
276*13fbcb42Sjoerg   if (GetCXXStdlibType(Args) == ToolChain::CST_Libcxx)
277*13fbcb42Sjoerg     CmdArgs.push_back("-lc++");
27806f32e7eSjoerg }
27906f32e7eSjoerg 
getSupportedSanitizers() const28006f32e7eSjoerg clang::SanitizerMask CrossWindowsToolChain::getSupportedSanitizers() const {
28106f32e7eSjoerg   SanitizerMask Res = ToolChain::getSupportedSanitizers();
28206f32e7eSjoerg   Res |= SanitizerKind::Address;
28306f32e7eSjoerg   Res |= SanitizerKind::PointerCompare;
28406f32e7eSjoerg   Res |= SanitizerKind::PointerSubtract;
28506f32e7eSjoerg   return Res;
28606f32e7eSjoerg }
28706f32e7eSjoerg 
buildLinker() const28806f32e7eSjoerg Tool *CrossWindowsToolChain::buildLinker() const {
28906f32e7eSjoerg   return new tools::CrossWindows::Linker(*this);
29006f32e7eSjoerg }
29106f32e7eSjoerg 
buildAssembler() const29206f32e7eSjoerg Tool *CrossWindowsToolChain::buildAssembler() const {
29306f32e7eSjoerg   return new tools::CrossWindows::Assembler(*this);
29406f32e7eSjoerg }
295