PS4CPU.cpp 15 KB

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