reloc: add PC-relative relocation support

This commit is contained in:
occheung 2022-06-01 15:31:02 +08:00
parent d652f01379
commit 82ed46aca1
1 changed files with 21 additions and 11 deletions

View File

@ -59,7 +59,8 @@ impl Relocatable for Elf32_Rela {
enum RelType { enum RelType {
None, None,
Relative, Relative,
Lookup, LookupAbs,
LookupRel,
} }
impl RelType { impl RelType {
@ -76,9 +77,11 @@ impl RelType {
Some(RelType::Relative), Some(RelType::Relative),
R_OR1K_32 | R_OR1K_GLOB_DAT | R_OR1K_JMP_SLOT R_OR1K_32 | R_OR1K_GLOB_DAT | R_OR1K_JMP_SLOT
if arch == Arch::OpenRisc => Some(RelType::Lookup), if arch == Arch::OpenRisc => Some(RelType::LookupAbs),
R_ARM_GLOB_DAT | R_ARM_JUMP_SLOT | R_ARM_ABS32 R_ARM_GLOB_DAT | R_ARM_JUMP_SLOT | R_ARM_ABS32
if arch == Arch::Arm => Some(RelType::Lookup), if arch == Arch::Arm => Some(RelType::LookupAbs),
R_ARM_PREL31 if arch == Arch::Arm => Some(RelType::LookupRel),
_ => _ =>
None None
@ -106,31 +109,38 @@ pub fn relocate<R: Relocatable>(
let rel_type = RelType::new(arch, rel.type_info()) let rel_type = RelType::new(arch, rel.type_info())
.ok_or("unsupported relocation type")?; .ok_or("unsupported relocation type")?;
let value; let value = match rel_type {
match rel_type {
RelType::None => RelType::None =>
return Ok(()), return Ok(()),
RelType::Relative => { RelType::Relative => {
let addend = rel.addend(&lib.image); let addend = rel.addend(&lib.image);
value = lib.image.ptr().wrapping_offset(addend as isize) as Elf32_Word; lib.image.ptr().wrapping_offset(addend as isize) as Elf32_Word
} }
RelType::Lookup => { RelType::LookupAbs | RelType::LookupRel => {
let sym = sym.ok_or("relocation requires an associated symbol")?; let sym = sym.ok_or("relocation requires an associated symbol")?;
let sym_name = lib.name_starting_at(sym.st_name as usize)?; let sym_name = lib.name_starting_at(sym.st_name as usize)?;
if let Some(addr) = lib.lookup(sym_name) { let sym_addr = if let Some(addr) = lib.lookup(sym_name) {
// First, try to resolve against itself. // First, try to resolve against itself.
trace!("looked up symbol {} in image", format_sym_name(sym_name)); trace!("looked up symbol {} in image", format_sym_name(sym_name));
value = addr; addr
} else if let Some(addr) = resolve(sym_name) { } else if let Some(addr) = resolve(sym_name) {
// Second, call the user-provided function. // Second, call the user-provided function.
trace!("resolved symbol {:?}", format_sym_name(sym_name)); trace!("resolved symbol {:?}", format_sym_name(sym_name));
value = addr; addr
} else { } else {
// We couldn't find it anywhere. // We couldn't find it anywhere.
return Err(Error::Lookup(format_sym_name(sym_name))) return Err(Error::Lookup(format_sym_name(sym_name)))
};
match rel_type {
RelType::LookupAbs => sym_addr,
RelType::LookupRel =>
sym_addr.wrapping_sub(
lib.image.ptr().wrapping_offset(rel.offset() as isize) as Elf32_Addr),
_ => unreachable!()
} }
} }
} }
@ -145,7 +155,7 @@ pub fn rebind(
let rel_type = RelType::new(arch, rela.type_info()) let rel_type = RelType::new(arch, rela.type_info())
.ok_or("unsupported relocation type")?; .ok_or("unsupported relocation type")?;
match rel_type { match rel_type {
RelType::Lookup => { RelType::LookupAbs => {
let sym = lib.symtab().get(ELF32_R_SYM(rela.r_info) as usize) let sym = lib.symtab().get(ELF32_R_SYM(rela.r_info) as usize)
.ok_or("symbol out of bounds of symbol table")?; .ok_or("symbol out of bounds of symbol table")?;
let sym_name = lib.name_starting_at(sym.st_name as usize)?; let sym_name = lib.name_starting_at(sym.st_name as usize)?;