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
|
/// memory address of the entry point from where the process starts its execution
|
||||||
///
|
///
|
||||||
/// ## Arguments:
|
/// ## Paramters:
|
||||||
///
|
///
|
||||||
/// **instructions** List of bytes of the loaded binary file
|
/// **instructions** List of bytes of the loaded binary file
|
||||||
/// **is_32bits** defines whether the binary file is 32 bits or 64 bits
|
/// **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
|
/// Memory address of the start of the program header table
|
||||||
///
|
///
|
||||||
/// ## Arguments:
|
/// ## Paramters:
|
||||||
///
|
///
|
||||||
/// **instructions** List of bytes of the loaded binary file
|
/// **instructions** List of bytes of the loaded binary file
|
||||||
/// **is_32bits** defines whether the binary file is 32 bits or 64 bits
|
/// **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
|
/// Memory address of the start of the section header table
|
||||||
///
|
///
|
||||||
/// ## Arguments:
|
/// ## Paramters:
|
||||||
///
|
///
|
||||||
/// **instructions** List of bytes of the loaded binary file
|
/// **instructions** List of bytes of the loaded binary file
|
||||||
/// **is_32bits** defines whether the binary file is 32 bits or 64 bits
|
/// **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
|
/// 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
|
/// **instructions** List of bytes of the loaded binary file
|
||||||
/// **is_32bits** defines whether the binary file is 32 bits or 64 bits
|
/// **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
|
/// return the size of a program header table entry
|
||||||
///
|
///
|
||||||
/// ## Arguments:
|
/// ## Paramters:
|
||||||
///
|
///
|
||||||
/// **instructions** List of bytes of the loaded binary file
|
/// **instructions** List of bytes of the loaded binary file
|
||||||
/// **is_32bits** defines whether the binary file is 32 bits or 64 bits
|
/// **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
|
/// return the number of entries in the program header
|
||||||
///
|
///
|
||||||
/// ## Arguments:
|
/// ## Paramters:
|
||||||
///
|
///
|
||||||
/// **instructions** List of bytes of the loaded binary file
|
/// **instructions** List of bytes of the loaded binary file
|
||||||
/// **is_32bits** defines whether the binary file is 32 bits or 64 bits
|
/// **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
|
/// Return the size of a section header table entry
|
||||||
///
|
///
|
||||||
/// ## Arguments:
|
/// ## Paramters:
|
||||||
///
|
///
|
||||||
/// **instructions** List of bytes of the loaded binary file
|
/// **instructions** List of bytes of the loaded binary file
|
||||||
/// **is_32bits** defines whether the binary file is 32 bits or 64 bits
|
/// **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
|
/// Return the number of entries in the section header
|
||||||
///
|
///
|
||||||
/// ## Arguments:
|
/// ## Paramters:
|
||||||
///
|
///
|
||||||
/// **instructions** List of bytes of the loaded binary file
|
/// **instructions** List of bytes of the loaded binary file
|
||||||
/// **is_32bits** defines whether the binary file is 32 bits or 64 bits
|
/// **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
|
/// 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
|
/// **instructions** List of bytes of the loaded binary file
|
||||||
/// **address** Position of the first byte
|
/// **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)
|
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)
|
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)
|
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 })
|
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 })
|
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)
|
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)
|
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 = ();
|
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 instructions = value.0;
|
||||||
let address = value.1 as usize;
|
let address = value.1 as usize;
|
||||||
let is_32bits = value.2;
|
let is_32bits = value.2;
|
||||||
@ -428,26 +432,47 @@ impl TryFrom<(&Vec<u8>, u64, bool)> for SectionHeader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Loader {
|
/// Error enum for [`Loader`]
|
||||||
bytes: Vec<u8>,
|
|
||||||
pub elf_header: ElfHeader,
|
|
||||||
pub sections: Vec<SectionHeader>
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum LoaderError {
|
pub enum LoaderError {
|
||||||
|
/// Correspond to std IO error
|
||||||
IOError(std::io::Error),
|
IOError(std::io::Error),
|
||||||
|
/// Others errors
|
||||||
ParsingError
|
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 {
|
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> {
|
pub fn new(path: &str, machine: &mut Machine, start_index: usize) -> Result<(Self, u64), LoaderError> {
|
||||||
let loader = Self::load_and_parse(path)?;
|
let loader = Self::load_and_parse(path)?;
|
||||||
let end_alloc = loader.load_into_machine(machine, start_index)?;
|
let end_alloc = loader.load_into_machine(machine, start_index)?;
|
||||||
Ok((loader, end_alloc))
|
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> {
|
fn load_into_machine(&self, machine: &mut Machine, start_index: usize) -> Result<u64, LoaderError> {
|
||||||
let mut end_index = 0;
|
let mut end_index = 0;
|
||||||
for i in 0..self.sections.len() {
|
for i in 0..self.sections.len() {
|
||||||
@ -457,7 +482,8 @@ impl Loader {
|
|||||||
// Can allocate to machine memory
|
// Can allocate to machine memory
|
||||||
for j in (0..section.section_size as usize).step_by(4) {
|
for j in (0..section.section_size as usize).step_by(4) {
|
||||||
let mut buf: [u8; 4] = [0; 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)?;
|
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);
|
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)
|
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> {
|
fn load_and_parse(path: &str) -> Result<Self, LoaderError> {
|
||||||
let file = fs::File::open(path);
|
let file = fs::File::open(path);
|
||||||
match file {
|
match file {
|
||||||
@ -507,15 +535,27 @@ impl Loader {
|
|||||||
};
|
};
|
||||||
// #[cfg(debug_assertions)]
|
// #[cfg(debug_assertions)]
|
||||||
// println!("{:04x?}", instructions); // only print loaded program in debug build
|
// 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) => {
|
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();
|
let mut sections: Vec<SectionHeader> = Default::default();
|
||||||
for i in 0..num_of_entries as u64 {
|
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)?);
|
sections.push(Self::parse_section_entry(instructions, is_32bits, header_location + i * entry_size as u64)?);
|
||||||
@ -523,7 +563,15 @@ impl Loader {
|
|||||||
Ok(sections)
|
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))
|
SectionHeader::try_from((instructions, location, is_32bits))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user