diff --git a/Cargo.lock b/Cargo.lock index a4c7b20..5fbecfa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,10 +2,31 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "bytemuck" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c041d3eab048880cb0b86b256447da3f18859a163c3b8d8893f4e6368abe6393" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aca418a974d83d40a0c1f0c5cba6ff4bc28d8df099109ca459a2118d40b6322" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "elven-parser" version = "0.1.0" dependencies = [ + "bytemuck", "memmap2", "thiserror", ] diff --git a/elven-parser/Cargo.toml b/elven-parser/Cargo.toml index 0c18b09..e5af80c 100644 --- a/elven-parser/Cargo.toml +++ b/elven-parser/Cargo.toml @@ -6,5 +6,6 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +bytemuck = { version = "1.13.0", features = ["derive", "min_const_generics"] } memmap2 = "0.5.8" thiserror = "1.0.38" diff --git a/elven-parser/src/raw.rs b/elven-parser/src/raw.rs index 620974c..6103d1f 100644 --- a/elven-parser/src/raw.rs +++ b/elven-parser/src/raw.rs @@ -2,13 +2,23 @@ use std::mem; -#[derive(Debug)] +use bytemuck::{Pod, PodCastError, Zeroable}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Zeroable, Pod)] +#[repr(transparent)] + pub struct Addr(u64); -#[derive(Debug)] + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Zeroable, Pod)] +#[repr(transparent)] pub struct Offset(u64); -#[derive(Debug)] + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Zeroable, Pod)] +#[repr(transparent)] pub struct Section(u16); -#[derive(Debug)] + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Zeroable, Pod)] +#[repr(transparent)] pub struct Versym(u16); #[derive(Debug, Clone, thiserror::Error)] @@ -27,7 +37,7 @@ pub struct Elf<'a> { pub header: &'a ElfHeader, } -#[derive(Debug)] +#[derive(Debug, Clone, Copy, Zeroable, Pod)] #[repr(C)] pub struct ElfHeader { pub ident: [u8; 16], @@ -46,6 +56,10 @@ pub struct ElfHeader { pub shstrndex: u16, } +#[derive(Debug)] +#[repr(C)] +pub struct Phdr {} + impl<'a> Elf<'a> { pub fn parse(input: &'a [u8]) -> Result { const HEADER_SIZE: usize = mem::size_of::(); @@ -55,19 +69,26 @@ impl<'a> Elf<'a> { return Err(ElfParseError::FileTooSmall(HEADER_SIZE, input.len())); } - let input_ptr = input as *const [u8]; + let input_addr = input as *const [u8] as *const u8 as usize; + let input_align = input_addr.trailing_zeros() as usize; - let input_addr = input_ptr as *const u8 as usize; - let align = input_addr.trailing_zeros() as usize; + let input_header = &input[..HEADER_SIZE]; - if align < HEADER_ALIGN { - return Err(ElfParseError::UnalignedInput(HEADER_ALIGN, align)); - } + let header_slice = match bytemuck::try_cast_slice::<_, ElfHeader>(input_header) { + Ok(slice) => slice, + Err( + PodCastError::SizeMismatch + | PodCastError::OutputSliceWouldHaveSlop + | PodCastError::AlignmentMismatch, + ) => { + unreachable!() + } + Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned) => { + return Err(ElfParseError::UnalignedInput(HEADER_ALIGN, input_align)) + } + }; - let header = input_ptr as *const ElfHeader; - // SAFETY: We checked that the size is enough. We checked that the alignment matches. - // ElfHeader is POD. - let header = unsafe { &*header }; + let header = &header_slice[0]; let magic = header.ident[..4].try_into().unwrap(); @@ -107,8 +128,6 @@ mod tests { #[test] fn rust_hello_world_bin() { let file = load_test_file("hello_world"); - let elf = Elf::parse(&file).unwrap(); - dbg!(elf); - panic!() + let _ = Elf::parse(&file).unwrap(); } }