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