mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-30 07:14:46 +00:00
Fix rust host with surgical linking
This commit is contained in:
parent
eae8a2ea37
commit
411ed58eec
16 changed files with 920 additions and 67 deletions
|
@ -28,6 +28,7 @@ use target_lexicon::Triple;
|
|||
use tempfile::Builder;
|
||||
|
||||
mod metadata;
|
||||
use metadata::VirtualOffset;
|
||||
|
||||
pub const CMD_PREPROCESS: &str = "preprocess";
|
||||
pub const CMD_SURGERY: &str = "surgery";
|
||||
|
@ -196,7 +197,6 @@ fn generate_dynamic_lib(
|
|||
|
||||
let text_section = out_object.section_id(write::StandardSection::Text);
|
||||
for sym in exposed_to_host {
|
||||
// TODO properly generate this list.
|
||||
for name in &[
|
||||
format!("roc__{}_1_exposed", sym),
|
||||
format!("roc__{}_1_exposed_generic", sym),
|
||||
|
@ -317,7 +317,9 @@ fn preprocess_impl(
|
|||
for sym in exec_obj.symbols().filter(|sym| {
|
||||
sym.is_definition() && sym.name().is_ok() && sym.name().unwrap().starts_with("roc_")
|
||||
}) {
|
||||
let name = sym.name().unwrap().to_string();
|
||||
// remove potentially trailing "@version".
|
||||
let name = sym.name().unwrap().split("@").next().unwrap().to_string();
|
||||
|
||||
// special exceptions for memcpy and memset.
|
||||
if &name == "roc_memcpy" {
|
||||
md.roc_symbol_vaddresses
|
||||
|
@ -368,9 +370,6 @@ fn preprocess_impl(
|
|||
println!("PLT File Offset: {:+x}", plt_offset);
|
||||
}
|
||||
|
||||
// TODO: it looks like we may need to support global data host relocations.
|
||||
// Rust host look to be using them by default instead of the plt.
|
||||
// I think this is due to first linking into a static lib and then linking to the c wrapper.
|
||||
let plt_relocs = (match exec_obj.dynamic_relocations() {
|
||||
Some(relocs) => relocs,
|
||||
None => {
|
||||
|
@ -380,7 +379,7 @@ fn preprocess_impl(
|
|||
}
|
||||
})
|
||||
.map(|(_, reloc)| reloc)
|
||||
.filter(|reloc| reloc.kind() == RelocationKind::Elf(7));
|
||||
.filter(|reloc| matches!(reloc.kind(), RelocationKind::Elf(7)));
|
||||
|
||||
let app_syms: Vec<Symbol> = exec_obj
|
||||
.dynamic_symbols()
|
||||
|
@ -388,6 +387,28 @@ fn preprocess_impl(
|
|||
sym.is_undefined() && sym.name().is_ok() && sym.name().unwrap().starts_with("roc_")
|
||||
})
|
||||
.collect();
|
||||
|
||||
let got_app_syms: Vec<(String, usize)> = (match exec_obj.dynamic_relocations() {
|
||||
Some(relocs) => relocs,
|
||||
None => {
|
||||
println!("Executable never calls any application functions.");
|
||||
println!("No work to do. Probably an invalid input.");
|
||||
return Ok(-1);
|
||||
}
|
||||
})
|
||||
.map(|(_, reloc)| reloc)
|
||||
.filter(|reloc| matches!(reloc.kind(), RelocationKind::Elf(6)))
|
||||
.map(|reloc| {
|
||||
for symbol in app_syms.iter() {
|
||||
if reloc.target() == RelocationTarget::Symbol(symbol.index()) {
|
||||
return Some((symbol.name().unwrap().to_string(), symbol.index().0));
|
||||
}
|
||||
}
|
||||
None
|
||||
})
|
||||
.filter_map(|x| x)
|
||||
.collect();
|
||||
|
||||
for sym in app_syms.iter() {
|
||||
let name = sym.name().unwrap().to_string();
|
||||
md.app_functions.push(name.clone());
|
||||
|
@ -408,6 +429,7 @@ fn preprocess_impl(
|
|||
if reloc.target() == RelocationTarget::Symbol(symbol.index()) {
|
||||
let func_address = (i as u64 + 1) * PLT_ADDRESS_OFFSET + plt_address;
|
||||
let func_offset = (i as u64 + 1) * PLT_ADDRESS_OFFSET + plt_offset;
|
||||
println!("{}", symbol.name().unwrap().to_string());
|
||||
app_func_addresses.insert(func_address, symbol.name().unwrap());
|
||||
md.plt_addresses.insert(
|
||||
symbol.name().unwrap().to_string(),
|
||||
|
@ -537,7 +559,7 @@ fn preprocess_impl(
|
|||
.unwrap()
|
||||
.push(metadata::SurgeryEntry {
|
||||
file_offset: offset,
|
||||
virtual_offset: inst.next_ip(),
|
||||
virtual_offset: VirtualOffset::Relative(inst.next_ip()),
|
||||
size: op_size,
|
||||
});
|
||||
}
|
||||
|
@ -879,7 +901,7 @@ fn preprocess_impl(
|
|||
sec_offset as usize + md.added_byte_count as usize,
|
||||
sec_size as usize / mem::size_of::<elf::Rela64<LittleEndian>>(),
|
||||
);
|
||||
for rel in relocations.iter_mut() {
|
||||
for (i, rel) in relocations.iter_mut().enumerate() {
|
||||
let r_offset = rel.r_offset.get(NativeEndian);
|
||||
if virtual_shift_start <= r_offset {
|
||||
rel.r_offset = endian::U64::new(LittleEndian, r_offset + md.added_byte_count);
|
||||
|
@ -891,6 +913,28 @@ fn preprocess_impl(
|
|||
.set(LittleEndian, r_addend + md.added_byte_count as i64);
|
||||
}
|
||||
}
|
||||
// If the relocation goes to a roc function, we need to surgically link it and change it to relative.
|
||||
let r_type = rel.r_type(NativeEndian, false);
|
||||
if r_type == elf::R_X86_64_GLOB_DAT {
|
||||
let r_sym = rel.r_sym(NativeEndian, false);
|
||||
for (name, index) in got_app_syms.iter() {
|
||||
if *index as u32 == r_sym {
|
||||
rel.set_r_info(LittleEndian, false, 0, elf::R_X86_64_RELATIVE);
|
||||
let addend_addr = sec_offset as usize
|
||||
+ i * mem::size_of::<elf::Rela64<LittleEndian>>()
|
||||
// This 16 skips the first 2 fields and gets to the addend field.
|
||||
+ 16;
|
||||
md.surgeries
|
||||
.get_mut(name)
|
||||
.unwrap()
|
||||
.push(metadata::SurgeryEntry {
|
||||
file_offset: addend_addr as u64,
|
||||
virtual_offset: VirtualOffset::Absolute,
|
||||
size: 8,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1462,7 +1506,7 @@ fn surgery_impl(
|
|||
let dynsym_offset = md.dynamic_symbol_table_section_offset + md.added_byte_count;
|
||||
|
||||
for func_name in md.app_functions {
|
||||
let virt_offset = match app_func_vaddr_map.get(&func_name) {
|
||||
let func_virt_offset = match app_func_vaddr_map.get(&func_name) {
|
||||
Some(offset) => *offset as u64,
|
||||
None => {
|
||||
println!("Function, {}, was not defined by the app", &func_name);
|
||||
|
@ -1472,7 +1516,7 @@ fn surgery_impl(
|
|||
if verbose {
|
||||
println!(
|
||||
"Updating calls to {} to the address: {:+x}",
|
||||
&func_name, virt_offset
|
||||
&func_name, func_virt_offset
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1480,11 +1524,13 @@ fn surgery_impl(
|
|||
if verbose {
|
||||
println!("\tPerforming surgery: {:+x?}", s);
|
||||
}
|
||||
let surgery_virt_offset = match s.virtual_offset {
|
||||
VirtualOffset::Relative(vs) => (vs + md.added_byte_count) as i64,
|
||||
VirtualOffset::Absolute => 0,
|
||||
};
|
||||
match s.size {
|
||||
4 => {
|
||||
let target = (virt_offset as i64
|
||||
- (s.virtual_offset + md.added_byte_count) as i64)
|
||||
as i32;
|
||||
let target = (func_virt_offset as i64 - surgery_virt_offset) as i32;
|
||||
if verbose {
|
||||
println!("\tTarget Jump: {:+x}", target);
|
||||
}
|
||||
|
@ -1493,6 +1539,16 @@ fn surgery_impl(
|
|||
..(s.file_offset + md.added_byte_count) as usize + 4]
|
||||
.copy_from_slice(&data);
|
||||
}
|
||||
8 => {
|
||||
let target = func_virt_offset as i64 - surgery_virt_offset;
|
||||
if verbose {
|
||||
println!("\tTarget Jump: {:+x}", target);
|
||||
}
|
||||
let data = target.to_le_bytes();
|
||||
exec_mmap[(s.file_offset + md.added_byte_count) as usize
|
||||
..(s.file_offset + md.added_byte_count) as usize + 8]
|
||||
.copy_from_slice(&data);
|
||||
}
|
||||
x => {
|
||||
println!("Surgery size not yet supported: {}", x);
|
||||
return Ok(-1);
|
||||
|
@ -1506,7 +1562,8 @@ fn surgery_impl(
|
|||
let plt_off = (*plt_off + md.added_byte_count) as usize;
|
||||
let plt_vaddr = *plt_vaddr + md.added_byte_count;
|
||||
let jmp_inst_len = 5;
|
||||
let target = (virt_offset as i64 - (plt_vaddr as i64 + jmp_inst_len as i64)) as i32;
|
||||
let target =
|
||||
(func_virt_offset as i64 - (plt_vaddr as i64 + jmp_inst_len as i64)) as i32;
|
||||
if verbose {
|
||||
println!("\tPLT: {:+x}, {:+x}", plt_off, plt_vaddr);
|
||||
println!("\tTarget Jump: {:+x}", target);
|
||||
|
@ -1525,7 +1582,7 @@ fn surgery_impl(
|
|||
dynsym_offset as usize + *i as usize * mem::size_of::<elf::Sym64<LittleEndian>>(),
|
||||
);
|
||||
sym.st_shndx = endian::U16::new(LittleEndian, new_text_section_index as u16);
|
||||
sym.st_value = endian::U64::new(LittleEndian, virt_offset as u64);
|
||||
sym.st_value = endian::U64::new(LittleEndian, func_virt_offset as u64);
|
||||
sym.st_size = endian::U64::new(
|
||||
LittleEndian,
|
||||
match app_func_size_map.get(&func_name) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue