Compare commits

...

3 Commits

1 changed files with 55 additions and 24 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,58 +109,86 @@ 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!()
} }
} }
} };
lib.image.write(rel.offset(), value) match rel.type_info() {
R_ARM_PREL31 => {
let reloc_word = lib.image.get_ref::<Elf32_Word>(rel.offset())
.ok_or("relocation offset cannot be read")?;
lib.image.write(rel.offset(), (reloc_word & 0x80000000) | (value & 0x7FFFFFFF))
},
_ => lib.image.write(rel.offset(), value),
}
} }
pub fn rebind( pub fn rebind(
arch: Arch, lib: &Library, name: &[u8], value: Elf32_Word arch: Arch, lib: &Library, name: &[u8], value: Elf32_Word
) -> Result<(), Error> { ) -> Result<(), Error> {
for rela in lib.pltrel() { fn rebind_symbol_to_value<R: Relocatable>(
let rel_type = RelType::new(arch, rela.type_info()) arch: Arch, lib: &Library,name: &[u8], value: Elf32_Word, relocs: &[R]
.ok_or("unsupported relocation type")?; ) -> Result<(), Error> {
match rel_type { for reloc in relocs {
RelType::Lookup => { let rel_type = RelType::new(arch, reloc.type_info())
let sym = lib.symtab().get(ELF32_R_SYM(rela.r_info) as usize) .ok_or("unsupported relocation type")?;
.ok_or("symbol out of bounds of symbol table")?; match rel_type {
let sym_name = lib.name_starting_at(sym.st_name as usize)?; RelType::LookupAbs => {
let sym = lib.symtab().get(reloc.sym_info() as usize)
.ok_or("symbol out of bounds of symbol table")?;
let sym_name = lib.name_starting_at(sym.st_name as usize)?;
if sym_name == name { if sym_name == name {
lib.image.write(rela.offset(), value)? lib.image.write(reloc.offset(), value)?
}
} }
// No associated symbols for other relocation types.
_ => {}
} }
// No associated symbols for other relocation types.
_ => {}
} }
Ok(())
} }
if lib.pltrel().is_empty() {
rebind_symbol_to_value(arch, lib, name, value, lib.rela())?;
} else {
rebind_symbol_to_value(arch, lib, name, value, lib.pltrel())?;
}
// FIXME: the cache maintainance operations may be more than enough, // FIXME: the cache maintainance operations may be more than enough,
// may cause performance degradation. // may cause performance degradation.
dcci_slice(lib.image.data); dcci_slice(lib.image.data);