1 //===--- NaCl.cpp - Native Client ToolChain Implementations -----*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "NaCl.h" 10 #include "CommonArgs.h" 11 #include "clang/Driver/Compilation.h" 12 #include "clang/Driver/Driver.h" 13 #include "clang/Driver/DriverDiagnostic.h" 14 #include "clang/Driver/InputInfo.h" 15 #include "clang/Driver/Options.h" 16 #include "llvm/Option/ArgList.h" 17 #include "llvm/Support/Path.h" 18 19 using namespace clang::driver; 20 using namespace clang::driver::tools; 21 using namespace clang::driver::toolchains; 22 using namespace clang; 23 using namespace llvm::opt; 24 25 // NaCl ARM assembly (inline or standalone) can be written with a set of macros 26 // for the various SFI requirements like register masking. The assembly tool 27 // inserts the file containing the macros as an input into all the assembly 28 // jobs. 29 void nacltools::AssemblerARM::ConstructJob(Compilation &C, const JobAction &JA, 30 const InputInfo &Output, 31 const InputInfoList &Inputs, 32 const ArgList &Args, 33 const char *LinkingOutput) const { 34 const auto &ToolChain = static_cast<const NaClToolChain &>(getToolChain()); 35 InputInfo NaClMacros(types::TY_PP_Asm, ToolChain.GetNaClArmMacrosPath(), 36 "nacl-arm-macros.s"); 37 InputInfoList NewInputs; 38 NewInputs.push_back(NaClMacros); 39 NewInputs.append(Inputs.begin(), Inputs.end()); 40 gnutools::Assembler::ConstructJob(C, JA, Output, NewInputs, Args, 41 LinkingOutput); 42 } 43 44 // This is quite similar to gnutools::Linker::ConstructJob with changes that 45 // we use static by default, do not yet support sanitizers or LTO, and a few 46 // others. Eventually we can support more of that and hopefully migrate back 47 // to gnutools::Linker. 48 void nacltools::Linker::ConstructJob(Compilation &C, const JobAction &JA, 49 const InputInfo &Output, 50 const InputInfoList &Inputs, 51 const ArgList &Args, 52 const char *LinkingOutput) const { 53 54 const auto &ToolChain = static_cast<const NaClToolChain &>(getToolChain()); 55 const Driver &D = ToolChain.getDriver(); 56 const llvm::Triple::ArchType Arch = ToolChain.getArch(); 57 const bool IsStatic = 58 !Args.hasArg(options::OPT_dynamic) && !Args.hasArg(options::OPT_shared); 59 60 ArgStringList CmdArgs; 61 62 // Silence warning for "clang -g foo.o -o foo" 63 Args.ClaimAllArgs(options::OPT_g_Group); 64 // and "clang -emit-llvm foo.o -o foo" 65 Args.ClaimAllArgs(options::OPT_emit_llvm); 66 // and for "clang -w foo.o -o foo". Other warning options are already 67 // handled somewhere else. 68 Args.ClaimAllArgs(options::OPT_w); 69 70 if (!D.SysRoot.empty()) 71 CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); 72 73 if (Args.hasArg(options::OPT_rdynamic)) 74 CmdArgs.push_back("-export-dynamic"); 75 76 if (Args.hasArg(options::OPT_s)) 77 CmdArgs.push_back("-s"); 78 79 // NaClToolChain doesn't have ExtraOpts like Linux; the only relevant flag 80 // from there is --build-id, which we do want. 81 CmdArgs.push_back("--build-id"); 82 83 if (!IsStatic) 84 CmdArgs.push_back("--eh-frame-hdr"); 85 86 CmdArgs.push_back("-m"); 87 if (Arch == llvm::Triple::x86) 88 CmdArgs.push_back("elf_i386_nacl"); 89 else if (Arch == llvm::Triple::arm) 90 CmdArgs.push_back("armelf_nacl"); 91 else if (Arch == llvm::Triple::x86_64) 92 CmdArgs.push_back("elf_x86_64_nacl"); 93 else if (Arch == llvm::Triple::mipsel) 94 CmdArgs.push_back("mipselelf_nacl"); 95 else 96 D.Diag(diag::err_target_unsupported_arch) << ToolChain.getArchName() 97 << "Native Client"; 98 99 if (IsStatic) 100 CmdArgs.push_back("-static"); 101 else if (Args.hasArg(options::OPT_shared)) 102 CmdArgs.push_back("-shared"); 103 104 CmdArgs.push_back("-o"); 105 CmdArgs.push_back(Output.getFilename()); 106 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { 107 if (!Args.hasArg(options::OPT_shared)) 108 CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt1.o"))); 109 CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); 110 111 const char *crtbegin; 112 if (IsStatic) 113 crtbegin = "crtbeginT.o"; 114 else if (Args.hasArg(options::OPT_shared)) 115 crtbegin = "crtbeginS.o"; 116 else 117 crtbegin = "crtbegin.o"; 118 CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); 119 } 120 121 Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_u}); 122 123 ToolChain.AddFilePathLibArgs(Args, CmdArgs); 124 125 if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) 126 CmdArgs.push_back("--no-demangle"); 127 128 AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); 129 130 if (D.CCCIsCXX() && 131 !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { 132 if (ToolChain.ShouldLinkCXXStdlib(Args)) { 133 bool OnlyLibstdcxxStatic = 134 Args.hasArg(options::OPT_static_libstdcxx) && !IsStatic; 135 if (OnlyLibstdcxxStatic) 136 CmdArgs.push_back("-Bstatic"); 137 ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); 138 if (OnlyLibstdcxxStatic) 139 CmdArgs.push_back("-Bdynamic"); 140 } 141 CmdArgs.push_back("-lm"); 142 } 143 144 if (!Args.hasArg(options::OPT_nostdlib)) { 145 if (!Args.hasArg(options::OPT_nodefaultlibs)) { 146 // Always use groups, since it has no effect on dynamic libraries. 147 CmdArgs.push_back("--start-group"); 148 CmdArgs.push_back("-lc"); 149 // NaCl's libc++ currently requires libpthread, so just always include it 150 // in the group for C++. 151 if (Args.hasArg(options::OPT_pthread) || 152 Args.hasArg(options::OPT_pthreads) || D.CCCIsCXX()) { 153 // Gold, used by Mips, handles nested groups differently than ld, and 154 // without '-lnacl' it prefers symbols from libpthread.a over libnacl.a, 155 // which is not a desired behaviour here. 156 // See https://sourceware.org/ml/binutils/2015-03/msg00034.html 157 if (getToolChain().getArch() == llvm::Triple::mipsel) 158 CmdArgs.push_back("-lnacl"); 159 160 CmdArgs.push_back("-lpthread"); 161 } 162 163 CmdArgs.push_back("-lgcc"); 164 CmdArgs.push_back("--as-needed"); 165 if (IsStatic) 166 CmdArgs.push_back("-lgcc_eh"); 167 else 168 CmdArgs.push_back("-lgcc_s"); 169 CmdArgs.push_back("--no-as-needed"); 170 171 // Mips needs to create and use pnacl_legacy library that contains 172 // definitions from bitcode/pnaclmm.c and definitions for 173 // __nacl_tp_tls_offset() and __nacl_tp_tdb_offset(). 174 if (getToolChain().getArch() == llvm::Triple::mipsel) 175 CmdArgs.push_back("-lpnacl_legacy"); 176 177 CmdArgs.push_back("--end-group"); 178 } 179 180 if (!Args.hasArg(options::OPT_nostartfiles)) { 181 const char *crtend; 182 if (Args.hasArg(options::OPT_shared)) 183 crtend = "crtendS.o"; 184 else 185 crtend = "crtend.o"; 186 187 CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend))); 188 CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); 189 } 190 } 191 192 const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); 193 C.addCommand(std::make_unique<Command>(JA, *this, 194 ResponseFileSupport::AtFileCurCP(), 195 Exec, CmdArgs, Inputs, Output)); 196 } 197 198 /// NaCl Toolchain 199 NaClToolChain::NaClToolChain(const Driver &D, const llvm::Triple &Triple, 200 const ArgList &Args) 201 : Generic_ELF(D, Triple, Args) { 202 203 // Remove paths added by Generic_GCC. NaCl Toolchain cannot use the 204 // default paths, and must instead only use the paths provided 205 // with this toolchain based on architecture. 206 path_list &file_paths = getFilePaths(); 207 path_list &prog_paths = getProgramPaths(); 208 209 file_paths.clear(); 210 prog_paths.clear(); 211 212 // Path for library files (libc.a, ...) 213 std::string FilePath(getDriver().Dir + "/../"); 214 215 // Path for tools (clang, ld, etc..) 216 std::string ProgPath(getDriver().Dir + "/../"); 217 218 // Path for toolchain libraries (libgcc.a, ...) 219 std::string ToolPath(getDriver().ResourceDir + "/lib/"); 220 221 switch (Triple.getArch()) { 222 case llvm::Triple::x86: 223 file_paths.push_back(FilePath + "x86_64-nacl/lib32"); 224 file_paths.push_back(FilePath + "i686-nacl/usr/lib"); 225 prog_paths.push_back(ProgPath + "x86_64-nacl/bin"); 226 file_paths.push_back(ToolPath + "i686-nacl"); 227 break; 228 case llvm::Triple::x86_64: 229 file_paths.push_back(FilePath + "x86_64-nacl/lib"); 230 file_paths.push_back(FilePath + "x86_64-nacl/usr/lib"); 231 prog_paths.push_back(ProgPath + "x86_64-nacl/bin"); 232 file_paths.push_back(ToolPath + "x86_64-nacl"); 233 break; 234 case llvm::Triple::arm: 235 file_paths.push_back(FilePath + "arm-nacl/lib"); 236 file_paths.push_back(FilePath + "arm-nacl/usr/lib"); 237 prog_paths.push_back(ProgPath + "arm-nacl/bin"); 238 file_paths.push_back(ToolPath + "arm-nacl"); 239 break; 240 case llvm::Triple::mipsel: 241 file_paths.push_back(FilePath + "mipsel-nacl/lib"); 242 file_paths.push_back(FilePath + "mipsel-nacl/usr/lib"); 243 prog_paths.push_back(ProgPath + "bin"); 244 file_paths.push_back(ToolPath + "mipsel-nacl"); 245 break; 246 default: 247 break; 248 } 249 250 NaClArmMacrosPath = GetFilePath("nacl-arm-macros.s"); 251 } 252 253 void NaClToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, 254 ArgStringList &CC1Args) const { 255 const Driver &D = getDriver(); 256 if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc)) 257 return; 258 259 if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { 260 SmallString<128> P(D.ResourceDir); 261 llvm::sys::path::append(P, "include"); 262 addSystemInclude(DriverArgs, CC1Args, P.str()); 263 } 264 265 if (DriverArgs.hasArg(options::OPT_nostdlibinc)) 266 return; 267 268 SmallString<128> P(D.Dir + "/../"); 269 switch (getTriple().getArch()) { 270 case llvm::Triple::x86: 271 // x86 is special because multilib style uses x86_64-nacl/include for libc 272 // headers but the SDK wants i686-nacl/usr/include. The other architectures 273 // have the same substring. 274 llvm::sys::path::append(P, "i686-nacl/usr/include"); 275 addSystemInclude(DriverArgs, CC1Args, P.str()); 276 llvm::sys::path::remove_filename(P); 277 llvm::sys::path::remove_filename(P); 278 llvm::sys::path::remove_filename(P); 279 llvm::sys::path::append(P, "x86_64-nacl/include"); 280 addSystemInclude(DriverArgs, CC1Args, P.str()); 281 return; 282 case llvm::Triple::arm: 283 llvm::sys::path::append(P, "arm-nacl/usr/include"); 284 break; 285 case llvm::Triple::x86_64: 286 llvm::sys::path::append(P, "x86_64-nacl/usr/include"); 287 break; 288 case llvm::Triple::mipsel: 289 llvm::sys::path::append(P, "mipsel-nacl/usr/include"); 290 break; 291 default: 292 return; 293 } 294 295 addSystemInclude(DriverArgs, CC1Args, P.str()); 296 llvm::sys::path::remove_filename(P); 297 llvm::sys::path::remove_filename(P); 298 llvm::sys::path::append(P, "include"); 299 addSystemInclude(DriverArgs, CC1Args, P.str()); 300 } 301 302 void NaClToolChain::AddCXXStdlibLibArgs(const ArgList &Args, 303 ArgStringList &CmdArgs) const { 304 // Check for -stdlib= flags. We only support libc++ but this consumes the arg 305 // if the value is libc++, and emits an error for other values. 306 GetCXXStdlibType(Args); 307 CmdArgs.push_back("-lc++"); 308 if (Args.hasArg(options::OPT_fexperimental_library)) 309 CmdArgs.push_back("-lc++experimental"); 310 } 311 312 void NaClToolChain::addLibCxxIncludePaths( 313 const llvm::opt::ArgList &DriverArgs, 314 llvm::opt::ArgStringList &CC1Args) const { 315 const Driver &D = getDriver(); 316 317 SmallString<128> P(D.Dir + "/../"); 318 switch (getTriple().getArch()) { 319 default: 320 break; 321 case llvm::Triple::arm: 322 llvm::sys::path::append(P, "arm-nacl/include/c++/v1"); 323 addSystemInclude(DriverArgs, CC1Args, P.str()); 324 break; 325 case llvm::Triple::x86: 326 llvm::sys::path::append(P, "x86_64-nacl/include/c++/v1"); 327 addSystemInclude(DriverArgs, CC1Args, P.str()); 328 break; 329 case llvm::Triple::x86_64: 330 llvm::sys::path::append(P, "x86_64-nacl/include/c++/v1"); 331 addSystemInclude(DriverArgs, CC1Args, P.str()); 332 break; 333 case llvm::Triple::mipsel: 334 llvm::sys::path::append(P, "mipsel-nacl/include/c++/v1"); 335 addSystemInclude(DriverArgs, CC1Args, P.str()); 336 break; 337 } 338 } 339 340 ToolChain::CXXStdlibType 341 NaClToolChain::GetCXXStdlibType(const ArgList &Args) const { 342 if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) { 343 StringRef Value = A->getValue(); 344 if (Value == "libc++") 345 return ToolChain::CST_Libcxx; 346 getDriver().Diag(clang::diag::err_drv_invalid_stdlib_name) 347 << A->getAsString(Args); 348 } 349 350 return ToolChain::CST_Libcxx; 351 } 352 353 std::string 354 NaClToolChain::ComputeEffectiveClangTriple(const ArgList &Args, 355 types::ID InputType) const { 356 llvm::Triple TheTriple(ComputeLLVMTriple(Args, InputType)); 357 if (TheTriple.getArch() == llvm::Triple::arm && 358 TheTriple.getEnvironment() == llvm::Triple::UnknownEnvironment) 359 TheTriple.setEnvironment(llvm::Triple::GNUEABIHF); 360 return TheTriple.getTriple(); 361 } 362 363 Tool *NaClToolChain::buildLinker() const { 364 return new tools::nacltools::Linker(*this); 365 } 366 367 Tool *NaClToolChain::buildAssembler() const { 368 if (getTriple().getArch() == llvm::Triple::arm) 369 return new tools::nacltools::AssemblerARM(*this); 370 return new tools::gnutools::Assembler(*this); 371 } 372