forked from M-Labs/artiq
dyld: support additional RV32 reloc types
The support of LO12 type requires the runtime linker to find the corresponding HI20 symbol. resolve_rela needs the entire relocation section for that.
This commit is contained in:
parent
5d7b01bd3f
commit
2cd43bf4f7
|
@ -133,7 +133,36 @@ impl<'a> Library<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let ptr = (self.image_off + rela.r_offset) as *mut Elf32_Addr;
|
let ptr = (self.image_off + rela.r_offset) as *mut Elf32_Addr;
|
||||||
Ok(unsafe { *ptr = value })
|
|
||||||
|
match ELF32_R_TYPE(rela.r_info) {
|
||||||
|
R_RISCV_RELATIVE | R_RISCV_32 | R_RISCV_JUMP_SLOT => Ok(unsafe { *ptr = value }),
|
||||||
|
|
||||||
|
R_RISCV_CALL_PLT => {
|
||||||
|
Ok(unsafe {
|
||||||
|
*ptr = (*ptr & 0xFFF) | ((value + 0x800) & 0xFFFFF000);
|
||||||
|
*(ptr.offset(1)) = (*(ptr.offset(1)) & 0xFFFFF) | ((value & 0xFFF) << 20);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
R_RISCV_GOT_HI20 => {
|
||||||
|
Ok(unsafe {
|
||||||
|
*ptr = (*ptr & 0xFFF) | ((value + 0x800) & 0xFFFFF000)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// We will not use indirect addressing here
|
||||||
|
// So, just put in the direct address instead of the GOT
|
||||||
|
// The lower instruction must be changed to addi (typically from lw)
|
||||||
|
// to make the value treated as the direct address
|
||||||
|
// Hex encoding of addi (opcode/funct3): 0x13/0
|
||||||
|
R_RISCV_PCREL_LO12_I => {
|
||||||
|
Ok(unsafe {
|
||||||
|
*ptr = (*ptr & 0xF8F80) | 0x13 | ((value & 0xFFF) << 20);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => Err(Error::Parsing("Unsupported relocation"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is unsafe because it mutates global data (instructions).
|
// This is unsafe because it mutates global data (instructions).
|
||||||
|
@ -157,35 +186,28 @@ impl<'a> Library<'a> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_rela(&self, rela: &Elf32_Rela, resolve: &dyn Fn(&[u8]) -> Option<Elf32_Word>)
|
fn resolve_rela(&self, relas: &[Elf32_Rela], resolve: &dyn Fn(&[u8]) -> Option<Elf32_Word>)
|
||||||
-> Result<(), Error<'a>> {
|
-> Result<(), Error<'a>> {
|
||||||
let sym;
|
for rela in relas {
|
||||||
if ELF32_R_SYM(rela.r_info) == 0 {
|
let sym;
|
||||||
sym = None;
|
if ELF32_R_SYM(rela.r_info) == 0 {
|
||||||
} else {
|
sym = None;
|
||||||
sym = Some(self.symtab.get(ELF32_R_SYM(rela.r_info) as usize)
|
} else {
|
||||||
.ok_or("symbol out of bounds of symbol table")?)
|
sym = Some(self.symtab.get(ELF32_R_SYM(rela.r_info) as usize)
|
||||||
}
|
.ok_or("symbol out of bounds of symbol table")?)
|
||||||
|
}
|
||||||
|
|
||||||
let value;
|
let get_symbol_value = |sym: Option<&Elf32_Sym>| {
|
||||||
match ELF32_R_TYPE(rela.r_info) {
|
|
||||||
R_RISCV_NONE =>
|
|
||||||
return Ok(()),
|
|
||||||
|
|
||||||
R_RISCV_RELATIVE =>
|
|
||||||
value = self.image_off + rela.r_addend as Elf32_Word,
|
|
||||||
|
|
||||||
R_RISCV_32 | R_RISCV_JUMP_SLOT => {
|
|
||||||
let sym = sym.ok_or("relocation requires an associated symbol")?;
|
let sym = sym.ok_or("relocation requires an associated symbol")?;
|
||||||
let sym_name = self.name_starting_at(sym.st_name as usize)?;
|
let sym_name = self.name_starting_at(sym.st_name as usize)?;
|
||||||
|
|
||||||
// First, try to resolve against itself.
|
// First, try to resolve against itself.
|
||||||
match self.lookup(sym_name) {
|
match self.lookup(sym_name) {
|
||||||
Some(addr) => value = addr,
|
Some(addr) => Ok(addr),
|
||||||
None => {
|
None => {
|
||||||
// Second, call the user-provided function.
|
// Second, call the user-provided function.
|
||||||
match resolve(sym_name) {
|
match resolve(sym_name) {
|
||||||
Some(addr) => value = addr,
|
Some(addr) => Ok(addr),
|
||||||
None => {
|
None => {
|
||||||
// We couldn't find it anywhere.
|
// We couldn't find it anywhere.
|
||||||
return Err(Error::Lookup(sym_name))
|
return Err(Error::Lookup(sym_name))
|
||||||
|
@ -193,12 +215,40 @@ impl<'a> Library<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
_ => return Err("unsupported relocation type")?
|
let value = match ELF32_R_TYPE(rela.r_info) {
|
||||||
|
R_RISCV_NONE =>
|
||||||
|
return Ok(()),
|
||||||
|
|
||||||
|
R_RISCV_RELATIVE =>
|
||||||
|
self.image_off + rela.r_addend as Elf32_Word,
|
||||||
|
|
||||||
|
R_RISCV_32 | R_RISCV_JUMP_SLOT => {
|
||||||
|
get_symbol_value(sym)?
|
||||||
|
}
|
||||||
|
|
||||||
|
R_RISCV_CALL_PLT | R_RISCV_GOT_HI20 => {
|
||||||
|
let reloc_value = get_symbol_value(sym)?;
|
||||||
|
reloc_value + rela.r_addend as Elf32_Word - (self.image_off + rela.r_offset)
|
||||||
|
}
|
||||||
|
|
||||||
|
R_RISCV_PCREL_LO12_I => {
|
||||||
|
let hi20_reloc_addr = get_symbol_value(sym)?;
|
||||||
|
let hi20_rela = relas.iter().find(|rela| rela.r_offset == (hi20_reloc_addr - self.image_off))
|
||||||
|
.ok_or("corresponding HI20 relocation not found")?;
|
||||||
|
|
||||||
|
let hi20_sym = self.symtab.get(ELF32_R_SYM(hi20_rela.r_info) as usize);
|
||||||
|
get_symbol_value(hi20_sym)? - hi20_reloc_addr
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => return Err("unsupported relocation type")?
|
||||||
|
};
|
||||||
|
|
||||||
|
self.update_rela(rela, value)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.update_rela(rela, value)
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load(data: &[u8], image: &'a mut [u8], resolve: &dyn Fn(&[u8]) -> Option<Elf32_Word>)
|
pub fn load(data: &[u8], image: &'a mut [u8], resolve: &dyn Fn(&[u8]) -> Option<Elf32_Word>)
|
||||||
|
@ -343,8 +393,8 @@ impl<'a> Library<'a> {
|
||||||
// we never write to the memory they refer to, so it's safe.
|
// we never write to the memory they refer to, so it's safe.
|
||||||
mem::drop(image);
|
mem::drop(image);
|
||||||
|
|
||||||
for r in rela { library.resolve_rela(r, resolve)? }
|
library.resolve_rela(rela, resolve)?;
|
||||||
for r in pltrel { library.resolve_rela(r, resolve)? }
|
library.resolve_rela(pltrel, resolve)?;
|
||||||
|
|
||||||
Ok(library)
|
Ok(library)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue