Continue to add comments
This commit is contained in:
parent
025ede6080
commit
aef8d219d0
@ -129,7 +129,7 @@ impl ElfHeader {
|
||||
|
||||
/// memory address of the entry point from where the process starts its execution
|
||||
///
|
||||
/// ## Arguments:
|
||||
/// ## Paramters:
|
||||
///
|
||||
/// **instructions** List of bytes of the loaded binary file
|
||||
/// **is_32bits** defines whether the binary file is 32 bits or 64 bits
|
||||
@ -143,7 +143,7 @@ impl ElfHeader {
|
||||
|
||||
/// Memory address of the start of the program header table
|
||||
///
|
||||
/// ## Arguments:
|
||||
/// ## Paramters:
|
||||
///
|
||||
/// **instructions** List of bytes of the loaded binary file
|
||||
/// **is_32bits** defines whether the binary file is 32 bits or 64 bits
|
||||
@ -157,7 +157,7 @@ impl ElfHeader {
|
||||
|
||||
/// Memory address of the start of the section header table
|
||||
///
|
||||
/// ## Arguments:
|
||||
/// ## Paramters:
|
||||
///
|
||||
/// **instructions** List of bytes of the loaded binary file
|
||||
/// **is_32bits** defines whether the binary file is 32 bits or 64 bits
|
||||
@ -171,7 +171,7 @@ impl ElfHeader {
|
||||
|
||||
/// Return the size of the header, normally, 0x40 for 64 bits bin and 0x34 for 32 bits
|
||||
///
|
||||
/// ## Arguments:
|
||||
/// ## Paramters:
|
||||
///
|
||||
/// **instructions** List of bytes of the loaded binary file
|
||||
/// **is_32bits** defines whether the binary file is 32 bits or 64 bits
|
||||
@ -182,7 +182,7 @@ impl ElfHeader {
|
||||
|
||||
/// return the size of a program header table entry
|
||||
///
|
||||
/// ## Arguments:
|
||||
/// ## Paramters:
|
||||
///
|
||||
/// **instructions** List of bytes of the loaded binary file
|
||||
/// **is_32bits** defines whether the binary file is 32 bits or 64 bits
|
||||
@ -193,7 +193,7 @@ impl ElfHeader {
|
||||
|
||||
/// return the number of entries in the program header
|
||||
///
|
||||
/// ## Arguments:
|
||||
/// ## Paramters:
|
||||
///
|
||||
/// **instructions** List of bytes of the loaded binary file
|
||||
/// **is_32bits** defines whether the binary file is 32 bits or 64 bits
|
||||
@ -204,7 +204,7 @@ impl ElfHeader {
|
||||
|
||||
/// Return the size of a section header table entry
|
||||
///
|
||||
/// ## Arguments:
|
||||
/// ## Paramters:
|
||||
///
|
||||
/// **instructions** List of bytes of the loaded binary file
|
||||
/// **is_32bits** defines whether the binary file is 32 bits or 64 bits
|
||||
@ -215,7 +215,7 @@ impl ElfHeader {
|
||||
|
||||
/// Return the number of entries in the section header
|
||||
///
|
||||
/// ## Arguments:
|
||||
/// ## Paramters:
|
||||
///
|
||||
/// **instructions** List of bytes of the loaded binary file
|
||||
/// **is_32bits** defines whether the binary file is 32 bits or 64 bits
|
||||
@ -228,7 +228,7 @@ impl ElfHeader {
|
||||
///
|
||||
/// This method retrieve 2 bytes and concatenate them assuming the file is little endian
|
||||
///
|
||||
/// ## Arguments:
|
||||
/// ## Paramters:
|
||||
///
|
||||
/// **instructions** List of bytes of the loaded binary file
|
||||
/// **address** Position of the first byte
|
||||
@ -370,36 +370,40 @@ impl SectionHeader {
|
||||
get_address_point(instructions, address + if is_32bits { 0x0C } else { 0x10 }, is_32bits)
|
||||
}
|
||||
|
||||
fn get_image_offset(instructions: &Vec<u8>, address: usize, is_32bits: bool) -> Option<u64> {
|
||||
/// Return the offset of the section in the file image (binary file)
|
||||
fn get_image_offset(instructions: &[u8], address: usize, is_32bits: bool) -> Option<u64> {
|
||||
get_address_point(instructions, address + if is_32bits { 0x10 } else { 0x18 }, is_32bits)
|
||||
}
|
||||
|
||||
fn get_section_size(instructions: &Vec<u8>, address: usize, is_32bits: bool) -> Option<u64> {
|
||||
/// Return the size of the section in the file image (binary file), may be 0
|
||||
fn get_section_size(instructions: &[u8], address: usize, is_32bits: bool) -> Option<u64> {
|
||||
get_address_point(instructions, address + if is_32bits { 0x14 } else { 0x20 }, is_32bits)
|
||||
}
|
||||
|
||||
fn get_section_link(instructions: &Vec<u8>, address: usize, is_32bits: bool) -> Option<u32> {
|
||||
fn get_section_link(instructions: &[u8], address: usize, is_32bits: bool) -> Option<u32> {
|
||||
get_address_point(instructions, address + if is_32bits { 0x18 } else { 0x28 }, false).map(|v| { v as u32 })
|
||||
}
|
||||
|
||||
fn get_section_info(instructions: &Vec<u8>, address: usize, is_32bits: bool) -> Option<u32> {
|
||||
fn get_section_info(instructions: &[u8], address: usize, is_32bits: bool) -> Option<u32> {
|
||||
get_address_point(instructions, address + if is_32bits { 0x1C } else { 0x2C }, false).map(|v| { v as u32 })
|
||||
}
|
||||
|
||||
fn get_required_align(instructions: &Vec<u8>, address: usize, is_32bits: bool) -> Option<u64> {
|
||||
/// Return the required alignment of the section, must be a power of 2
|
||||
fn get_required_align(instructions: &[u8], address: usize, is_32bits: bool) -> Option<u64> {
|
||||
get_address_point(instructions, address + if is_32bits { 0x20 } else { 0x30 }, is_32bits)
|
||||
}
|
||||
|
||||
fn get_entry_size(instructions: &Vec<u8>, address: usize, is_32bits: bool) -> Option<u64> {
|
||||
/// Contain the size of each entry for sections that contain fixed-size entries, otherwise 0
|
||||
fn get_entry_size(instructions: &[u8], address: usize, is_32bits: bool) -> Option<u64> {
|
||||
get_address_point(instructions, address + if is_32bits { 0x24 } else { 0x38 }, is_32bits)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl TryFrom<(&Vec<u8>, u64, bool)> for SectionHeader {
|
||||
impl TryFrom<(&[u8], u64, bool)> for SectionHeader {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(value: (&Vec<u8>, u64, bool)) -> Result<Self, Self::Error> {
|
||||
fn try_from(value: (&[u8], u64, bool)) -> Result<Self, Self::Error> {
|
||||
let instructions = value.0;
|
||||
let address = value.1 as usize;
|
||||
let is_32bits = value.2;
|
||||
@ -428,26 +432,47 @@ impl TryFrom<(&Vec<u8>, u64, bool)> for SectionHeader {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Loader {
|
||||
bytes: Vec<u8>,
|
||||
pub elf_header: ElfHeader,
|
||||
pub sections: Vec<SectionHeader>
|
||||
}
|
||||
|
||||
/// Error enum for [`Loader`]
|
||||
#[derive(Debug)]
|
||||
pub enum LoaderError {
|
||||
/// Correspond to std IO error
|
||||
IOError(std::io::Error),
|
||||
/// Others errors
|
||||
ParsingError
|
||||
}
|
||||
|
||||
/// Global structure of the loader, one instance per loaded files
|
||||
pub struct Loader {
|
||||
/// List of bytes inside the binary file
|
||||
bytes: Vec<u8>,
|
||||
/// Elf header, see [`ElfHeader`] for more informations
|
||||
pub elf_header: ElfHeader,
|
||||
/// Section header table entries, see [`SectionHeader`] for more informations
|
||||
pub sections: Vec<SectionHeader>
|
||||
}
|
||||
impl Loader {
|
||||
|
||||
/// # Loader constructor
|
||||
///
|
||||
/// Load the binary file given in parameter, parse it and load inside the machine memory
|
||||
/// return the loader instance and the location of the end of the last a allocated section in memory
|
||||
///
|
||||
/// ## Parameters
|
||||
///
|
||||
/// **path**: location of the binary file on disk
|
||||
/// **machine**: well, the risc-v simulator
|
||||
/// **start_index**: The position at which you want to start to allocate the program
|
||||
pub fn new(path: &str, machine: &mut Machine, start_index: usize) -> Result<(Self, u64), LoaderError> {
|
||||
let loader = Self::load_and_parse(path)?;
|
||||
let end_alloc = loader.load_into_machine(machine, start_index)?;
|
||||
Ok((loader, end_alloc))
|
||||
}
|
||||
|
||||
/// Try to load the binary file in memory after it been parsed
|
||||
///
|
||||
/// Binary file is loaded according to sections order and rules, see [`SectionHeader`]
|
||||
///
|
||||
/// Return the location of the end of the last a allocated section in memory
|
||||
fn load_into_machine(&self, machine: &mut Machine, start_index: usize) -> Result<u64, LoaderError> {
|
||||
let mut end_index = 0;
|
||||
for i in 0..self.sections.len() {
|
||||
@ -457,7 +482,8 @@ impl Loader {
|
||||
// Can allocate to machine memory
|
||||
for j in (0..section.section_size as usize).step_by(4) {
|
||||
let mut buf: [u8; 4] = [0; 4];
|
||||
for k in 0..4 {
|
||||
#[allow(clippy::needless_range_loop)]
|
||||
for k in 0..buf.len() {
|
||||
buf[k] = self.bytes.get(section.image_offset as usize + j + k).copied().ok_or(LoaderError::ParsingError)?;
|
||||
}
|
||||
machine.write_memory(4, start_index + section.virt_addr as usize + j, u32::from_le_bytes(buf) as u64);
|
||||
@ -467,6 +493,8 @@ impl Loader {
|
||||
Ok(start_index as u64 + end_index)
|
||||
}
|
||||
|
||||
/// Load the binary file and store it inside an array and try to parse it,
|
||||
/// useful for a lot of thing like to know which sections to allocate memory and where
|
||||
fn load_and_parse(path: &str) -> Result<Self, LoaderError> {
|
||||
let file = fs::File::open(path);
|
||||
match file {
|
||||
@ -507,15 +535,27 @@ impl Loader {
|
||||
};
|
||||
// #[cfg(debug_assertions)]
|
||||
// println!("{:04x?}", instructions); // only print loaded program in debug build
|
||||
return Ok(Self { bytes: instructions, elf_header, sections: section_header });
|
||||
Ok(Self { bytes: instructions, elf_header, sections: section_header })
|
||||
},
|
||||
Err(err) => {
|
||||
return Err(LoaderError::IOError(err));
|
||||
Err(LoaderError::IOError(err))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn parse_section_header(instructions: &Vec<u8>, is_32bits: bool, header_location: u64, num_of_entries: u16, entry_size: u16) -> Result<Vec<SectionHeader>, ()> {
|
||||
|
||||
/// Try to parse sections header table
|
||||
///
|
||||
/// Create one instance of [`SectionHeader`] for each entry and store it inside an array
|
||||
///
|
||||
/// ## Parameters
|
||||
///
|
||||
/// **instructions**: array of bytes of the binary file
|
||||
/// **is_32bits**: contain whether the binary file is 32 bits or 64 bits
|
||||
/// **header_location**: represent the position of the first entry of the header
|
||||
/// **num_of_entries**: defines the number of section header entries
|
||||
/// **entry_size**: Defines the size of an entry (each entry have the exact same size), value vary depending of if this binary file is 32 or 64 bits
|
||||
fn parse_section_header(instructions: &[u8], is_32bits: bool, header_location: u64, num_of_entries: u16, entry_size: u16) -> Result<Vec<SectionHeader>, ()> {
|
||||
let mut sections: Vec<SectionHeader> = Default::default();
|
||||
for i in 0..num_of_entries as u64 {
|
||||
sections.push(Self::parse_section_entry(instructions, is_32bits, header_location + i * entry_size as u64)?);
|
||||
@ -523,7 +563,15 @@ impl Loader {
|
||||
Ok(sections)
|
||||
}
|
||||
|
||||
fn parse_section_entry(instructions: &Vec<u8>, is_32bits: bool, location: u64) -> Result<SectionHeader, ()> {
|
||||
|
||||
/// Parse one entry of the section header
|
||||
///
|
||||
/// ## Parameters:
|
||||
///
|
||||
/// **instructions**: array of bytes of the binary file
|
||||
/// **is_32bits**: contain whether the binary file is 32 bits or 64 bits
|
||||
/// **location**: represent the position of the entry on the file image
|
||||
fn parse_section_entry(instructions: &[u8], is_32bits: bool, location: u64) -> Result<SectionHeader, ()> {
|
||||
SectionHeader::try_from((instructions, location, is_32bits))
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user