diff options
Diffstat (limited to 'clang/lib/Driver/ToolChains/NaCl.cpp')
| -rw-r--r-- | clang/lib/Driver/ToolChains/NaCl.cpp | 370 | 
1 files changed, 370 insertions, 0 deletions
| diff --git a/clang/lib/Driver/ToolChains/NaCl.cpp b/clang/lib/Driver/ToolChains/NaCl.cpp new file mode 100644 index 000000000000..97241c884027 --- /dev/null +++ b/clang/lib/Driver/ToolChains/NaCl.cpp @@ -0,0 +1,370 @@ +//===--- NaCl.cpp - Native Client ToolChain Implementations -----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "NaCl.h" +#include "InputInfo.h" +#include "CommonArgs.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/Path.h" + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; + +// NaCl ARM assembly (inline or standalone) can be written with a set of macros +// for the various SFI requirements like register masking. The assembly tool +// inserts the file containing the macros as an input into all the assembly +// jobs. +void nacltools::AssemblerARM::ConstructJob(Compilation &C, const JobAction &JA, +                                           const InputInfo &Output, +                                           const InputInfoList &Inputs, +                                           const ArgList &Args, +                                           const char *LinkingOutput) const { +  const toolchains::NaClToolChain &ToolChain = +      static_cast<const toolchains::NaClToolChain &>(getToolChain()); +  InputInfo NaClMacros(types::TY_PP_Asm, ToolChain.GetNaClArmMacrosPath(), +                       "nacl-arm-macros.s"); +  InputInfoList NewInputs; +  NewInputs.push_back(NaClMacros); +  NewInputs.append(Inputs.begin(), Inputs.end()); +  gnutools::Assembler::ConstructJob(C, JA, Output, NewInputs, Args, +                                    LinkingOutput); +} + +// This is quite similar to gnutools::Linker::ConstructJob with changes that +// we use static by default, do not yet support sanitizers or LTO, and a few +// others. Eventually we can support more of that and hopefully migrate back +// to gnutools::Linker. +void nacltools::Linker::ConstructJob(Compilation &C, const JobAction &JA, +                                     const InputInfo &Output, +                                     const InputInfoList &Inputs, +                                     const ArgList &Args, +                                     const char *LinkingOutput) const { + +  const toolchains::NaClToolChain &ToolChain = +      static_cast<const toolchains::NaClToolChain &>(getToolChain()); +  const Driver &D = ToolChain.getDriver(); +  const llvm::Triple::ArchType Arch = ToolChain.getArch(); +  const bool IsStatic = +      !Args.hasArg(options::OPT_dynamic) && !Args.hasArg(options::OPT_shared); + +  ArgStringList CmdArgs; + +  // Silence warning for "clang -g foo.o -o foo" +  Args.ClaimAllArgs(options::OPT_g_Group); +  // and "clang -emit-llvm foo.o -o foo" +  Args.ClaimAllArgs(options::OPT_emit_llvm); +  // and for "clang -w foo.o -o foo". Other warning options are already +  // handled somewhere else. +  Args.ClaimAllArgs(options::OPT_w); + +  if (!D.SysRoot.empty()) +    CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); + +  if (Args.hasArg(options::OPT_rdynamic)) +    CmdArgs.push_back("-export-dynamic"); + +  if (Args.hasArg(options::OPT_s)) +    CmdArgs.push_back("-s"); + +  // NaClToolChain doesn't have ExtraOpts like Linux; the only relevant flag +  // from there is --build-id, which we do want. +  CmdArgs.push_back("--build-id"); + +  if (!IsStatic) +    CmdArgs.push_back("--eh-frame-hdr"); + +  CmdArgs.push_back("-m"); +  if (Arch == llvm::Triple::x86) +    CmdArgs.push_back("elf_i386_nacl"); +  else if (Arch == llvm::Triple::arm) +    CmdArgs.push_back("armelf_nacl"); +  else if (Arch == llvm::Triple::x86_64) +    CmdArgs.push_back("elf_x86_64_nacl"); +  else if (Arch == llvm::Triple::mipsel) +    CmdArgs.push_back("mipselelf_nacl"); +  else +    D.Diag(diag::err_target_unsupported_arch) << ToolChain.getArchName() +                                              << "Native Client"; + +  if (IsStatic) +    CmdArgs.push_back("-static"); +  else if (Args.hasArg(options::OPT_shared)) +    CmdArgs.push_back("-shared"); + +  CmdArgs.push_back("-o"); +  CmdArgs.push_back(Output.getFilename()); +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { +    if (!Args.hasArg(options::OPT_shared)) +      CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt1.o"))); +    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); + +    const char *crtbegin; +    if (IsStatic) +      crtbegin = "crtbeginT.o"; +    else if (Args.hasArg(options::OPT_shared)) +      crtbegin = "crtbeginS.o"; +    else +      crtbegin = "crtbegin.o"; +    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); +  } + +  Args.AddAllArgs(CmdArgs, options::OPT_L); +  Args.AddAllArgs(CmdArgs, options::OPT_u); + +  ToolChain.AddFilePathLibArgs(Args, CmdArgs); + +  if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) +    CmdArgs.push_back("--no-demangle"); + +  AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); + +  if (D.CCCIsCXX() && +      !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { +    if (ToolChain.ShouldLinkCXXStdlib(Args)) { +      bool OnlyLibstdcxxStatic = +          Args.hasArg(options::OPT_static_libstdcxx) && !IsStatic; +      if (OnlyLibstdcxxStatic) +        CmdArgs.push_back("-Bstatic"); +      ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); +      if (OnlyLibstdcxxStatic) +        CmdArgs.push_back("-Bdynamic"); +    } +    CmdArgs.push_back("-lm"); +  } + +  if (!Args.hasArg(options::OPT_nostdlib)) { +    if (!Args.hasArg(options::OPT_nodefaultlibs)) { +      // Always use groups, since it has no effect on dynamic libraries. +      CmdArgs.push_back("--start-group"); +      CmdArgs.push_back("-lc"); +      // NaCl's libc++ currently requires libpthread, so just always include it +      // in the group for C++. +      if (Args.hasArg(options::OPT_pthread) || +          Args.hasArg(options::OPT_pthreads) || D.CCCIsCXX()) { +        // Gold, used by Mips, handles nested groups differently than ld, and +        // without '-lnacl' it prefers symbols from libpthread.a over libnacl.a, +        // which is not a desired behaviour here. +        // See https://sourceware.org/ml/binutils/2015-03/msg00034.html +        if (getToolChain().getArch() == llvm::Triple::mipsel) +          CmdArgs.push_back("-lnacl"); + +        CmdArgs.push_back("-lpthread"); +      } + +      CmdArgs.push_back("-lgcc"); +      CmdArgs.push_back("--as-needed"); +      if (IsStatic) +        CmdArgs.push_back("-lgcc_eh"); +      else +        CmdArgs.push_back("-lgcc_s"); +      CmdArgs.push_back("--no-as-needed"); + +      // Mips needs to create and use pnacl_legacy library that contains +      // definitions from bitcode/pnaclmm.c and definitions for +      // __nacl_tp_tls_offset() and __nacl_tp_tdb_offset(). +      if (getToolChain().getArch() == llvm::Triple::mipsel) +        CmdArgs.push_back("-lpnacl_legacy"); + +      CmdArgs.push_back("--end-group"); +    } + +    if (!Args.hasArg(options::OPT_nostartfiles)) { +      const char *crtend; +      if (Args.hasArg(options::OPT_shared)) +        crtend = "crtendS.o"; +      else +        crtend = "crtend.o"; + +      CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend))); +      CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); +    } +  } + +  const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); +  C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +/// NaCl Toolchain +NaClToolChain::NaClToolChain(const Driver &D, const llvm::Triple &Triple, +                             const ArgList &Args) +    : Generic_ELF(D, Triple, Args) { + +  // Remove paths added by Generic_GCC. NaCl Toolchain cannot use the +  // default paths, and must instead only use the paths provided +  // with this toolchain based on architecture. +  path_list &file_paths = getFilePaths(); +  path_list &prog_paths = getProgramPaths(); + +  file_paths.clear(); +  prog_paths.clear(); + +  // Path for library files (libc.a, ...) +  std::string FilePath(getDriver().Dir + "/../"); + +  // Path for tools (clang, ld, etc..) +  std::string ProgPath(getDriver().Dir + "/../"); + +  // Path for toolchain libraries (libgcc.a, ...) +  std::string ToolPath(getDriver().ResourceDir + "/lib/"); + +  switch (Triple.getArch()) { +  case llvm::Triple::x86: +    file_paths.push_back(FilePath + "x86_64-nacl/lib32"); +    file_paths.push_back(FilePath + "i686-nacl/usr/lib"); +    prog_paths.push_back(ProgPath + "x86_64-nacl/bin"); +    file_paths.push_back(ToolPath + "i686-nacl"); +    break; +  case llvm::Triple::x86_64: +    file_paths.push_back(FilePath + "x86_64-nacl/lib"); +    file_paths.push_back(FilePath + "x86_64-nacl/usr/lib"); +    prog_paths.push_back(ProgPath + "x86_64-nacl/bin"); +    file_paths.push_back(ToolPath + "x86_64-nacl"); +    break; +  case llvm::Triple::arm: +    file_paths.push_back(FilePath + "arm-nacl/lib"); +    file_paths.push_back(FilePath + "arm-nacl/usr/lib"); +    prog_paths.push_back(ProgPath + "arm-nacl/bin"); +    file_paths.push_back(ToolPath + "arm-nacl"); +    break; +  case llvm::Triple::mipsel: +    file_paths.push_back(FilePath + "mipsel-nacl/lib"); +    file_paths.push_back(FilePath + "mipsel-nacl/usr/lib"); +    prog_paths.push_back(ProgPath + "bin"); +    file_paths.push_back(ToolPath + "mipsel-nacl"); +    break; +  default: +    break; +  } + +  NaClArmMacrosPath = GetFilePath("nacl-arm-macros.s"); +} + +void NaClToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, +                                              ArgStringList &CC1Args) const { +  const Driver &D = getDriver(); +  if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc)) +    return; + +  if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { +    SmallString<128> P(D.ResourceDir); +    llvm::sys::path::append(P, "include"); +    addSystemInclude(DriverArgs, CC1Args, P.str()); +  } + +  if (DriverArgs.hasArg(options::OPT_nostdlibinc)) +    return; + +  SmallString<128> P(D.Dir + "/../"); +  switch (getTriple().getArch()) { +  case llvm::Triple::x86: +    // x86 is special because multilib style uses x86_64-nacl/include for libc +    // headers but the SDK wants i686-nacl/usr/include. The other architectures +    // have the same substring. +    llvm::sys::path::append(P, "i686-nacl/usr/include"); +    addSystemInclude(DriverArgs, CC1Args, P.str()); +    llvm::sys::path::remove_filename(P); +    llvm::sys::path::remove_filename(P); +    llvm::sys::path::remove_filename(P); +    llvm::sys::path::append(P, "x86_64-nacl/include"); +    addSystemInclude(DriverArgs, CC1Args, P.str()); +    return; +  case llvm::Triple::arm: +    llvm::sys::path::append(P, "arm-nacl/usr/include"); +    break; +  case llvm::Triple::x86_64: +    llvm::sys::path::append(P, "x86_64-nacl/usr/include"); +    break; +  case llvm::Triple::mipsel: +    llvm::sys::path::append(P, "mipsel-nacl/usr/include"); +    break; +  default: +    return; +  } + +  addSystemInclude(DriverArgs, CC1Args, P.str()); +  llvm::sys::path::remove_filename(P); +  llvm::sys::path::remove_filename(P); +  llvm::sys::path::append(P, "include"); +  addSystemInclude(DriverArgs, CC1Args, P.str()); +} + +void NaClToolChain::AddCXXStdlibLibArgs(const ArgList &Args, +                                        ArgStringList &CmdArgs) const { +  // Check for -stdlib= flags. We only support libc++ but this consumes the arg +  // if the value is libc++, and emits an error for other values. +  GetCXXStdlibType(Args); +  CmdArgs.push_back("-lc++"); +} + +void NaClToolChain::addLibCxxIncludePaths( +    const llvm::opt::ArgList &DriverArgs, +    llvm::opt::ArgStringList &CC1Args) const { +  const Driver &D = getDriver(); + +  SmallString<128> P(D.Dir + "/../"); +  switch (getTriple().getArch()) { +  default: +    break; +  case llvm::Triple::arm: +    llvm::sys::path::append(P, "arm-nacl/include/c++/v1"); +    addSystemInclude(DriverArgs, CC1Args, P.str()); +    break; +  case llvm::Triple::x86: +    llvm::sys::path::append(P, "x86_64-nacl/include/c++/v1"); +    addSystemInclude(DriverArgs, CC1Args, P.str()); +    break; +  case llvm::Triple::x86_64: +    llvm::sys::path::append(P, "x86_64-nacl/include/c++/v1"); +    addSystemInclude(DriverArgs, CC1Args, P.str()); +    break; +  case llvm::Triple::mipsel: +    llvm::sys::path::append(P, "mipsel-nacl/include/c++/v1"); +    addSystemInclude(DriverArgs, CC1Args, P.str()); +    break; +  } +} + +ToolChain::CXXStdlibType +NaClToolChain::GetCXXStdlibType(const ArgList &Args) const { +  if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) { +    StringRef Value = A->getValue(); +    if (Value == "libc++") +      return ToolChain::CST_Libcxx; +    getDriver().Diag(clang::diag::err_drv_invalid_stdlib_name) +        << A->getAsString(Args); +  } + +  return ToolChain::CST_Libcxx; +} + +std::string +NaClToolChain::ComputeEffectiveClangTriple(const ArgList &Args, +                                           types::ID InputType) const { +  llvm::Triple TheTriple(ComputeLLVMTriple(Args, InputType)); +  if (TheTriple.getArch() == llvm::Triple::arm && +      TheTriple.getEnvironment() == llvm::Triple::UnknownEnvironment) +    TheTriple.setEnvironment(llvm::Triple::GNUEABIHF); +  return TheTriple.getTriple(); +} + +Tool *NaClToolChain::buildLinker() const { +  return new tools::nacltools::Linker(*this); +} + +Tool *NaClToolChain::buildAssembler() const { +  if (getTriple().getArch() == llvm::Triple::arm) +    return new tools::nacltools::AssemblerARM(*this); +  return new tools::gnutools::Assembler(*this); +} | 
