diff --git a/src/simulator/loader.rs b/src/simulator/loader.rs index 1a968c8..cf77546 100644 --- a/src/simulator/loader.rs +++ b/src/simulator/loader.rs @@ -84,27 +84,27 @@ impl ElfHeader { /// memory address of the entry point from where the process starts its execution fn get_entrypoint(instructions: &Vec, is_32bits: bool) -> Option { if is_32bits { - Self::get_address_point(instructions, 0x18, true) + get_address_point(instructions, 0x18, true) } else { - Self::get_address_point(instructions, 0x18, false) + get_address_point(instructions, 0x18, false) } } /// Memory address of the start of the program header table fn get_program_header_table_location(instructions: &Vec, is_32bits: bool) -> Option { if is_32bits { - Self::get_address_point(instructions, 0x1c, true) + get_address_point(instructions, 0x1c, true) } else { - Self::get_address_point(instructions, 0x20, false) + get_address_point(instructions, 0x20, false) } } /// Memory address of the start of the section header table fn get_section_header_table_location(instructions: &Vec, is_32bits: bool) -> Option { if is_32bits { - Self::get_address_point(instructions, 0x20, true) + get_address_point(instructions, 0x20, true) } else { - Self::get_address_point(instructions, 0x28, false) + get_address_point(instructions, 0x28, false) } } @@ -138,30 +138,6 @@ impl ElfHeader { Self::get_u16_value(instructions, address) } - /// return the memory address of something stored at address - /// Can return None if the file is smaller than adress + 3 (or 7 if 64 bits), in this case, the elf header is incorrect - fn get_address_point(instructions: &Vec, address: usize, is_32bits: bool) -> Option { - if is_32bits { - let mut bytes: [u8; 4] = [0; 4]; - bytes[0] = instructions.get(address).copied()?; - bytes[1] = instructions.get(address + 1).copied()?; - bytes[2] = instructions.get(address + 2).copied()?; - bytes[3] = instructions.get(address + 3).copied()?; - Option::Some(u32::from_le_bytes(bytes) as u64) - } else { - let mut bytes: [u8; 8] = [0; 8]; - bytes[0] = instructions.get(address).copied()?; - bytes[1] = instructions.get(address + 1).copied()?; - bytes[2] = instructions.get(address + 2).copied()?; - bytes[3] = instructions.get(address + 3).copied()?; - bytes[4] = instructions.get(address + 4).copied()?; - bytes[5] = instructions.get(address + 5).copied()?; - bytes[6] = instructions.get(address + 6).copied()?; - bytes[7] = instructions.get(address + 7).copied()?; - Option::Some(u64::from_le_bytes(bytes)) - } - } - /// Return a u16 value, usually for the size or the number of entries inside a header fn get_u16_value(instructions: &Vec, address: usize) -> Option { let mut bytes: [u8; 2] = [0; 2]; @@ -211,6 +187,7 @@ impl TryFrom<&Vec> for ElfHeader { } } +#[derive(Debug)] pub struct SectionHeader { pub name_offset: u32, pub header_type: u32, @@ -218,17 +195,86 @@ pub struct SectionHeader { pub virt_addr: u64, pub image_offset: u64, pub section_size: u64, - pub section_index: u32, + pub section_link: u32, pub section_info: u32, pub required_align: u64, pub entry_size: u64 } -impl TryFrom<(&Vec, u64)> for SectionHeader { +impl SectionHeader { + + fn get_name_offset(instructions: &Vec, address: usize) -> Option { + get_address_point(instructions, address, true).map(|v| { v as u32 }) + // set true to return a u32 + } + + fn get_header_type(instructions: &Vec, address: usize) -> Option { + get_address_point(instructions, address + 0x4, true).map(|v| { v as u32 }) + } + + fn get_attribute(instructions: &Vec, address: usize, is_32bits: bool) -> Option { + get_address_point(instructions, address + 0x8, is_32bits) + } + + fn get_virtual_address(instructions: &Vec, address: usize, is_32bits: bool) -> Option { + get_address_point(instructions, address + if is_32bits { 0x0C } else { 0x10 }, is_32bits) + } + + fn get_image_offset(instructions: &Vec, address: usize, is_32bits: bool) -> Option { + get_address_point(instructions, address + if is_32bits { 0x10 } else { 0x18 }, is_32bits) + } + + fn get_section_size(instructions: &Vec, address: usize, is_32bits: bool) -> Option { + get_address_point(instructions, address + if is_32bits { 0x14 } else { 0x20 }, is_32bits) + } + + fn get_section_link(instructions: &Vec, address: usize, is_32bits: bool) -> Option { + get_address_point(instructions, address + if is_32bits { 0x18 } else { 0x28 }, false).map(|v| { v as u32 }) + } + + fn get_section_info(instructions: &Vec, address: usize, is_32bits: bool) -> Option { + get_address_point(instructions, address + if is_32bits { 0x1C } else { 0x2C }, false).map(|v| { v as u32 }) + } + + fn get_required_align(instructions: &Vec, address: usize, is_32bits: bool) -> Option { + get_address_point(instructions, address + if is_32bits { 0x20 } else { 0x30 }, is_32bits) + } + + fn get_entry_size(instructions: &Vec, address: usize, is_32bits: bool) -> Option { + get_address_point(instructions, address + if is_32bits { 0x24 } else { 0x38 }, is_32bits) + } + +} + +impl TryFrom<(&Vec, u64, bool)> for SectionHeader { type Error = (); - fn try_from(value: (&Vec, u64)) -> Result { - todo!() + fn try_from(value: (&Vec, u64, bool)) -> Result { + let instructions = value.0; + let address = value.1 as usize; + let is_32bits = value.2; + + let name_offset = Self::get_name_offset(instructions, address).ok_or(())?; + let header_type = Self::get_header_type(instructions, address).ok_or(())?; + let attribute = Self::get_attribute(instructions, address, is_32bits).ok_or(())?; + let virt_addr = Self::get_virtual_address(instructions, address, is_32bits).ok_or(())?; + let image_offset = Self::get_image_offset(instructions, address, is_32bits).ok_or(())?; + let section_size = Self::get_section_size(instructions, address, is_32bits).ok_or(())?; + let section_link = Self::get_section_link(instructions, address, is_32bits).ok_or(())?; + let section_info = Self::get_section_info(instructions, address, is_32bits).ok_or(())?; + let required_align = Self::get_required_align(instructions, address, is_32bits).ok_or(())?; + let entry_size = Self::get_entry_size(instructions, address, is_32bits).ok_or(())?; + Ok(Self { name_offset, + header_type, + attribute, + virt_addr, + image_offset, + section_size, + section_link, + section_info, + required_align, + entry_size + }) } } @@ -238,6 +284,7 @@ pub struct Loader { pub sections: Vec } +#[derive(Debug)] pub enum LoaderError { IOError(std::io::Error), ParsingError @@ -302,35 +349,60 @@ impl Loader { } fn parse_section_entry(instructions: &Vec, is_32bits: bool, location: u64) -> Result { - SectionHeader::try_from((instructions, location)) + SectionHeader::try_from((instructions, location, is_32bits)) } } +/// return the memory address of something stored at address +/// Can return None if the file is smaller than adress + 3 (or 7 if 64 bits), in this case, the elf header is incorrect +fn get_address_point(instructions: &Vec, address: usize, is_32bits: bool) -> Option { + if is_32bits { + let mut bytes: [u8; 4] = [0; 4]; + bytes[0] = instructions.get(address).copied()?; + bytes[1] = instructions.get(address + 1).copied()?; + bytes[2] = instructions.get(address + 2).copied()?; + bytes[3] = instructions.get(address + 3).copied()?; + Option::Some(u32::from_le_bytes(bytes) as u64) + } else { + let mut bytes: [u8; 8] = [0; 8]; + bytes[0] = instructions.get(address).copied()?; + bytes[1] = instructions.get(address + 1).copied()?; + bytes[2] = instructions.get(address + 2).copied()?; + bytes[3] = instructions.get(address + 3).copied()?; + bytes[4] = instructions.get(address + 4).copied()?; + bytes[5] = instructions.get(address + 5).copied()?; + bytes[6] = instructions.get(address + 6).copied()?; + bytes[7] = instructions.get(address + 7).copied()?; + Option::Some(u64::from_le_bytes(bytes)) + } +} + #[cfg(test)] mod test { use crate::simulator::{loader::Loader, machine::Machine}; #[test] + #[ignore = "CI gitlab a modifié"] fn test_parse_elf() { - // let mut machine = Machine::init_machine(); - // let loader = Loader::load("./test/riscv_instructions/simple_arithmetics/unsigned_addition", &mut machine, 0).expect("IO Error"); - // assert_eq!(true, loader.is_elf()); - // assert_eq!(false, loader.is_32bits()); - // assert_eq!(false, loader.check_endianess()); - // assert_eq!(true, loader.is_system_v_elf()); - // assert_eq!(true, loader.is_riscv_isa()); - // assert_eq!(Option::Some(1), loader.get_version()); - // assert_eq!(Option::Some(0x4000), loader.get_entrypoint(false)); - // assert_eq!(Option::Some(64), loader.get_elf_header_size(false)); - // assert_eq!(Option::Some(64), loader.get_program_header_table_location(false)); - // assert_eq!(Option::Some(18984), loader.get_section_header_table_location(false)); - // assert_eq!(Option::Some(56), loader.get_program_header_size(false)); - // assert_eq!(Option::Some(64), loader.get_section_header_size(false)); - // assert_eq!(Option::Some(4), loader.get_number_entries_program_header(false)); - // assert_eq!(Option::Some(9), loader.get_section_header_num_entries(false)); + let mut machine = Machine::init_machine(); + let loader = Loader::load("./test/riscv_instructions/simple_arithmetics/unsigned_addition", &mut machine, 0).expect("IO Error"); + assert_eq!(false, loader.elf_header.is_32bits); + assert_eq!(false, loader.elf_header.endianess); + assert_eq!(true, loader.elf_header.sys_v_abi); + assert_eq!(true, loader.elf_header.is_riscv_target); + assert_eq!(1, loader.elf_header.version); + assert_eq!(0x4000, loader.elf_header.entrypoint); + assert_eq!(64, loader.elf_header.elf_header_size); + assert_eq!(64, loader.elf_header.program_header_location); + assert_eq!(18984, loader.elf_header.section_header_location); + assert_eq!(56, loader.elf_header.program_header_size); + assert_eq!(64, loader.elf_header.section_header_size); + assert_eq!(4, loader.elf_header.program_header_entries); + assert_eq!(9, loader.elf_header.section_header_entries); + println!("{:#x?}", loader.sections); } } \ No newline at end of file