166 changes: 166 additions & 0 deletions clang/lib/Driver/Tools.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7911,6 +7911,172 @@ void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA,
llvm::make_unique<Command>(JA, *this, ToolChain.Linker.c_str(), CmdArgs));
}


// 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::AssembleARM::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
const toolchains::NaCl_TC& ToolChain =
static_cast<const toolchains::NaCl_TC&>(getToolChain());
InputInfo NaClMacros(ToolChain.GetNaClArmMacrosPath(), types::TY_PP_Asm,
"nacl-arm-macros.s");
InputInfoList NewInputs;
NewInputs.push_back(NaClMacros);
NewInputs.append(Inputs.begin(), Inputs.end());
gnutools::Assemble::ConstructJob(C, JA, Output, NewInputs, Args,
LinkingOutput);
}


// This is quite similar to gnutools::link::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::link.
void nacltools::Link::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {

const toolchains::NaCl_TC& ToolChain =
static_cast<const toolchains::NaCl_TC&>(getToolChain());
const Driver &D = ToolChain.getDriver();
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");

// NaCl_TC 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 (ToolChain.getArch() == llvm::Triple::x86)
CmdArgs.push_back("elf_i386_nacl");
else if (ToolChain.getArch() == llvm::Triple::arm)
CmdArgs.push_back("armelf_nacl");
else if (ToolChain.getArch() == llvm::Triple::x86_64)
CmdArgs.push_back("elf_x86_64_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) &&
!Args.hasArg(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);

const ToolChain::path_list &Paths = ToolChain.getFilePaths();

for (const auto &Path : Paths)
CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + Path));

if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle))
CmdArgs.push_back("--no-demangle");

AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs);

if (D.CCCIsCXX() &&
!Args.hasArg(options::OPT_nostdlib) &&
!Args.hasArg(options::OPT_nodefaultlibs)) {
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()) {
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");
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")));
}
}

C.addCommand(llvm::make_unique<Command>(JA, *this,
ToolChain.Linker.c_str(), CmdArgs));
}


void minix::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
Expand Down
27 changes: 27 additions & 0 deletions clang/lib/Driver/Tools.h
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,33 @@ namespace gnutools {
const char *LinkingOutput) const override;
};
}

namespace nacltools {
class LLVM_LIBRARY_VISIBILITY AssembleARM : public gnutools::Assemble {
public:
AssembleARM(const ToolChain &TC) : gnutools::Assemble(TC) {}

void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
};
class LLVM_LIBRARY_VISIBILITY Link : public Tool {
public:
Link(const ToolChain &TC) : Tool("NaCl::Link", "linker", TC) {}

bool hasIntegratedCPP() const override { return false; }
bool isLinkJob() const override { return true; }

void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
};
}

