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 ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); 231 if (Args.hasArg(options::OPT_pg)) 232 CmdArgs.push_back("-lm_p"); 233 else 234 CmdArgs.push_back("-lm"); 235 } 236 // FIXME: For some reason GCC passes -lgcc and -lgcc_s before adding 237 // the default system libraries. Just mimic this for now. 238 if (Args.hasArg(options::OPT_pg)) 239 CmdArgs.push_back("-lgcc_p"); 240 else 241 CmdArgs.push_back("-lcompiler_rt"); 242 if (Args.hasArg(options::OPT_static)) { 243 CmdArgs.push_back("-lstdc++"); 244 } else if (Args.hasArg(options::OPT_pg)) { 245 CmdArgs.push_back("-lgcc_eh_p"); 246 } else { 247 CmdArgs.push_back("--as-needed"); 248 CmdArgs.push_back("-lstdc++"); 249 CmdArgs.push_back("--no-as-needed"); 250 } 251 252 if (Args.hasArg(options::OPT_pthread)) { 253 if (Args.hasArg(options::OPT_pg)) 254 CmdArgs.push_back("-lpthread_p"); 255 else 256 CmdArgs.push_back("-lpthread"); 257 } 258 259 if (Args.hasArg(options::OPT_pg)) { 260 if (Args.hasArg(options::OPT_shared)) 261 CmdArgs.push_back("-lc"); 262 else { 263 if (Args.hasArg(options::OPT_static)) { 264 CmdArgs.push_back("--start-group"); 265 CmdArgs.push_back("-lc_p"); 266 CmdArgs.push_back("-lpthread_p"); 267 CmdArgs.push_back("--end-group"); 268 } else { 269 CmdArgs.push_back("-lc_p"); 270 } 271 } 272 CmdArgs.push_back("-lgcc_p"); 273 } else { 274 if (Args.hasArg(options::OPT_static)) { 275 CmdArgs.push_back("--start-group"); 276 CmdArgs.push_back("-lc"); 277 CmdArgs.push_back("-lpthread"); 278 CmdArgs.push_back("--end-group"); 279 } else { 280 CmdArgs.push_back("-lc"); 281 } 282 CmdArgs.push_back("-lcompiler_rt"); 283 } 284 285 if (Args.hasArg(options::OPT_static)) { 286 CmdArgs.push_back("-lstdc++"); 287 } else if (Args.hasArg(options::OPT_pg)) { 288 CmdArgs.push_back("-lgcc_eh_p"); 289 } else { 290 CmdArgs.push_back("--as-needed"); 291 CmdArgs.push_back("-lstdc++"); 292 CmdArgs.push_back("--no-as-needed"); 293 } 294 } 295 296 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { 297 if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) 298 CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtendS.o"))); 299 else 300 CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o"))); 301 CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); 302 } 303 304 const char *Exec = 305 #ifdef LLVM_ON_WIN32 306 Args.MakeArgString(ToolChain.GetProgramPath("orbis-ld.gold")); 307 #else 308 Args.MakeArgString(ToolChain.GetProgramPath("orbis-ld")); 309 #endif 310 311 C.addCommand(llvm::make_unique<Command>(JA, T, Exec, CmdArgs, Inputs)); 312 } 313 314 void tools::PS4cpu::Link::ConstructJob(Compilation &C, const JobAction &JA, 315 const InputInfo &Output, 316 const InputInfoList &Inputs, 317 const ArgList &Args, 318 const char *LinkingOutput) const { 319 const toolchains::FreeBSD &ToolChain = 320 static_cast<const toolchains::FreeBSD &>(getToolChain()); 321 const Driver &D = ToolChain.getDriver(); 322 bool PS4Linker; 323 StringRef LinkerOptName; 324 if (const Arg *A = Args.getLastArg(options::OPT_fuse_ld_EQ)) { 325 LinkerOptName = A->getValue(); 326 if (LinkerOptName != "ps4" && LinkerOptName != "gold") 327 D.Diag(diag::err_drv_unsupported_linker) << LinkerOptName; 328 } 329 330 if (LinkerOptName == "gold") 331 PS4Linker = false; 332 else if (LinkerOptName == "ps4") 333 PS4Linker = true; 334 else 335 PS4Linker = !Args.hasArg(options::OPT_shared); 336 337 if (PS4Linker) 338 ConstructPS4LinkJob(*this, C, JA, Output, Inputs, Args, LinkingOutput); 339 else 340 ConstructGoldLinkJob(*this, C, JA, Output, Inputs, Args, LinkingOutput); 341 } 342 343 toolchains::PS4CPU::PS4CPU(const Driver &D, const llvm::Triple &Triple, 344 const ArgList &Args) 345 : Generic_ELF(D, Triple, Args) { 346 if (Args.hasArg(clang::driver::options::OPT_static)) 347 D.Diag(clang::diag::err_drv_unsupported_opt_for_target) << "-static" 348 << "PS4"; 349 350 // Determine where to find the PS4 libraries. We use SCE_ORBIS_SDK_DIR 351 // if it exists; otherwise use the driver's installation path, which 352 // should be <SDK_DIR>/host_tools/bin. 353 354 SmallString<512> PS4SDKDir; 355 if (const char *EnvValue = getenv("SCE_ORBIS_SDK_DIR")) { 356 if (!llvm::sys::fs::exists(EnvValue)) 357 getDriver().Diag(clang::diag::warn_drv_ps4_sdk_dir) << EnvValue; 358 PS4SDKDir = EnvValue; 359 } else { 360 PS4SDKDir = getDriver().Dir; 361 llvm::sys::path::append(PS4SDKDir, "/../../"); 362 } 363 364 // By default, the driver won't report a warning if it can't find 365 // PS4's include or lib directories. This behavior could be changed if 366 // -Weverything or -Winvalid-or-nonexistent-directory options are passed. 367 // If -isysroot was passed, use that as the SDK base path. 368 std::string PrefixDir; 369 if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { 370 PrefixDir = A->getValue(); 371 if (!llvm::sys::fs::exists(PrefixDir)) 372 getDriver().Diag(clang::diag::warn_missing_sysroot) << PrefixDir; 373 } else 374 PrefixDir = PS4SDKDir.str(); 375 376 SmallString<512> PS4SDKIncludeDir(PrefixDir); 377 llvm::sys::path::append(PS4SDKIncludeDir, "target/include"); 378 if (!Args.hasArg(options::OPT_nostdinc) && 379 !Args.hasArg(options::OPT_nostdlibinc) && 380 !Args.hasArg(options::OPT_isysroot) && 381 !Args.hasArg(options::OPT__sysroot_EQ) && 382 !llvm::sys::fs::exists(PS4SDKIncludeDir)) { 383 getDriver().Diag(clang::diag::warn_drv_unable_to_find_directory_expected) 384 << "PS4 system headers" << PS4SDKIncludeDir; 385 } 386 387 SmallString<512> PS4SDKLibDir(PS4SDKDir); 388 llvm::sys::path::append(PS4SDKLibDir, "target/lib"); 389 if (!Args.hasArg(options::OPT_nostdlib) && 390 !Args.hasArg(options::OPT_nodefaultlibs) && 391 !Args.hasArg(options::OPT__sysroot_EQ) && !Args.hasArg(options::OPT_E) && 392 !Args.hasArg(options::OPT_c) && !Args.hasArg(options::OPT_S) && 393 !Args.hasArg(options::OPT_emit_ast) && 394 !llvm::sys::fs::exists(PS4SDKLibDir)) { 395 getDriver().Diag(clang::diag::warn_drv_unable_to_find_directory_expected) 396 << "PS4 system libraries" << PS4SDKLibDir; 397 return; 398 } 399 getFilePaths().push_back(PS4SDKLibDir.str()); 400 } 401 402 Tool *toolchains::PS4CPU::buildAssembler() const { 403 return new tools::PS4cpu::Assemble(*this); 404 } 405 406 Tool *toolchains::PS4CPU::buildLinker() const { 407 return new tools::PS4cpu::Link(*this); 408 } 409 410 bool toolchains::PS4CPU::isPICDefault() const { return true; } 411 412 bool toolchains::PS4CPU::HasNativeLLVMSupport() const { return true; } 413 414 SanitizerMask toolchains::PS4CPU::getSupportedSanitizers() const { 415 SanitizerMask Res = ToolChain::getSupportedSanitizers(); 416 Res |= SanitizerKind::Address; 417 Res |= SanitizerKind::Vptr; 418 return Res; 419 } 420