add impure incremental build process, document
This commit is contained in:
10
src/libdyld/Cargo.toml
Normal file
10
src/libdyld/Cargo.toml
Normal file
@@ -0,0 +1,10 @@
|
||||
[package]
|
||||
authors = ["M-Labs"]
|
||||
name = "dyld"
|
||||
version = "0.1.0"
|
||||
|
||||
[lib]
|
||||
name = "dyld"
|
||||
|
||||
[dependencies]
|
||||
log = "0.4"
|
||||
2736
src/libdyld/src/elf.rs
Normal file
2736
src/libdyld/src/elf.rs
Normal file
File diff suppressed because it is too large
Load Diff
73
src/libdyld/src/file.rs
Normal file
73
src/libdyld/src/file.rs
Normal file
@@ -0,0 +1,73 @@
|
||||
use core::{mem, ptr, ops::{Deref, Range}};
|
||||
use super::{
|
||||
Arch,
|
||||
elf::*,
|
||||
};
|
||||
|
||||
fn read_unaligned<T: Copy>(data: &[u8], offset: usize) -> Option<T> {
|
||||
if data.len() < offset + mem::size_of::<T>() {
|
||||
None
|
||||
} else {
|
||||
let ptr = data.as_ptr().wrapping_offset(offset as isize) as *const T;
|
||||
Some(unsafe { ptr::read_unaligned(ptr) })
|
||||
}
|
||||
}
|
||||
|
||||
/// ELF file
|
||||
pub struct File<'a> {
|
||||
pub ehdr: Elf32_Ehdr,
|
||||
data: &'a [u8],
|
||||
}
|
||||
|
||||
impl<'a> File<'a> {
|
||||
pub fn new(data: &'a [u8]) -> Option<Self> {
|
||||
let ehdr = read_unaligned(data, 0)?;
|
||||
Some(File { ehdr, data })
|
||||
}
|
||||
|
||||
fn read_unaligned<T: Copy>(&self, offset: usize) -> Option<T> {
|
||||
read_unaligned(self.data, offset)
|
||||
}
|
||||
|
||||
pub fn arch(&self) -> Option<Arch> {
|
||||
const IDENT_OPENRISC: [u8; EI_NIDENT] = [
|
||||
ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3,
|
||||
ELFCLASS32, ELFDATA2MSB, EV_CURRENT, ELFOSABI_NONE,
|
||||
/* ABI version */ 0, /* padding */ 0, 0, 0, 0, 0, 0, 0
|
||||
];
|
||||
const IDENT_ARM: [u8; EI_NIDENT] = [
|
||||
ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3,
|
||||
ELFCLASS32, ELFDATA2LSB, EV_CURRENT, ELFOSABI_NONE,
|
||||
/* ABI version */ 0, /* padding */ 0, 0, 0, 0, 0, 0, 0
|
||||
];
|
||||
|
||||
match (self.ehdr.e_ident, self.ehdr.e_machine) {
|
||||
(IDENT_ARM, EM_ARM) => Some(Arch::Arm),
|
||||
(IDENT_OPENRISC, EM_OPENRISC) => Some(Arch::OpenRisc),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn program_headers<'b>(&'b self) -> impl Iterator<Item = Option<Elf32_Phdr>> + 'b
|
||||
{
|
||||
(0..self.ehdr.e_phnum).map(move |i| {
|
||||
let phdr_off = self.ehdr.e_phoff as usize + mem::size_of::<Elf32_Phdr>() * i as usize;
|
||||
self.read_unaligned::<Elf32_Phdr>(phdr_off)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn dyn_header_vaddr(&self) -> Option<Range<usize>> {
|
||||
self.program_headers()
|
||||
.filter_map(|phdr| phdr)
|
||||
.find(|phdr| phdr.p_type == PT_DYNAMIC)
|
||||
.map(|phdr| phdr.p_vaddr as usize..(phdr.p_vaddr + phdr.p_filesz) as usize)
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for File<'_> {
|
||||
type Target = [u8];
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.data
|
||||
}
|
||||
}
|
||||
196
src/libdyld/src/image.rs
Normal file
196
src/libdyld/src/image.rs
Normal file
@@ -0,0 +1,196 @@
|
||||
use core::{
|
||||
ops::{Deref, DerefMut, Range},
|
||||
mem,
|
||||
slice,
|
||||
};
|
||||
use alloc::alloc::{alloc_zeroed, dealloc, Layout, LayoutErr};
|
||||
use super::{
|
||||
elf::*,
|
||||
Error,
|
||||
};
|
||||
|
||||
pub struct DynamicSection {
|
||||
pub strtab: Range<usize>,
|
||||
pub symtab: Range<usize>,
|
||||
pub hash: Range<usize>,
|
||||
pub hash_bucket: Range<usize>,
|
||||
pub hash_chain: Range<usize>,
|
||||
pub rel: Range<usize>,
|
||||
pub rela: Range<usize>,
|
||||
pub pltrel: Range<usize>,
|
||||
}
|
||||
|
||||
/// target memory image
|
||||
pub struct Image {
|
||||
layout: Layout,
|
||||
data: &'static mut [u8],
|
||||
}
|
||||
|
||||
impl Image {
|
||||
pub fn new(size: usize, align: usize) -> Result<Self, LayoutErr> {
|
||||
let layout = Layout::from_size_align(size, align)?;
|
||||
let data = unsafe {
|
||||
let ptr = alloc_zeroed(layout);
|
||||
slice::from_raw_parts_mut(ptr, size)
|
||||
};
|
||||
|
||||
Ok(Image {
|
||||
layout,
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
/// assumes that self.data is properly aligned
|
||||
pub(crate) fn get_ref<T>(&self, offset: usize) -> Option<&T>
|
||||
where
|
||||
T: Copy,
|
||||
{
|
||||
if self.data.len() < offset + mem::size_of::<T>() {
|
||||
None
|
||||
} else if (self.data.as_ptr() as usize + offset) & (mem::align_of::<T>() - 1) != 0 {
|
||||
None
|
||||
} else {
|
||||
let ptr = self.data.as_ptr().wrapping_offset(offset as isize) as *const T;
|
||||
Some(unsafe { &*ptr })
|
||||
}
|
||||
}
|
||||
|
||||
/// assumes that self.data is properly aligned
|
||||
///
|
||||
/// range: in bytes
|
||||
pub(crate) fn get_ref_slice_unchecked<T: Copy>(&self, range: &Range<usize>) -> &[T] {
|
||||
let offset = range.start;
|
||||
let len = (range.end - range.start) / mem::size_of::<T>();
|
||||
|
||||
let ptr = self.data.as_ptr().wrapping_offset(offset as isize) as *const T;
|
||||
unsafe { slice::from_raw_parts(ptr, len) }
|
||||
}
|
||||
|
||||
fn dyn_headers<'a>(&'a self, range: Range<usize>) ->
|
||||
impl Iterator<Item = &'a Elf32_Dyn> + 'a
|
||||
{
|
||||
range
|
||||
.step_by(mem::size_of::<Elf32_Dyn>())
|
||||
.filter_map(move |offset| {
|
||||
self.get_ref::<Elf32_Dyn>(offset)
|
||||
})
|
||||
.take_while(|d| unsafe { d.d_un.d_val } as i32 != DT_NULL)
|
||||
}
|
||||
|
||||
pub fn dyn_section(&self, range: Range<usize>) -> Result<DynamicSection, Error> {
|
||||
let (mut strtab_off, mut strtab_sz) = (0, 0);
|
||||
let (mut symtab_off, mut symtab_sz) = (0, 0);
|
||||
let (mut rel_off, mut rel_sz) = (0, 0);
|
||||
let (mut rela_off, mut rela_sz) = (0, 0);
|
||||
let (mut pltrel_off, mut pltrel_sz) = (0, 0);
|
||||
let (mut hash_off, mut hash_sz) = (0, 0);
|
||||
let mut sym_ent = 0;
|
||||
let mut rel_ent = 0;
|
||||
let mut rela_ent = 0;
|
||||
let mut nbucket = 0;
|
||||
let mut nchain = 0;
|
||||
|
||||
for dyn_header in self.dyn_headers(range) {
|
||||
let val = unsafe { dyn_header.d_un.d_val } as usize;
|
||||
match dyn_header.d_tag {
|
||||
DT_NULL => break,
|
||||
DT_STRTAB => strtab_off = val,
|
||||
DT_STRSZ => strtab_sz = val,
|
||||
DT_SYMTAB => symtab_off = val,
|
||||
DT_SYMENT => sym_ent = val,
|
||||
DT_REL => rel_off = val,
|
||||
DT_RELSZ => rel_sz = val,
|
||||
DT_RELENT => rel_ent = val,
|
||||
DT_RELA => rela_off = val,
|
||||
DT_RELASZ => rela_sz = val,
|
||||
DT_RELAENT => rela_ent = val,
|
||||
DT_JMPREL => pltrel_off = val,
|
||||
DT_PLTRELSZ => pltrel_sz = val,
|
||||
DT_HASH => {
|
||||
nbucket = *self.get_ref::<Elf32_Word>(val + 0)
|
||||
.ok_or("cannot read hash bucket count")? as usize;
|
||||
nchain = *self.get_ref::<Elf32_Word>(val + 4)
|
||||
.ok_or("cannot read hash chain count")? as usize;
|
||||
hash_off = val + 8;
|
||||
hash_sz = nbucket + nchain;
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
if strtab_off + strtab_sz > self.data.len() {
|
||||
return Err("invalid strtab offset/size")?
|
||||
}
|
||||
if symtab_off + symtab_sz > self.data.len() {
|
||||
return Err("invalid symtab offset/size")?
|
||||
}
|
||||
if sym_ent != mem::size_of::<Elf32_Sym>() {
|
||||
return Err("incorrect symbol entry size")?
|
||||
}
|
||||
if rel_off + rel_sz > self.data.len() {
|
||||
return Err("invalid rel offset/size")?
|
||||
}
|
||||
if rel_ent != 0 && rel_ent != mem::size_of::<Elf32_Rel>() {
|
||||
return Err("incorrect relocation entry size")?
|
||||
}
|
||||
if rela_off + rela_sz > self.data.len() {
|
||||
return Err("invalid rela offset/size")?
|
||||
}
|
||||
if rela_ent != 0 && rela_ent != mem::size_of::<Elf32_Rela>() {
|
||||
return Err("incorrect relocation entry size")?
|
||||
}
|
||||
if pltrel_off + pltrel_sz > self.data.len() {
|
||||
return Err("invalid pltrel offset/size")?
|
||||
}
|
||||
|
||||
// These are the same--there are as many chains as buckets, and the chains only contain
|
||||
// the symbols that overflowed the bucket.
|
||||
symtab_sz = nchain;
|
||||
|
||||
Ok(DynamicSection {
|
||||
strtab: strtab_off..strtab_off + strtab_sz,
|
||||
symtab: symtab_off..symtab_off + symtab_sz,
|
||||
hash: hash_off..hash_off + hash_sz,
|
||||
hash_bucket: 0..nbucket,
|
||||
hash_chain: nbucket..nbucket + nchain,
|
||||
rel: rel_off..rel_off + rel_sz,
|
||||
rela: rela_off..rela_off + rela_sz,
|
||||
pltrel: pltrel_off..pltrel_off + rela_sz,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn ptr(&self) -> *const u8 {
|
||||
self.data.as_ptr()
|
||||
}
|
||||
|
||||
pub fn write(&self, offset: usize, value: Elf32_Word) -> Result<(), Error> {
|
||||
if offset + mem::size_of::<Elf32_Addr>() > self.data.len() {
|
||||
return Err("relocation out of image bounds")?
|
||||
}
|
||||
|
||||
let ptr = (self.data.as_ptr() as usize + offset) as *mut Elf32_Addr;
|
||||
Ok(unsafe { *ptr = value })
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Image {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
dealloc(self.data.as_mut_ptr(), self.layout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Image {
|
||||
type Target = [u8];
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.data
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for Image {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
self.data
|
||||
}
|
||||
}
|
||||
206
src/libdyld/src/lib.rs
Normal file
206
src/libdyld/src/lib.rs
Normal file
@@ -0,0 +1,206 @@
|
||||
#![no_std]
|
||||
|
||||
extern crate alloc;
|
||||
extern crate log;
|
||||
|
||||
use core::{fmt, str, convert};
|
||||
use alloc::string::String;
|
||||
use log::{info, trace};
|
||||
use elf::*;
|
||||
|
||||
pub mod elf;
|
||||
mod file;
|
||||
mod image;
|
||||
use image::{DynamicSection, Image};
|
||||
mod reloc;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Arch {
|
||||
Arm,
|
||||
OpenRisc,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
Parsing(&'static str),
|
||||
Lookup(String)
|
||||
}
|
||||
|
||||
impl convert::From<&'static str> for Error {
|
||||
fn from(desc: &'static str) -> Error {
|
||||
Error::Parsing(desc)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&Error::Parsing(desc) =>
|
||||
write!(f, "parse error: {}", desc),
|
||||
&Error::Lookup(ref sym) =>
|
||||
write!(f, "symbol lookup error: {}", sym),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn elf_hash(name: &[u8]) -> u32 {
|
||||
let mut h: u32 = 0;
|
||||
for c in name {
|
||||
h = (h << 4) + *c as u32;
|
||||
let g = h & 0xf0000000;
|
||||
if g != 0 {
|
||||
h ^= g >> 24;
|
||||
h &= !g;
|
||||
}
|
||||
}
|
||||
h
|
||||
}
|
||||
|
||||
pub struct Library {
|
||||
image: Image,
|
||||
dyn_section: DynamicSection,
|
||||
}
|
||||
|
||||
impl Library {
|
||||
fn strtab(&self) -> &[u8] {
|
||||
self.image.get_ref_slice_unchecked(&self.dyn_section.strtab)
|
||||
}
|
||||
|
||||
fn symtab(&self) -> &[Elf32_Sym] {
|
||||
self.image.get_ref_slice_unchecked(&self.dyn_section.symtab)
|
||||
}
|
||||
|
||||
fn hash(&self) -> &[Elf32_Word] {
|
||||
self.image.get_ref_slice_unchecked(&self.dyn_section.hash)
|
||||
}
|
||||
|
||||
fn hash_bucket(&self) -> &[Elf32_Word] {
|
||||
&self.hash()[self.dyn_section.hash_bucket.clone()]
|
||||
}
|
||||
|
||||
fn hash_chain(&self) -> &[Elf32_Word] {
|
||||
&self.hash()[self.dyn_section.hash_chain.clone()]
|
||||
}
|
||||
|
||||
fn rel(&self) -> &[Elf32_Rel] {
|
||||
self.image.get_ref_slice_unchecked(&self.dyn_section.rel)
|
||||
}
|
||||
|
||||
fn rela(&self) -> &[Elf32_Rela] {
|
||||
self.image.get_ref_slice_unchecked(&self.dyn_section.rela)
|
||||
}
|
||||
|
||||
fn pltrel(&self) -> &[Elf32_Rel] {
|
||||
self.image.get_ref_slice_unchecked(&self.dyn_section.pltrel)
|
||||
}
|
||||
|
||||
pub fn lookup(&self, name: &[u8]) -> Option<Elf32_Word> {
|
||||
let hash = elf_hash(name);
|
||||
let mut index = self.hash_bucket()[hash as usize % self.hash_bucket().len()] as usize;
|
||||
|
||||
loop {
|
||||
if index == STN_UNDEF { return None }
|
||||
|
||||
let sym = &self.symtab()[index];
|
||||
let sym_name_off = sym.st_name as usize;
|
||||
match self.strtab().get(sym_name_off..sym_name_off + name.len()) {
|
||||
Some(sym_name) if sym_name == name => {
|
||||
if ELF32_ST_BIND(sym.st_info) & STB_GLOBAL == 0 {
|
||||
return None
|
||||
}
|
||||
|
||||
match sym.st_shndx {
|
||||
SHN_UNDEF => return None,
|
||||
SHN_ABS => return Some(self.image.ptr() as u32 + sym.st_value),
|
||||
_ => return Some(self.image.ptr() as u32 + sym.st_value)
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
index = self.hash_chain()[index] as usize;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name_starting_at(&self, offset: usize) -> Result<&[u8], Error> {
|
||||
let size = self.strtab().iter().skip(offset).position(|&x| x == 0)
|
||||
.ok_or("symbol in symbol table not null-terminated")?;
|
||||
Ok(self.strtab().get(offset..offset + size)
|
||||
.ok_or("cannot read symbol name")?)
|
||||
}
|
||||
}
|
||||
|
||||
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")?
|
||||
}
|
||||
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
|
||||
}
|
||||
}))
|
||||
.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);
|
||||
}
|
||||
|
||||
// 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());
|
||||
let lib = Library {
|
||||
image,
|
||||
dyn_section,
|
||||
};
|
||||
|
||||
for rela in lib.rela() {
|
||||
reloc::relocate(arch, &lib, rela, resolve)?;
|
||||
}
|
||||
for rel in lib.rel() {
|
||||
reloc::relocate(arch, &lib, rel, resolve)?;
|
||||
}
|
||||
for pltrel in lib.pltrel() {
|
||||
reloc::relocate(arch, &lib, pltrel, resolve)?;
|
||||
}
|
||||
|
||||
Ok(lib)
|
||||
}
|
||||
137
src/libdyld/src/reloc.rs
Normal file
137
src/libdyld/src/reloc.rs
Normal file
@@ -0,0 +1,137 @@
|
||||
use alloc::string::String;
|
||||
use log::{debug, trace};
|
||||
use super::{
|
||||
Arch,
|
||||
elf::*,
|
||||
Error,
|
||||
image::Image,
|
||||
Library,
|
||||
};
|
||||
|
||||
pub trait Relocatable {
|
||||
fn offset(&self) -> usize;
|
||||
fn type_info(&self) -> u8;
|
||||
fn sym_info(&self) -> u32;
|
||||
fn addend(&self, image: &Image) -> i32;
|
||||
}
|
||||
|
||||
impl Relocatable for Elf32_Rel {
|
||||
fn offset(&self) -> usize {
|
||||
self.r_offset as usize
|
||||
}
|
||||
|
||||
fn type_info(&self) -> u8 {
|
||||
ELF32_R_TYPE(self.r_info)
|
||||
}
|
||||
|
||||
fn sym_info(&self) -> u32 {
|
||||
ELF32_R_SYM(self.r_info)
|
||||
}
|
||||
|
||||
fn addend(&self, image: &Image) -> i32 {
|
||||
*image.get_ref(self.offset()).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl Relocatable for Elf32_Rela {
|
||||
fn offset(&self) -> usize {
|
||||
self.r_offset as usize
|
||||
}
|
||||
|
||||
fn type_info(&self) -> u8 {
|
||||
ELF32_R_TYPE(self.r_info)
|
||||
}
|
||||
|
||||
fn sym_info(&self) -> u32 {
|
||||
ELF32_R_SYM(self.r_info)
|
||||
}
|
||||
|
||||
fn addend(&self, _: &Image) -> i32 {
|
||||
self.r_addend
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
enum RelType {
|
||||
None,
|
||||
Relative,
|
||||
Lookup,
|
||||
}
|
||||
|
||||
impl RelType {
|
||||
pub fn new(arch: Arch, type_info: u8) -> Option<Self> {
|
||||
match type_info {
|
||||
R_OR1K_NONE if arch == Arch::OpenRisc =>
|
||||
Some(RelType::None),
|
||||
R_ARM_NONE if arch == Arch::Arm =>
|
||||
Some(RelType::None),
|
||||
|
||||
R_OR1K_RELATIVE if arch == Arch::OpenRisc =>
|
||||
Some(RelType::Relative),
|
||||
R_ARM_RELATIVE if arch == Arch::Arm =>
|
||||
Some(RelType::Relative),
|
||||
|
||||
R_OR1K_32 | R_OR1K_GLOB_DAT | R_OR1K_JMP_SLOT
|
||||
if arch == Arch::OpenRisc => Some(RelType::Lookup),
|
||||
R_ARM_GLOB_DAT | R_ARM_JUMP_SLOT
|
||||
if arch == Arch::Arm => Some(RelType::Lookup),
|
||||
|
||||
_ =>
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn format_sym_name(sym_name: &[u8]) -> String {
|
||||
core::str::from_utf8(sym_name)
|
||||
.map(String::from)
|
||||
.unwrap_or(String::from("<invalid symbol name>"))
|
||||
}
|
||||
|
||||
pub fn relocate<R: Relocatable>(
|
||||
arch: Arch, lib: &Library,
|
||||
rel: &R, resolve: &dyn Fn(&[u8]) -> Option<Elf32_Word>
|
||||
) -> Result<(), Error> {
|
||||
// debug!("rel r_offset={:08X} r_info={:08X} r_addend={:08X}", rel.offset(), rel.r_info, rela.r_addend);
|
||||
let sym;
|
||||
if rel.sym_info() == 0 {
|
||||
sym = None;
|
||||
} else {
|
||||
sym = Some(lib.symtab().get(rel.sym_info() as usize)
|
||||
.ok_or("symbol out of bounds of symbol table")?)
|
||||
}
|
||||
|
||||
let rel_type = RelType::new(arch, rel.type_info())
|
||||
.ok_or("unsupported relocation type")?;
|
||||
let value;
|
||||
match rel_type {
|
||||
RelType::None =>
|
||||
return Ok(()),
|
||||
|
||||
RelType::Relative => {
|
||||
let addend = rel.addend(&lib.image);
|
||||
value = lib.image.ptr().wrapping_offset(addend as isize) as Elf32_Word;
|
||||
}
|
||||
|
||||
RelType::Lookup => {
|
||||
let sym = sym.ok_or("relocation requires an associated symbol")?;
|
||||
let sym_name = lib.name_starting_at(sym.st_name as usize)?;
|
||||
|
||||
if let Some(addr) = lib.lookup(sym_name) {
|
||||
// First, try to resolve against itself.
|
||||
trace!("looked up symbol {} in image", format_sym_name(sym_name));
|
||||
value = lib.image.ptr() as u32 + addr;
|
||||
} else if let Some(addr) = resolve(sym_name) {
|
||||
// Second, call the user-provided function.
|
||||
trace!("resolved symbol {:?}", format_sym_name(sym_name));
|
||||
value = addr;
|
||||
} else {
|
||||
// We couldn't find it anywhere.
|
||||
return Err(Error::Lookup(format_sym_name(sym_name)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
debug!("rel_type={:?} write at {:08X} value {:08X}", rel_type, rel.offset(), value);
|
||||
lib.image.write(rel.offset(), value)
|
||||
}
|
||||
Reference in New Issue
Block a user