use binrw::binrw;
macro_rules! typed_value {
($name:ident, $inner:ty, $($constant:ident = $value:expr),* $(,)?) => {
#[binrw]
#[brw(big)]
#[repr(transparent)]
#[derive(PartialEq, Clone, Copy)]
pub struct $name(pub $inner);
impl $name {
$(
pub const $constant: Self = Self($value);
)*
}
impl std::fmt::Debug for $name {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.0 == 0 {
return write!(f, "NULL ({:#X})", self.0);
}
$(
if self.0 == $value {
return write!(f, "{} ({:#X})", stringify!($constant), self.0);
}
)*
write!(f, "({:#X})", self.0)
}
}
};
}
macro_rules! typed_flag {
($name:ident, $inner:ty, $($constant:ident = $value:expr),* $(,)?) => {
#[binrw]
#[brw(big)]
#[repr(transparent)]
#[derive(PartialEq, Eq, Clone, Copy)]
pub struct $name(pub $inner);
impl $name {
$(
pub const $constant: Self = Self($value);
)*
}
impl std::ops::BitOr for $name {
type Output = Self;
fn bitor(self, rhs: Self) -> Self { Self(self.0 | rhs.0) }
}
impl std::ops::BitOrAssign for $name {
fn bitor_assign(&mut self, rhs: Self) { self.0 |= rhs.0; }
}
impl std::ops::BitAnd for $name {
type Output = Self;
fn bitand(self, rhs: Self) -> Self { Self(self.0 & rhs.0) }
}
impl std::ops::BitAndAssign for $name {
fn bitand_assign(&mut self, rhs: Self) { self.0 &= rhs.0; }
}
impl std::fmt::Debug for $name {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.0 == 0 {
return write!(f, "NULL ({:#X})", self.0);
}
let mut active = Vec::new();
$(
if $value != 0 && (self.0 & $value) == $value {
active.push(stringify!($constant));
}
)*
if active.is_empty() {
write!(f, "({:#X})", self.0)
} else {
write!(f, "{} ({:#X})", active.join(" | "), self.0)
}
}
}
};
}
typed_value!(Magic, u32, ELF = 0x7f454c46);
typed_value!(Class, u8, B32 = 1);
typed_value!(Data, u8, MSB = 2);
typed_value!(Eabi, u16, CAFE = 0xcafe);
typed_value!(Machine, u16, PPC = 0x14);
#[binrw]
#[brw(big)]
#[derive(Debug, Clone)]
pub struct Header {
pub magic: Magic,
pub file_class: Class,
pub encoding: Data,
pub elf_version: u8,
pub abi: Eabi,
pub pad: [u8; 7],
pub ty: u16,
pub machine: Machine,
pub version: u32,
pub entry: u32,
pub phoff: u32,
pub shoff: u32,
pub flags: u32,
pub ehsize: u16,
pub phentsize: u16,
pub phnum: u16,
pub shentsize: u16,
pub shnum: u16,
pub shstrndx: u16,
}
const _: () = assert!(std::mem::size_of::<Header>() == 0x34);
typed_value!(
SectionType,
u32,
NULL = 0x0,
SYMTAB = 0x2,
STRTAB = 0x3,
RELA = 0x4,
NOBITS = 0x8,
RPL_EXPORTS = 0x80000001,
RPL_IMPORTS = 0x80000002,
RPL_CRCS = 0x80000003,
RPL_FILEINFO = 0x80000004,
);
typed_flag!(
SectionFlags,
u32,
EMPTY = 0x0,
WRITE = 0x1,
ALLOC = 0x2,
EXEC = 0x4,
DEFLATED = 0x08000000
);
#[binrw]
#[brw(big)]
#[derive(Debug, Clone)]
pub struct SectionHeader {
pub name: u32,
pub ty: SectionType,
pub flags: SectionFlags,
pub addr: u32,
pub offset: u32,
pub size: u32,
pub link: u32,
pub info: u32,
pub addralign: u32,
pub entsize: u32,
}
const _: () = assert!(std::mem::size_of::<SectionHeader>() == 0x28);
typed_value!(
SymbolType,
u8,
OBJECT = 0x1,
FUNC = 0x2,
SECTION = 0x3,
);
#[binrw]
#[brw(big)]
#[derive(Debug, Clone)]
pub struct Symbol {
pub name: u32,
pub value: u32,
pub size: u32,
pub info: u8,
pub other: u8,
pub shndx: u16,
}
const _: () = assert!(std::mem::size_of::<Symbol>() == 0x10);
typed_value!(
RelaType,
u32,
PPC_NONE = 0x0,
PPC_ADDR32 = 0x1,
PPC_ADDR16_LO = 0x4,
PPC_ADDR16_HI = 0x5,
PPC_ADDR16_HA = 0x6,
PPC_REL24 = 0xa,
PPC_REL14 = 0xb,
PPC_REL32 = 0x1a,
PPC_DTPMOD32 = 0x44,
PPC_DTPREL32 = 0x4e,
PPC_EMB_SDA21 = 0x6d,
PPC_EMB_RELSDA = 0x74,
PPC_DIAB_SDA21_LO = 0xb4,
PPC_DIAB_SDA21_HI = 0xb5,
PPC_DIAB_SDA21_HA = 0xb6,
PPC_DIAB_RELSDA_LO = 0xb7,
PPC_DIAB_RELSDA_HI = 0xb8,
PPC_DIAB_RELSDA_HA = 0xb9,
PPC_GHS_REL16_HI = 0xfc,
PPC_GHS_REL16_LO = 0xfd,
);
#[binrw]
#[brw(big)]
#[derive(Debug, Clone)]
pub struct Rela {
pub offset: u32,
pub info: u32,
pub addend: i32,
}
const _: () = assert!(std::mem::size_of::<Rela>() == 0x0C);
#[binrw]
#[brw(big)]
#[derive(Debug, Clone)]
pub struct RplCrc {
pub crc: u32,
}
const _: () = assert!(std::mem::size_of::<RplCrc>() == 0x04);
#[binrw]
#[brw(big)]
#[derive(Debug, Clone)]
pub struct RplFileInfo {
pub version: u32,
pub text_size: u32,
pub text_align: u32,
pub data_size: u32,
pub data_align: u32,
pub load_size: u32,
pub load_align: u32,
pub temp_size: u32,
pub tramp_adjust: u32,
pub sda_base: u32,
pub sda2_base: u32,
pub stack_size: u32,
pub filename: u32,
pub flags: u32,
pub heap_size: u32,
pub tag_offset: u32,
pub min_version: u32,
pub compression_level: i32,
pub tramp_addition: u32,
pub file_info_pad: u32,
pub cafe_sdk_version: u32,
pub cafe_sdk_revision: u32,
pub tls_module_index: u16,
pub tls_align_shift: u16,
pub runtime_file_info_size: u32,
}
const _: () = assert!(std::mem::size_of::<RplFileInfo>() == 0x60);