1 //===--- PS4CPU.cpp - PS4CPU ToolChain Implementations ----------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "PS4CPU.h" 11 #include "FreeBSD.h" 12 #include "CommonArgs.h" 13 #include "clang/Driver/Compilation.h" 14 #include "clang/Driver/Driver.h" 15 #include "clang/Driver/DriverDiagnostic.h" 16 #include "clang/Driver/Options.h" 17 #include "clang/Driver/SanitizerArgs.h" 18 #include "llvm/Option/ArgList.h" 19 #include "llvm/Support/FileSystem.h" 20 #include "llvm/Support/Path.h" 21 #include <cstdlib> // ::getenv 22 23 using namespace clang::driver; 24 using namespace clang; 25 using namespace llvm::opt; 26 27 using clang::driver::tools::AddLinkerInputs; 28 29 void tools::PS4cpu::addProfileRTArgs(const ToolChain &TC, const ArgList &Args, 30 ArgStringList &CmdArgs) { 31 if ((Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs, 32 false) || 33 Args.hasFlag(options::OPT_fprofile_generate, 34 options::OPT_fno_profile_instr_generate, false) || 35 Args.hasFlag(options::OPT_fprofile_generate_EQ, 36 options::OPT_fno_profile_instr_generate, false) || 37 Args.hasFlag(options::OPT_fprofile_instr_generate, 38 options::OPT_fno_profile_instr_generate, false) || 39 Args.hasFlag(options::OPT_fprofile_instr_generate_EQ, 40 options::OPT_fno_profile_instr_generate, false) || 41 Args.hasArg(options::OPT_fcreate_profile) || 42 Args.hasArg(options::OPT_coverage))) 43 CmdArgs.push_back("--dependent-lib=libclang_rt.profile-x86_64.a"); 44 } 45 46 void tools::PS4cpu::Assemble::ConstructJob(Compilation &C, const JobAction &JA, 47 const InputInfo &Output, 48 const InputInfoList &Inputs, 49 const ArgList &Args, 50 const char *LinkingOutput) const { 51 claimNoWarnArgs(Args); 52 ArgStringList CmdArgs; 53 54 Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); 55 56 CmdArgs.push_back("-o"); 57 CmdArgs.push_back(Output.getFilename()); 58 59 assert(Inputs.size() == 1 && "Unexpected number of inputs."); 60 const InputInfo &Input = Inputs[0]; 61 assert(Input.isFilename() && "Invalid input."); 62 CmdArgs.push_back(Input.getFilename()); 63 64 const char *Exec = 65 Args.MakeArgString(getToolChain().GetProgramPath("orbis-as")); 66 C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); 67 } 68 69 static void AddPS4SanitizerArgs(const ToolChain &TC, ArgStringList &CmdArgs) { 70 const SanitizerArgs &SanArgs = TC.getSanitizerArgs(); 71 if (SanArgs.needsUbsanRt()) { 72 CmdArgs.push_back("-lSceDbgUBSanitizer_stub_weak"); 73 } 74 if (SanArgs.needsAsanRt()) { 75 CmdArgs.push_back("-lSceDbgAddressSanitizer_stub_weak"); 76 } 77 } 78 79 static void ConstructPS4LinkJob(const Tool &T, Compilation &C, 80 const JobAction &JA, const InputInfo &Output, 81 const InputInfoList &Inputs, 82 const ArgList &Args, 83 const char *LinkingOutput) { 84 const toolchains::FreeBSD &ToolChain = 85 static_cast<const toolchains::FreeBSD &>(T.getToolChain()); 86 const Driver &D = ToolChain.getDriver(); 87 ArgStringList CmdArgs; 88 89 // Silence warning for "clang -g foo.o -o foo" 90 Args.ClaimAllArgs(options::OPT_g_Group); 91 // and "clang -emit-llvm foo.o -o foo" 92 Args.ClaimAllArgs(options::OPT_emit_llvm); 93 // and for "clang -w foo.o -o foo". Other warning options are already 94 // handled somewhere else. 95 Args.ClaimAllArgs(options::OPT_w); 96 97 if (!D.SysRoot.empty()) 98 CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); 99 100 if (Args.hasArg(options::OPT_pie)) 101 CmdArgs.push_back("-pie"); 102 103 if (Args.hasArg(options::OPT_rdynamic)) 104 CmdArgs.push_back("-export-dynamic"); 105 if (Args.hasArg(options::OPT_shared)) 106 CmdArgs.push_back("--oformat=so"); 107 108 if (Output.isFilename()) { 109 CmdArgs.push_back("-o"); 110 CmdArgs.push_back(Output.getFilename()); 111 } else { 112 assert(Output.isNothing() && "Invalid output."); 113 } 114 115 AddPS4SanitizerArgs(ToolChain, CmdArgs); 116 117 Args.AddAllArgs(CmdArgs, options::OPT_L); 118 Args.AddAllArgs(CmdArgs, options::OPT_T_Group); 119 Args.AddAllArgs(CmdArgs, options::OPT_e); 120 Args.AddAllArgs(CmdArgs, options::OPT_s); 121 Args.AddAllArgs(CmdArgs, options::OPT_t); 122 Args.AddAllArgs(CmdArgs, options::OPT_r); 123 124 if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) 125 CmdArgs.push_back("--no-demangle"); 126 127 AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); 128 129 if (Args.hasArg(options::OPT_pthread)) { 130 CmdArgs.push_back("-lpthread"); 131 } 132 133 const char *Exec = Args.MakeArgString(ToolChain.GetProgramPath("orbis-ld")); 134 135 C.addCommand(llvm::make_unique<Command>(JA, T, Exec, CmdArgs, Inputs)); 136 } 137 138 static void ConstructGoldLinkJob(const Tool &T, Compilation &C, 139 const JobAction &JA, const InputInfo &Output, 140 const InputInfoList &Inputs, 141 const ArgList &Args, 142 const char *LinkingOutput) { 143 const toolchains::FreeBSD &ToolChain = 144 static_cast<const toolchains::FreeBSD &>(T.getToolChain()); 145 const Driver &D = ToolChain.getDriver(); 146 ArgStringList CmdArgs; 147 148 // Silence warning for "clang -g foo.o -o foo" 149 Args.ClaimAllArgs(options::OPT_g_Group); 150 // and "clang -emit-llvm foo.o -o foo" 151 Args.ClaimAllArgs(options::OPT_emit_llvm); 152 // and for "clang -w foo.o -o foo". Other warning options are already 153 // handled somewhere else. 154 Args.ClaimAllArgs(options::OPT_w); 155 156 if (!D.SysRoot.empty()) 157 CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); 158 159 if (Args.hasArg(options::OPT_pie)) 160 CmdArgs.push_back("-pie"); 161 162 if (Args.hasArg(options::OPT_static)) { 163 CmdArgs.push_back("-Bstatic"); 164 } else { 165 if (Args.hasArg(options::OPT_rdynamic)) 166 CmdArgs.push_back("-export-dynamic"); 167 CmdArgs.push_back("--eh-frame-hdr"); 168 if (Args.hasArg(options::OPT_shared)) { 169 CmdArgs.push_back("-Bshareable"); 170 } else { 171 CmdArgs.push_back("-dynamic-linker"); 172 CmdArgs.push_back("/libexec/ld-elf.so.1"); 173 } 174 CmdArgs.push_back("--enable-new-dtags"); 175 } 176 177 if (Output.isFilename()) { 178 CmdArgs.push_back("-o"); 179 CmdArgs.push_back(Output.getFilename()); 180 } else { 181 assert(Output.isNothing() && "Invalid output."); 182 } 183 184 AddPS4SanitizerArgs(ToolChain, CmdArgs); 185 186 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { 187 const char *crt1 = nullptr; 188 if (!Args.hasArg(options::OPT_shared)) { 189 if (Args.hasArg(options::OPT_pg)) 190 crt1 = "gcrt1.o"; 191 else if (Args.hasArg(options::OPT_pie)) 192 crt1 = "Scrt1.o"; 193 else 194 crt1 = "crt1.o"; 195 } 196 if (crt1) 197 CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt1))); 198 199 CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); 200 201 const char *crtbegin = nullptr; 202 if (Args.hasArg(options::OPT_static)) 203 crtbegin = "crtbeginT.o"; 204 else if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) 205 crtbegin = "crtbeginS.o"; 206 else 207 crtbegin = "crtbegin.o"; 208 209 CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); 210 } 211 212 Args.AddAllArgs(CmdArgs, options::OPT_L); 213 ToolChain.AddFilePathLibArgs(Args, CmdArgs); 214 Args.AddAllArgs(CmdArgs, options::OPT_T_Group); 215 Args.AddAllArgs(CmdArgs, options::OPT_e); 216 Args.AddAllArgs(CmdArgs, options::OPT_s); 217 Args.AddAllArgs(CmdArgs, options::OPT_t); 218 Args.AddAllArgs(CmdArgs, options::OPT_r); 219 220 if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) 221 CmdArgs.push_back("--no-demangle"); 222 223 AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); 224 225 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { 226 // For PS4, we always want to pass libm, libstdc++ and libkernel 227 // libraries for both C and C++ compilations. 228 CmdArgs.push_back("-lkernel"); 229 if (D.CCCIsCXX()) { 230 if (ToolChain.ShouldLinkCXXStdlib(Args)) 231 ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); 232 if (Args.hasArg(options::OPT_pg)) 233 CmdArgs.push_back("-lm_p"); 234 else 235 CmdArgs.push_back("-lm"); 236 } 237 // FIXME: For some reason GCC passes -lgcc and -lgcc_s before adding 238 // the default system libraries. Just mimic this for now. 239 if (Args.hasArg(options::OPT_pg)) 240 CmdArgs.push_back("-lgcc_p"); 241 else 242 CmdArgs.push_back("-lcompiler_rt"); 243 if (Args.hasArg(options::OPT_static)) { 244 CmdArgs.push_back("-lstdc++"); 245 } else if (Args.hasArg(options::OPT_pg)) { 246 CmdArgs.push_back("-lgcc_eh_p"); 247 } else { 248 CmdArgs.push_back("--as-needed"); 249 CmdArgs.push_back("-lstdc++"); 250 CmdArgs.push_back("--no-as-needed"); 251 } 252 253 if (Args.hasArg(options::OPT_pthread)) { 254 if (Args.hasArg(options::OPT_pg)) 255 CmdArgs.push_back("-lpthread_p"); 256 else 257 CmdArgs.push_back("-lpthread"); 258 } 259 260 if (Args.hasArg(options::OPT_pg)) { 261 if (Args.hasArg(options::OPT_shared)) 262 CmdArgs.push_back("-lc"); 263 else { 264 if (Args.hasArg(options::OPT_static)) { 265 CmdArgs.push_back("--start-group"); 266 CmdArgs.push_back("-lc_p"); 267 CmdArgs.push_back("-lpthread_p"); 268 CmdArgs.push_back("--end-group"); 269 } else { 270 CmdArgs.push_back("-lc_p"); 271 } 272 } 273 CmdArgs.push_back("-lgcc_p"); 274 } else { 275 if (Args.hasArg(options::OPT_static)) { 276 CmdArgs.push_back("--start-group"); 277 CmdArgs.push_back("-lc"); 278 CmdArgs.push_back("-lpthread"); 279 CmdArgs.push_back("--end-group"); 280 } else { 281 CmdArgs.push_back("-lc"); 282 } 283 CmdArgs.push_back("-lcompiler_rt"); 284 } 285 286 if (Args.hasArg(options::OPT_static)) { 287 CmdArgs.push_back("-lstdc++"); 288 } else if (Args.hasArg(options::OPT_pg)) { 289 CmdArgs.push_back("-lgcc_eh_p"); 290 } else { 291 CmdArgs.push_back("--as-needed"); 292 CmdArgs.push_back("-lstdc++"); 293 CmdArgs.push_back("--no-as-needed"); 294 } 295 } 296 297 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { 298 if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) 299 CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtendS.o"))); 300 else 301 CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o"))); 302 CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); 303 } 304 305 const char *Exec = 306 #ifdef LLVM_ON_WIN32 307 Args.MakeArgString(ToolChain.GetProgramPath("orbis-ld.gold")); 308 #else 309 Args.MakeArgString(ToolChain.GetProgramPath("orbis-ld")); 310 #endif 311 312 C.addCommand(llvm::make_unique<Command>(JA, T, Exec, CmdArgs, Inputs)); 313 } 314 315 void tools::PS4cpu::Link::ConstructJob(Compilation &C, const JobAction &JA, 316 const InputInfo &Output, 317 const InputInfoList &Inputs, 318 const ArgList &Args, 319 const char *LinkingOutput) const { 320 const toolchains::FreeBSD &ToolChain = 321 static_cast<const toolchains::FreeBSD &>(getToolChain()); 322 const Driver &D = ToolChain.getDriver(); 323 bool PS4Linker; 324 StringRef LinkerOptName; 325 if (const Arg *A = Args.getLastArg(options::OPT_fuse_ld_EQ)) { 326 LinkerOptName = A->getValue(); 327 if (LinkerOptName != "ps4" && LinkerOptName != "gold") 328 D.Diag(diag::err_drv_unsupported_linker) << LinkerOptName; 329 } 330 331 if (LinkerOptName == "gold") 332 PS4Linker = false; 333 else if (LinkerOptName == "ps4") 334 PS4Linker = true; 335 else 336 PS4Linker = !Args.hasArg(options::OPT_shared); 337 338 if (PS4Linker) 339 ConstructPS4LinkJob(*this, C, JA, Output, Inputs, Args, LinkingOutput); 340 else 341 ConstructGoldLinkJob(*this, C, JA, Output, Inputs, Args, LinkingOutput); 342 } 343 344 toolchains::PS4CPU::PS4CPU(const Driver &D, const llvm::Triple &Triple, 345 const ArgList &Args) 346 : Generic_ELF(D, Triple, Args) { 347 if (Args.hasArg(clang::driver::options::OPT_static)) 348 D.Diag(clang::diag::err_drv_unsupported_opt_for_target) << "-static" 349 << "PS4"; 350 351 // Determine where to find the PS4 libraries. We use SCE_ORBIS_SDK_DIR 352 // if it exists; otherwise use the driver's installation path, which 353 // should be <SDK_DIR>/host_tools/bin. 354 355 SmallString<512> PS4SDKDir; 356 if (const char *EnvValue = getenv("SCE_ORBIS_SDK_DIR")) { 357 if (!llvm::sys::fs::exists(EnvValue)) 358 getDriver().Diag(clang::diag::warn_drv_ps4_sdk_dir) << EnvValue; 359 PS4SDKDir = EnvValue; 360 } else { 361 PS4SDKDir = getDriver().Dir; 362 llvm::sys::path::append(PS4SDKDir, "/../../"); 363 } 364 365 // By default, the driver won't report a warning if it can't find 366 // PS4's include or lib directories. This behavior could be changed if 367 // -Weverything or -Winvalid-or-nonexistent-directory options are passed. 368 // If -isysroot was passed, use that as the SDK base path. 369 std::string PrefixDir; 370 if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { 371 PrefixDir = A->getValue(); 372 if (!llvm::sys::fs::exists(PrefixDir)) 373 getDriver().Diag(clang::diag::warn_missing_sysroot) << PrefixDir; 374 } else 375 PrefixDir = PS4SDKDir.str(); 376 377 SmallString<512> PS4SDKIncludeDir(PrefixDir); 378 llvm::sys::path::append(PS4SDKIncludeDir, "target/include"); 379 if (!Args.hasArg(options::OPT_nostdinc) && 380 !Args.hasArg(options::OPT_nostdlibinc) && 381 !Args.hasArg(options::OPT_isysroot) && 382 !Args.hasArg(options::OPT__sysroot_EQ) && 383 !llvm::sys::fs::exists(PS4SDKIncludeDir)) { 384 getDriver().Diag(clang::diag::warn_drv_unable_to_find_directory_expected) 385 << "PS4 system headers" << PS4SDKIncludeDir; 386 } 387 388 SmallString<512> PS4SDKLibDir(PS4SDKDir); 389 llvm::sys::path::append(PS4SDKLibDir, "target/lib"); 390 if (!Args.hasArg(options::OPT_nostdlib) && 391 !Args.hasArg(options::OPT_nodefaultlibs) && 392 !Args.hasArg(options::OPT__sysroot_EQ) && !Args.hasArg(options::OPT_E) && 393 !Args.hasArg(options::OPT_c) && !Args.hasArg(options::OPT_S) && 394 !Args.hasArg(options::OPT_emit_ast) && 395 !llvm::sys::fs::exists(PS4SDKLibDir)) { 396 getDriver().Diag(clang::diag::warn_drv_unable_to_find_directory_expected) 397 << "PS4 system libraries" << PS4SDKLibDir; 398 return; 399 } 400 getFilePaths().push_back(PS4SDKLibDir.str()); 401 } 402 403 Tool *toolchains::PS4CPU::buildAssembler() const { 404 return new tools::PS4cpu::Assemble(*this); 405 } 406 407 Tool *toolchains::PS4CPU::buildLinker() const { 408 return new tools::PS4cpu::Link(*this); 409 } 410 411 bool toolchains::PS4CPU::isPICDefault() const { return true; } 412 413 bool toolchains::PS4CPU::HasNativeLLVMSupport() const { return true; } 414 415 SanitizerMask toolchains::PS4CPU::getSupportedSanitizers() const { 416 SanitizerMask Res = ToolChain::getSupportedSanitizers(); 417 Res |= SanitizerKind::Address; 418 Res |= SanitizerKind::Vptr; 419 return Res; 420 } 421