use crate::backend::{LinkedProgram, container::encode::ByteEncoder}; #[repr(C)] #[derive(Default)] pub struct ELF64Header { magic: u32, class: u8, endianness: u8, ei_version: u8, os_abi: u8, os_abi_ver: u8, pad: [u8; 7], ty: u16, machine: u16, e_version: u32, entry: u64, program_header_offset: u64, section_header_offset: u64, flags: u32, header_size: u16, program_header_entry_size: u16, program_header_num: u16, section_header_entry_size: u16, section_header_num: u16, section_header_str_idx: u16, } #[repr(C)] #[derive(Default)] pub struct ProgramHeader { ty: u32, flags: u32, offset: u64, vaddr: u64, paddr: u64, filesz: u64, memsz: u64, align: u64, } #[repr(C)] pub struct SectionHeader { name_idx: u32, ty: u32, flags: u64, addr: u64, offset: u64, size: u64, link: u32, info: u32, addr_align: u64, entry_size: u64, } pub enum Arch { X86_64, Riscv, } impl Arch { pub fn machine(&self) -> u16 { match self { Arch::X86_64 => 0x3e, Arch::Riscv => 0xf3, } } } #[repr(u8)] pub enum EType { None = 0, Rel = 1, Exec = 2, Dyn = 3, Core = 4, } // this is currently specialized for x86_64; obviously add params later pub fn create(program: &[u8], start_offset: u64) -> Vec { let pie = true; let addr_start = if pie { 0 } else { 0x400000 }; let page_size = 0x1000; // I don't know if I have to add addr_start here, idk how it maps the memory let program_size = std::mem::size_of_val(program) as u64; let mut data = ByteEncoder::default(); let header = data.reserve::(); let program_header_offset = data.pos() as u64; let program_header = data.reserve::(); let program_pos = data.pos() as u64; data.extend(program); data[header] = ELF64Header { magic: 0x7f_45_4c_46u32.swap_bytes(), class: 0x2, // 64 bit endianness: 0x1, // little endian ei_version: 0x1, os_abi: 0x0, // system-v os_abi_ver: 0x0, pad: [0x0; 7], ty: if pie { EType::Dyn } else { EType::Exec } as u16, machine: Arch::X86_64.machine(), e_version: 0x1, entry: addr_start + program_pos + start_offset, program_header_offset, section_header_offset: 0x0, // C ABI (16 bit instruction align) + double precision floats flags: 0x1 | 0x4, header_size: size_of::() as u16, program_header_entry_size: size_of::() as u16, program_header_num: 0x1, section_header_entry_size: size_of::() as u16, section_header_num: 0x0, section_header_str_idx: 0x0, }; data[program_header] = ProgramHeader { ty: 0x1, // LOAD flags: 0b101, // executable, readable offset: 0x0, vaddr: addr_start, paddr: 0x0, filesz: program_size, memsz: program_size, align: page_size, }; data.data } impl LinkedProgram { pub fn to_elf(&self) -> Vec { create(&self.code, self.entry.expect("no start")) } }