use crate::SbpfArch;
#[derive(Debug)]
pub struct ElfHeader {
pub e_ident: [u8; 16], pub e_type: u16, pub e_machine: u16, pub e_version: u32, pub e_entry: u64, pub e_phoff: u64, pub e_shoff: u64, pub e_flags: u32, pub e_ehsize: u16, pub e_phentsize: u16, pub e_phnum: u16, pub e_shentsize: u16, pub e_shnum: u16, pub e_shstrndx: u16, }
#[derive(Debug)]
pub struct ProgramHeader {
pub p_type: u32, pub p_flags: u32, pub p_offset: u64, pub p_vaddr: u64, pub p_paddr: u64, pub p_filesz: u64, pub p_memsz: u64, pub p_align: u64, }
impl Default for ElfHeader {
fn default() -> Self {
Self {
e_ident: Self::SOLANA_IDENT,
e_type: Self::SOLANA_TYPE,
e_machine: Self::SOLANA_MACHINE,
e_version: Self::SOLANA_VERSION,
e_entry: 0,
e_phoff: Self::ELF64_HEADER_SIZE as u64,
e_shoff: 0,
e_flags: 0,
e_ehsize: Self::ELF64_HEADER_SIZE,
e_phentsize: Self::PROGRAM_HEADER_SIZE,
e_phnum: 0,
e_shentsize: Self::SECTION_HEADER_SIZE,
e_shnum: 0,
e_shstrndx: 0,
}
}
}
impl ElfHeader {
const SOLANA_IDENT: [u8; 16] = [
0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ];
const SOLANA_TYPE: u16 = 3; const SOLANA_MACHINE: u16 = 247; const SOLANA_VERSION: u32 = 1; const ELF64_HEADER_SIZE: u16 = 64;
const PROGRAM_HEADER_SIZE: u16 = 56;
const SECTION_HEADER_SIZE: u16 = 64;
pub fn new() -> Self {
Self::default()
}
pub fn bytecode(&self) -> Vec<u8> {
let mut bytecode = Vec::with_capacity(Self::ELF64_HEADER_SIZE as usize);
bytecode.extend_from_slice(&self.e_ident);
bytecode.extend_from_slice(&self.e_type.to_le_bytes());
bytecode.extend_from_slice(&self.e_machine.to_le_bytes());
bytecode.extend_from_slice(&self.e_version.to_le_bytes());
bytecode.extend_from_slice(&self.e_entry.to_le_bytes());
bytecode.extend_from_slice(&self.e_phoff.to_le_bytes());
bytecode.extend_from_slice(&self.e_shoff.to_le_bytes());
bytecode.extend_from_slice(&self.e_flags.to_le_bytes());
bytecode.extend_from_slice(&self.e_ehsize.to_le_bytes());
bytecode.extend_from_slice(&self.e_phentsize.to_le_bytes());
bytecode.extend_from_slice(&self.e_phnum.to_le_bytes());
bytecode.extend_from_slice(&self.e_shentsize.to_le_bytes());
bytecode.extend_from_slice(&self.e_shnum.to_le_bytes());
bytecode.extend_from_slice(&self.e_shstrndx.to_le_bytes());
bytecode
}
}
#[rustfmt::skip]
impl ProgramHeader {
const PT_LOAD: u32 = 1; const PT_DYNAMIC: u32 = 2;
pub const PF_X: u32 = 1; pub const PF_W: u32 = 2; pub const PF_R: u32 = 4;
const PAGE_SIZE: u64 = 4096;
pub const V3_RODATA_VADDR: u64 = 0 << 32;
pub const V3_BYTECODE_VADDR: u64 = 1 << 32;
pub fn new_load(offset: u64, size: u64, executable: bool, arch: SbpfArch) -> Self {
let (flags, vaddr, align) = match (arch, executable) {
(SbpfArch::V0, true) => (Self::PF_R | Self::PF_X, offset, Self::PAGE_SIZE),
(SbpfArch::V0, false) => (Self::PF_R, offset, Self::PAGE_SIZE),
(SbpfArch::V3, true) => (Self::PF_X, Self::V3_BYTECODE_VADDR, 0),
(SbpfArch::V3, false) => (Self::PF_R, Self::V3_RODATA_VADDR, 0),
};
ProgramHeader {
p_type: Self::PT_LOAD,
p_flags: flags,
p_offset: offset,
p_vaddr: vaddr,
p_paddr: vaddr,
p_filesz: size,
p_memsz: size,
p_align: align }
}
pub fn new_dynamic(offset: u64, size: u64) -> Self {
ProgramHeader {
p_type: Self::PT_DYNAMIC,
p_flags: Self::PF_R | Self::PF_W,
p_offset: offset,
p_vaddr: offset,
p_paddr: offset,
p_filesz: size,
p_memsz: size,
p_align: 8
}
}
pub fn bytecode(&self) -> Vec<u8> {
let mut bytecode = Vec::with_capacity(56);
bytecode.extend_from_slice(&self.p_type.to_le_bytes());
bytecode.extend_from_slice(&self.p_flags.to_le_bytes());
bytecode.extend_from_slice(&self.p_offset.to_le_bytes());
bytecode.extend_from_slice(&self.p_vaddr.to_le_bytes());
bytecode.extend_from_slice(&self.p_paddr.to_le_bytes());
bytecode.extend_from_slice(&self.p_filesz.to_le_bytes());
bytecode.extend_from_slice(&self.p_memsz.to_le_bytes());
bytecode.extend_from_slice(&self.p_align.to_le_bytes());
bytecode
}
}
#[derive(Debug)]
pub struct SectionHeader {
sh_name: u32, sh_type: u32, sh_flags: u64, sh_addr: u64, sh_offset: u64, sh_size: u64, sh_link: u32, sh_info: u32, sh_addralign: u64, sh_entsize: u64, }
#[rustfmt::skip]
impl SectionHeader {
pub const SHT_NULL: u32 = 0; pub const SHT_PROGBITS: u32 = 1; pub const SHT_STRTAB: u32 = 3; pub const SHT_NOBITS: u32 = 8; pub const SHT_DYNAMIC: u32 = 6; pub const SHT_DYNSYM: u32 = 11; pub const SHT_REL: u32 = 9;
pub const SHF_WRITE: u64 = 0x1; pub const SHF_ALLOC: u64 = 0x2; pub const SHF_EXECINSTR: u64 = 0x4;
#[allow(clippy::too_many_arguments)]
pub fn new(name_offset: u32, sh_type: u32, flags: u64, addr: u64, offset: u64, size: u64, link: u32, info: u32, addralign: u64, entsize: u64) -> Self {
Self {
sh_name: name_offset,
sh_type,
sh_flags: flags,
sh_addr: addr,
sh_offset: offset,
sh_size: size,
sh_link: link,
sh_info: info,
sh_addralign: addralign,
sh_entsize: entsize,
}
}
pub fn bytecode(&self) -> Vec<u8> {
let mut bytecode = Vec::with_capacity(64);
bytecode.extend_from_slice(&self.sh_name.to_le_bytes());
bytecode.extend_from_slice(&self.sh_type.to_le_bytes());
bytecode.extend_from_slice(&self.sh_flags.to_le_bytes());
bytecode.extend_from_slice(&self.sh_addr.to_le_bytes());
bytecode.extend_from_slice(&self.sh_offset.to_le_bytes());
bytecode.extend_from_slice(&self.sh_size.to_le_bytes());
bytecode.extend_from_slice(&self.sh_link.to_le_bytes());
bytecode.extend_from_slice(&self.sh_info.to_le_bytes());
bytecode.extend_from_slice(&self.sh_addralign.to_le_bytes());
bytecode.extend_from_slice(&self.sh_entsize.to_le_bytes());
bytecode
}
}