asterinas/framework/libs/boot-trojan/trojan/src/x86/relocation.rs

96 lines
3.3 KiB
Rust

// This is enforced in the linker script.
const START_OF_SETUP32_VA: usize = 0x100000;
/// The trojan is a position-independent executable. We can get the loaded base
/// address from the symbol.
#[inline]
pub fn get_image_loaded_offset() -> isize {
extern "C" {
fn start_of_setup32();
}
start_of_setup32 as isize - START_OF_SETUP32_VA as isize
}
#[allow(unused)]
struct Elf64Rela {
r_offset: u64,
r_info: u64,
r_addend: i64,
}
#[allow(unused)]
fn get_rela_array() -> &'static [Elf64Rela] {
extern "C" {
fn __rela_dyn_start();
fn __rela_dyn_end();
}
let start = __rela_dyn_start as *const Elf64Rela;
let end = __rela_dyn_end as *const Elf64Rela;
// FIXME: 2023/11/29
// There should be a Rust compiler bug that makes the calculation of len incorrect.
// The current implementation only works in debug mode.
// To do it in release mode, a workaround is to use inline asm. But that crashes
// in debug mode. QaQ
let len = unsafe { end.offset_from(start) } as usize;
#[cfg(feature = "debug_print")]
unsafe {
use crate::console::{print_hex, print_str};
print_str("[EFI stub debug] .rela.dyn section size = ");
print_hex(len as u64);
print_str("; __rela_dyn_start = ");
print_hex(start as u64);
print_str(", __rela_dyn_end = ");
print_hex(end as u64);
print_str("\n");
}
// Safety: the linker will ensure that the symbols are valid.
unsafe { core::slice::from_raw_parts(start as *const Elf64Rela, len) }
}
const R_X86_64_RELATIVE: u32 = 8;
/// Apply the relocations in the `.rela.dyn` section.
///
/// The function will enable dyn Trait objects to work since they rely on vtable pointers. Vtable
/// won't work without relocations.
///
/// We currently support R_X86_64_RELATIVE relocations only. And this type of relocation seems to
/// be the only existing type if we compile Rust code to PIC ELF binaries.
///
/// # Safety
/// This function will modify the memory pointed by the relocations. And the Rust memory safety
/// mechanisms are not aware of these kind of modification. Failure to do relocations will cause
/// dyn Trait objects to break.
#[allow(unused)]
pub unsafe fn apply_rela_dyn_relocations() {
let image_loaded_offset = get_image_loaded_offset();
let relas = get_rela_array();
for rela in relas {
let r_type = (rela.r_info & 0xffffffff) as u32;
let _r_sym = (rela.r_info >> 32) as usize;
let r_addend = rela.r_addend;
let r_offset = rela.r_offset as usize;
let target = (image_loaded_offset + r_offset as isize) as usize;
#[cfg(feature = "debug_print")]
unsafe {
use crate::console::{print_hex, print_str};
print_str("[EFI stub debug] Applying relocation at offset ");
print_hex(r_offset as u64);
print_str(", type = ");
print_hex(r_type as u64);
print_str(", addend = ");
print_hex(r_addend as u64);
print_str("\n");
}
match r_type {
R_X86_64_RELATIVE => {
let value = (image_loaded_offset as i64 + r_addend) as usize;
*(target as *mut usize) = value;
}
_ => {
panic!("Unknown relocation type: {}", r_type);
}
}
}
}