Skip to main content

rustc_target/spec/targets/
powerpc64_sony_ps3.rs

1use crate::spec::{
2    Arch, Cc, CfgAbi, CodeModel, Endian, FramePointer, LinkerFlavor, Lld, LlvmAbi, Os,
3    PanicStrategy, RelocModel, Target, TargetMetadata, TargetOptions,
4};
5
6pub(crate) fn target() -> Target {
7    let pre_link_args = TargetOptions::link_args(
8        LinkerFlavor::Gnu(Cc::No, Lld::No),
9        &[
10            // We strictly need ELFv1 PPC64.
11            "-m",
12            "elf64ppc",
13            // PS3 LV2 reserves the first 64KB page for unmapped memory protection.
14            "--image-base=0x10000",
15            // Should be default, but relying on automatic behavior appears to be brittle.
16            "-e",
17            "_start",
18            // CellOS expects .rodata to be merged into the executable Text segment (RX)
19            //  so there are only 2 loadable segments (RX and RW)
20            "--no-rosegment",
21            // CellOS uses 64 KB memory pages. Without this flag, `mold` might align data segments to 4 KB boundaries.
22            "-z",
23            "separate-loadable-segments",
24            // Prevents mold from creating a `PT_GNU_RELRO` segment that GameOS does not support.
25            "-z",
26            "norelro",
27            // CellOS's loader doesn't behave like `ld`. PRXs are stubbed in the binary already.
28            "-Bstatic",
29            // The following are segments that might never be referenced by the code,
30            //  but are expected to exist by the PS3's loader.
31            "-u",
32            "sys_process_param",
33            "-u",
34            "sys_proc_prx_param",
35            "--undefined-glob=*_prx_header",
36            "--undefined-glob=*_fnid_table",
37            "--undefined-glob=*_name",
38            "--undefined-glob=*_fstub_table",
39        ],
40    );
41
42    Target {
43        // LLVM will default to a compatible ELF backend.
44        llvm_target: "powerpc64-sony-ps3".into(),
45
46        metadata: TargetMetadata {
47            description: Some("PowerPC64 (big endian) Sony PlayStation 3 (PS3)".into()),
48            tier: Some(3),
49            host_tools: Some(false),
50            std: Some(false),
51        },
52
53        // We declare pointers to be 64-bit as the PPU _is_ a 64-bit core.
54        // However, for all real usage the OS limits us to **32-bit pointers**.
55        // SDKs should therefore take this into account, specifically when handling syscalls.
56        pointer_width: 64,
57
58        data_layout: "E-m:e-Fi64-i64:64-i128:128-n32:64".into(),
59        arch: Arch::PowerPC64,
60
61        options: TargetOptions {
62            // Base PS3 hardware.
63            vendor: "sony".into(),
64            endian: Endian::Big,
65            os: Os::Ps3,
66            cfg_abi: CfgAbi::ElfV1,
67            llvm_abiname: LlvmAbi::ElfV1,
68            features: "+altivec".into(),
69
70            // CellOS requiring ELFv1 makes LLVM's `lld` incompatible.
71            // See:
72            // - [rust-lang/rust#85589](https://github.com/rust-lang/rust/issues/85589)
73            // - [llvm/llvm-project#27630](https://github.com/llvm/llvm-project/issues/27630)
74            linker: Some("mold".into()),
75            linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::No),
76
77            // CellOS _is_ case-sensitive, but the PS3's binaries vary
78            //  in casing depending on whether they are games in `/dev_hdd0`
79            //  or system binaries (such as PRX files).
80            //
81            // All games use the .ELF (uppercase) suffix, and Sony's own
82            //  documentation and tools expect user app binaries to be uppercase.
83            exe_suffix: ".ELF".into(),
84
85            // This limits us to 64KB of ToC, but yields smaller binaries and less assembly.
86            // Only becomes a problem for binaries with thousands of dependencies.
87            code_model: Some(CodeModel::Small),
88            // Prevents LLVM from emitting modern linker relaxation relocations.
89            relax_elf_relocations: false,
90            // CellOS main executables (`EBOOT.ELF`) **must be static executables** (ET_EXEC).
91            relocation_model: RelocModel::Static,
92
93            // Locking defaults against future changes.
94            c_int_width: 32,
95            executables: true,
96            frame_pointer: FramePointer::MayOmit,
97            // Change this to `true` for developing kernel-mode applications.
98            // This target defaults to user-mode, and the kernel already handles
99            //  this for us, so keeping it off is a performance gain.
100            disable_redzone: false,
101
102            panic_strategy: PanicStrategy::Abort,
103            pre_link_args,
104            ..Default::default()
105        },
106    }
107}