/// minix -- Directly call GNU Binutils assembler and linker
namespace minix {
class LLVM_LIBRARY_VISIBILITY Assemble : public GnuTool {
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Frontend/InitHeaderSearch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
case llvm::Triple::NetBSD:
case llvm::Triple::OpenBSD:
case llvm::Triple::Bitrig:
case llvm::Triple::NaCl:
break;
default:
// FIXME: temporary hack: hard-coded paths.
Expand Down Expand Up @@ -352,6 +353,7 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
switch (os) {
case llvm::Triple::CloudABI:
case llvm::Triple::RTEMS:
case llvm::Triple::NaCl:
break;
default:
AddPath("/usr/include", ExternCSystem, false);
Expand Down
2 changes: 1 addition & 1 deletion clang/test/CodeGen/target-data.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
// RUN: FileCheck %s -check-prefix=X86_64-NACL
// X86_64-NACL: target datalayout = "e-m:e-p:32:32-i64:64-n8:16:32:64-S128"

// RUN: %clang_cc1 -triple arm-nacl-gnueabi -o - -emit-llvm %s | \
// RUN: %clang_cc1 -triple arm-nacl -o - -emit-llvm %s | \
// RUN: FileCheck %s -check-prefix=ARM-NACL
// ARM-NACL: target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S128"

Expand Down
108 changes: 108 additions & 0 deletions clang/test/Driver/nacl-direct.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// Test clang changes for NaCl Support including:
// include paths, library paths, emulation, default static
//
// RUN: %clang -### -o %t.o %s 2>&1 \
// RUN: -target i686-unknown-nacl \
// RUN: | FileCheck --check-prefix=CHECK-I686 %s
// CHECK-I686: {{.*}}clang{{.*}}" "-cc1"
// CHECK-I686: "-fuse-init-array"
// CHECK-I686: "-target-cpu" "pentium4"
// CHECK-I686: "-resource-dir" "{{.*}}/lib/clang/[[VER:[0-9.]+]]"
// CHECK-I686: "-internal-isystem" "{{.*}}/../lib/clang/[[VER]]/include"
// CHECK-I686: "-internal-isystem" "{{.*}}/../x86_64-nacl/usr/include"
// CHECK-I686: "-internal-isystem" "{{.*}}/../x86_64-nacl/include"
// CHECK-I686: /as" "--32"
// CHECK-I686: /ld"
// CHECK-I686: "--build-id"
// CHECK-I686: "-m" "elf_i386_nacl"
// CHECK-I686: "-static"
// CHECK-I686: "-L{{.*}}/../x86_64-nacl/lib32"
// CHECK-I686: "-L{{.*}}/../x86_64-nacl/usr/lib32"
// CHECK-I686: "-L{{.*}}/../lib/clang/[[VER]]/lib/i686-nacl"
// CHECK-I686-NOT: -lpthread
//
// RUN: %clang -### -o %t.o %s 2>&1 \
// RUN: -target x86_64-unknown-nacl \
// RUN: | FileCheck --check-prefix=CHECK-x86_64 %s
// CHECK-x86_64: {{.*}}clang{{.*}}" "-cc1"
// CHECK-x86_64: "-fuse-init-array"
// CHECK-x86_64: "-target-cpu" "x86-64"
// CHECK-x86_64: "-resource-dir" "{{.*}}/lib/clang/[[VER:[0-9.]+]]"
// CHECK-x86_64: "-internal-isystem" "{{.*}}/../lib/clang/[[VER]]/include"
// CHECK-x86_64: "-internal-isystem" "{{.*}}/../x86_64-nacl/usr/include"
// CHECK-x86_64: "-internal-isystem" "{{.*}}/../x86_64-nacl/include"
// CHECK-x86_64: /as" "--64"
// CHECK-x86_64: /ld"
// CHECK-x86_64: "--build-id"
// CHECK-x86_64: "-m" "elf_x86_64_nacl"
// CHECK-x86_64: "-static"
// CHECK-x86_64: "-L{{.*}}/../x86_64-nacl/lib"
// CHECK-x86_64: "-L{{.*}}/../x86_64-nacl/usr/lib"
// CHECK-x86_64: "-L{{.*}}/../lib/clang/[[VER]]/lib/x86_64-nacl"
// CHECK-X86_64-NOT: -lpthread
//
// RUN: %clang -### -o %t.o %s 2>&1 \
// RUN: -target armv7a-unknown-nacl-gnueabihf \
// RUN: | FileCheck --check-prefix=CHECK-ARM %s
// CHECK-ARM: {{.*}}clang{{.*}}" "-cc1"
// CHECK-ARM: "-fuse-init-array"
// CHECK-ARM: "-target-cpu" "cortex-a8"
// CHECK-ARM: "-target-abi" "aapcs-linux"
// CHECK-ARM: "-mfloat-abi" "hard"
// CHECK-ARM: "-resource-dir" "{{.*}}/lib/clang/[[VER:[0-9.]+]]"
// CHECK-ARM: "-internal-isystem" "{{.*}}/../lib/clang/[[VER]]/include"
// CHECK-ARM: "-internal-isystem" "{{.*}}/../arm-nacl/usr/include"
// CHECK-ARM: "-internal-isystem" "{{.*}}/../arm-nacl/include"
// CHECK-ARM: /as"
// CHECK-ARM: /ld"
// CHECK-ARM: "--build-id"
// CHECK-ARM: "-m" "armelf_nacl"
// CHECK-ARM: "-static"
// CHECK-ARM: "-L{{.*}}/../arm-nacl/lib"
// CHECK-ARM: "-L{{.*}}/../arm-nacl/usr/lib"
// CHECK-ARM: "-L{{.*}}/../lib/clang/[[VER]]/lib/arm-nacl"
// CHECK-ARM-NOT: -lpthread

// Check that even when the target arch is just "arm" (as will be the case when
// it is inferred from the binary name) that we get the right ABI flags
// RUN: %clang -### -o %t.o %s 2>&1 \
// RUN: -target arm-nacl \
// RUN: | FileCheck --check-prefix=CHECK-ARM-NOV7 %s
// CHECK-ARM-NOV7: "-triple" "armv7--nacl-gnueabihf"
// CHECK-ARM-NOV7: "-target-abi" "aapcs-linux"
// CHECK-ARM-NOV7: "-mfloat-abi" "hard"

// Test clang c++ include dirs and link line when using clang++

// RUN: %clangxx -### -o %t.o %s 2>&1 \
// RUN: -target armv7a-unknown-nacl-gnueabihf \
// RUN: | FileCheck --check-prefix=CHECK-ARM-CXX %s
// CHECK-ARM-CXX: {{.*}}clang{{.*}}" "-cc1"
// CHECK-ARM-CXX: "-resource-dir" "{{.*}}/lib/clang/[[VER:[0-9.]+]]"
// CHECK-ARM-CXX: "-internal-isystem" "{{.*}}/../arm-nacl/include/c++/v1"
// CHECK-ARM-CXX: "-internal-isystem" "{{.*}}/../lib/clang/[[VER]]/include"
// CHECK-ARM-CXX: "-internal-isystem" "{{.*}}/../arm-nacl/usr/include"
// CHECK-ARM-CXX: "-internal-isystem" "{{.*}}/../arm-nacl/include"
// CHECK-ARM-CXX: "-lpthread"

// RUN: %clangxx -### -o %t.o %s 2>&1 \
// RUN: -target i686-unknown-nacl \
// RUN: | FileCheck --check-prefix=CHECK-I686-CXX %s
// CHECK-I686-CXX: {{.*}}clang{{.*}}" "-cc1"
// CHECK-I686-CXX: "-resource-dir" "{{.*}}/lib/clang/[[VER:[0-9.]+]]"
// CHECK-I686-CXX: "-internal-isystem" "{{.*}}/../x86_64-nacl/include/c++/v1"
// CHECK-I686-CXX: "-internal-isystem" "{{.*}}/../lib/clang/[[VER]]/include"
// CHECK-I686-CXX: "-internal-isystem" "{{.*}}/../x86_64-nacl/usr/include"
// CHECK-I686-CXX: "-internal-isystem" "{{.*}}/../x86_64-nacl/include"
// CHECK-I686-CXX: "-lpthread"

// RUN: %clangxx -### -o %t.o %s 2>&1 \
// RUN: -target x86_64-unknown-nacl \
// RUN: | FileCheck --check-prefix=CHECK-x86_64-CXX %s
// CHECK-x86_64-CXX: {{.*}}clang{{.*}}" "-cc1"
// CHECK-x86_64-CXX: "-resource-dir" "{{.*}}/lib/clang/[[VER:[0-9.]+]]"
// CHECK-x86_64-CXX: "-internal-isystem" "{{.*}}/../x86_64-nacl/include/c++/v1"
// CHECK-x86_64-CXX: "-internal-isystem" "{{.*}}/../lib/clang/[[VER]]/include"
// CHECK-x86_64-CXX: "-internal-isystem" "{{.*}}/../x86_64-nacl/usr/include"
// CHECK-x86_64-CXX: "-internal-isystem" "{{.*}}/../x86_64-nacl/include"
// CHECK-x86_64-CXX: "-lpthread"