2020-04-12 18:40:15 +08:00
|
|
|
#![no_std]
|
|
|
|
|
2020-04-30 04:01:12 +08:00
|
|
|
extern crate alloc;
|
|
|
|
extern crate log;
|
|
|
|
|
|
|
|
use core::{mem, ptr, fmt, slice, str, convert, ops::Range};
|
|
|
|
use alloc::string::String;
|
|
|
|
use log::{info, trace, error};
|
2020-04-12 18:40:15 +08:00
|
|
|
use elf::*;
|
|
|
|
|
|
|
|
pub mod elf;
|
2020-04-30 04:01:12 +08:00
|
|
|
mod file;
|
|
|
|
mod image;
|
|
|
|
use image::{DynamicSection, Image};
|
|
|
|
mod reloc;
|
2020-04-12 18:40:15 +08:00
|
|
|
|
2020-04-22 07:42:15 +08:00
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
|
|
pub enum Arch {
|
|
|
|
Arm,
|
|
|
|
OpenRisc,
|
|
|
|
}
|
|
|
|
|
2020-04-12 18:40:15 +08:00
|
|
|
|
|
|
|
#[derive(Debug)]
|
2020-04-30 04:01:12 +08:00
|
|
|
pub enum Error {
|
2020-04-12 18:40:15 +08:00
|
|
|
Parsing(&'static str),
|
2020-04-30 04:01:12 +08:00
|
|
|
Lookup(String)
|
2020-04-12 18:40:15 +08:00
|
|
|
}
|
|
|
|
|
2020-04-30 04:01:12 +08:00
|
|
|
impl convert::From<&'static str> for Error {
|
|
|
|
fn from(desc: &'static str) -> Error {
|
2020-04-12 18:40:15 +08:00
|
|
|
Error::Parsing(desc)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-30 04:01:12 +08:00
|
|
|
impl fmt::Display for Error {
|
2020-04-12 18:40:15 +08:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
match self {
|
|
|
|
&Error::Parsing(desc) =>
|
|
|
|
write!(f, "parse error: {}", desc),
|
2020-04-30 04:01:12 +08:00
|
|
|
&Error::Lookup(ref sym) =>
|
|
|
|
write!(f, "symbol lookup error: {}", sym),
|
2020-04-12 18:40:15 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-30 04:01:12 +08:00
|
|
|
pub struct Library {
|
|
|
|
image: Image,
|
|
|
|
dyn_range: Range<usize>,
|
|
|
|
dyn_section: DynamicSection<'static>,
|
2020-04-12 18:40:15 +08:00
|
|
|
}
|
|
|
|
|
2020-04-30 04:01:12 +08:00
|
|
|
impl Library {
|
|
|
|
pub fn lookup(&self, name: &[u8]) -> Option<u32> {
|
|
|
|
self.dyn_section.lookup(name)
|
|
|
|
.map(|addr| self.image.ptr() as u32 + addr)
|
2020-04-12 18:40:15 +08:00
|
|
|
}
|
2020-04-30 04:01:12 +08:00
|
|
|
}
|
2020-04-12 18:40:15 +08:00
|
|
|
|
2020-04-30 04:01:12 +08:00
|
|
|
pub fn load(
|
|
|
|
data: &[u8],
|
|
|
|
resolve: &dyn Fn(&[u8]) -> Option<Elf32_Word>
|
|
|
|
) -> Result<Library, Error> {
|
|
|
|
// validate ELF file
|
|
|
|
let file = file::File::new(data)
|
|
|
|
.ok_or("cannot read ELF header")?;
|
|
|
|
if file.ehdr.e_type != ET_DYN {
|
|
|
|
return Err("not a shared library")?
|
2020-04-26 03:17:11 +08:00
|
|
|
}
|
2020-04-30 04:01:12 +08:00
|
|
|
let arch = file.arch()
|
|
|
|
.ok_or("not for a supported architecture")?;
|
|
|
|
|
|
|
|
// prepare target memory
|
|
|
|
let image_size = file.program_headers()
|
|
|
|
.filter_map(|phdr| phdr.map(|phdr| phdr.p_vaddr + phdr.p_memsz))
|
|
|
|
.max()
|
|
|
|
.unwrap_or(0) as usize;
|
|
|
|
let image_align = file.program_headers()
|
|
|
|
.filter_map(|phdr| phdr.and_then(|phdr| {
|
|
|
|
if phdr.p_type == PT_LOAD {
|
|
|
|
Some(phdr.p_align)
|
|
|
|
} else {
|
|
|
|
None
|
2020-04-12 18:40:15 +08:00
|
|
|
}
|
2020-04-30 04:01:12 +08:00
|
|
|
}))
|
|
|
|
.max()
|
|
|
|
.unwrap_or(4) as usize;
|
|
|
|
// 1 image for all segments
|
|
|
|
let mut image = image::Image::new(image_size, image_align)
|
|
|
|
.map_err(|_| "cannot allocate target image")?;
|
|
|
|
info!("ELF target: {} bytes, align to {:X}, allocated at {:08X}", image_size, image_align, image.ptr() as usize);
|
|
|
|
|
|
|
|
// LOAD
|
|
|
|
for phdr in file.program_headers() {
|
|
|
|
let phdr = phdr.ok_or("cannot read program header")?;
|
|
|
|
if phdr.p_type != PT_LOAD { continue; }
|
|
|
|
|
|
|
|
trace!("Program header: {:08X}+{:08X} to {:08X}",
|
|
|
|
phdr.p_offset, phdr.p_filesz,
|
|
|
|
image.ptr() as u32
|
|
|
|
);
|
|
|
|
let src = file.get(phdr.p_offset as usize..(phdr.p_offset + phdr.p_filesz) as usize)
|
|
|
|
.ok_or("program header requests an out of bounds load (in file)")?;
|
|
|
|
let dst = image.get_mut(phdr.p_vaddr as usize..
|
|
|
|
(phdr.p_vaddr + phdr.p_filesz) as usize)
|
|
|
|
.ok_or("program header requests an out of bounds load (in target)")?;
|
|
|
|
dst.copy_from_slice(src);
|
2020-04-12 18:40:15 +08:00
|
|
|
}
|
|
|
|
|
2020-04-30 04:01:12 +08:00
|
|
|
// relocate DYNAMIC
|
|
|
|
let dyn_range = file.dyn_header_vaddr()
|
|
|
|
.ok_or("cannot find a dynamic header")?;
|
|
|
|
let dyn_section = image.dyn_section(dyn_range.clone())?;
|
|
|
|
info!("Relocating {} rela, {} rel, {} pltrel",
|
|
|
|
dyn_section.rela.len(), dyn_section.rel.len(), dyn_section.pltrel.len());
|
2020-04-12 18:40:15 +08:00
|
|
|
|
2020-04-30 04:01:12 +08:00
|
|
|
for rela in dyn_section.rela {
|
|
|
|
reloc::relocate(arch, &image, &dyn_section, rela, resolve)?;
|
2020-04-12 18:40:15 +08:00
|
|
|
}
|
2020-04-30 04:01:12 +08:00
|
|
|
for rel in dyn_section.rela {
|
|
|
|
reloc::relocate(arch, &image, &dyn_section, rel, resolve)?;
|
2020-04-26 03:17:11 +08:00
|
|
|
}
|
2020-04-30 04:01:12 +08:00
|
|
|
for pltrel in dyn_section.pltrel {
|
|
|
|
reloc::relocate(arch, &image, &dyn_section, pltrel, resolve)?;
|
2020-04-12 18:40:15 +08:00
|
|
|
}
|
2020-04-30 04:01:12 +08:00
|
|
|
|
|
|
|
let dyn_section = unsafe {
|
|
|
|
core::mem::transmute(dyn_section)
|
|
|
|
};
|
|
|
|
Ok(Library {
|
|
|
|
image,
|
|
|
|
dyn_range,
|
|
|
|
dyn_section,
|
|
|
|
})
|
2020-04-12 18:40:15 +08:00
|
|
|
}
|