use crate::error::{Error, ErrorKind};
use crate::uleb128;
pub fn elf32_relocate<F>(data: &[u8], op: &mut F) -> Result<usize, Error>
where
F: FnMut(u8, u32) -> Result<(), Error>,
{
let base_address = read_u32_np(data)?;
let mut count = slice_read_u8(data, 4)?;
let mut index = 5;
while count > 0 {
index += elf32_relocate_group(array_from_slice_u8(data, index)?, base_address, op)?;
count -= 1;
}
Ok(index)
}
fn elf32_relocate_group<F>(data: &[u8], mut address: u32, op: &mut F) -> Result<usize, Error>
where
F: FnMut(u8, u32) -> Result<(), Error>,
{
let relocation_type = slice_read_u8(data, 0)?;
let mut index = 1;
let mut count = 0;
index += uleb128::read_u32(array_from_slice_u8(data, 1)?, &mut count)?;
while count > 0 {
let mut offset = 0;
index += uleb128::read_u32(array_from_slice_u8(data, index)?, &mut offset)?;
address += offset;
op(relocation_type, address)?;
count -= 1;
}
Ok(index)
}
fn read_u32_np(data: &[u8]) -> Result<u32, Error> {
if cfg!(feature = "no_bounds_check") || data.len() >= 4 {
Ok(unsafe { core::ptr::read(data.as_ptr() as *const u32) })
} else {
Err(Error::new(ErrorKind::NotEnoughData))
}
}
fn slice_read_u8(data: &[u8], index: usize) -> Result<u8, Error> {
if cfg!(feature = "no_bounds_check") || data.len() > index {
Ok(unsafe { *data.get_unchecked(index) })
} else {
Err(Error::new(ErrorKind::NotEnoughData))
}
}
fn array_from_slice_u8<'a>(data: &'a [u8], offset: usize) -> Result<&'a [u8], Error> {
if cfg!(feature = "no_bounds_check") || data.len() > offset {
Ok(unsafe { core::slice::from_raw_parts(data.as_ptr().add(offset), data.len() - offset) })
} else {
Err(Error::new(ErrorKind::NotEnoughData))
}
}
#[cfg(test)]
mod tests {
#[allow(unused)]
use super::*;
#[cfg(not(feature = "no_bounds_check"))]
#[test]
fn test_decompress_no_data() {
elf32_relocate(&[0; 0], &mut |_, _| unreachable!()).unwrap_err();
}
#[cfg(not(feature = "no_bounds_check"))]
#[test]
fn test_decompress_base_address_only() {
elf32_relocate(&[0; 4], &mut |_, _| unreachable!()).unwrap_err();
}
#[cfg(not(feature = "no_bounds_check"))]
#[test]
fn test_decompress_count_only() {
elf32_relocate(&[1; 5], &mut |_, _| unreachable!()).unwrap_err();
}
#[cfg(not(feature = "no_bounds_check"))]
#[test]
fn test_decompress_count_is_zero() {
elf32_relocate(&[0; 5], &mut |_, _| unreachable!()).unwrap();
}
#[cfg(not(feature = "no_bounds_check"))]
#[test]
fn test_decompress_group_reloc_type_no_data() {
elf32_relocate(&[1; 6], &mut |_, _| unreachable!()).unwrap_err();
}
#[cfg(not(feature = "no_bounds_check"))]
#[test]
fn test_decompress_group_count_no_data() {
elf32_relocate(&[1; 6], &mut |_, _| unreachable!()).unwrap_err();
}
#[cfg(not(feature = "no_bounds_check"))]
#[test]
fn test_decompress_group_offset_no_data() {
elf32_relocate(&[1; 7], &mut |_, _| unreachable!()).unwrap_err();
}
#[test]
fn test_decompress_relocate_one() {
let memory = [
0x04, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01, 0x00, ];
let read = elf32_relocate(&memory, &mut |relocation_type, address| {
assert_eq!(relocation_type, 0x01);
assert_eq!(address, 0x01020304);
Ok(())
})
.unwrap();
assert_eq!(read, 8);
}
}