wasmer/src/webassembly/relocation.rs

231 lines
6.7 KiB
Rust
Raw Normal View History

2018-10-19 09:31:10 +00:00
//! The relocation package provide two structures: RelocSink, TrapSink.
//! This structures are used by Cranelift when compiling functions to mark
//! any other calls that this function is doing, so we can "patch" the
//! function addrs in runtime with the functions we need.
2018-10-15 00:48:59 +00:00
use cranelift_codegen::binemit;
2018-10-23 23:14:59 +00:00
use cranelift_codegen::ir::{self, ExternalName, SourceLoc, TrapCode, LibCall};
2018-10-15 00:48:59 +00:00
2018-10-15 22:04:05 +00:00
pub use cranelift_codegen::binemit::Reloc;
use cranelift_wasm::FuncIndex;
2018-10-15 00:48:59 +00:00
#[derive(Debug)]
pub struct Relocation {
/// The relocation code.
pub reloc: binemit::Reloc,
/// The offset where to apply the relocation.
pub offset: binemit::CodeOffset,
/// The addend to add to the relocation value.
pub addend: binemit::Addend,
}
/// Specify the type of relocation
#[derive(Debug)]
pub enum RelocationType {
Normal(u32),
Intrinsic(String),
2018-10-23 23:14:59 +00:00
LibCall(LibCall),
GrowMemory,
CurrentMemory,
2018-10-15 00:48:59 +00:00
}
/// Implementation of a relocation sink that just saves all the information for later
pub struct RelocSink {
// func: &'func ir::Function,
/// Relocations recorded for the function.
pub func_relocs: Vec<(Relocation, RelocationType)>,
}
impl binemit::RelocSink for RelocSink {
fn reloc_ebb(
&mut self,
_offset: binemit::CodeOffset,
_reloc: binemit::Reloc,
_ebb_offset: binemit::CodeOffset,
) {
// This should use the `offsets` field of `ir::Function`.
unimplemented!();
}
fn reloc_external(
&mut self,
offset: binemit::CodeOffset,
reloc: binemit::Reloc,
name: &ExternalName,
addend: binemit::Addend,
) {
match *name {
ExternalName::User {
namespace: 0,
index,
} => {
2018-10-15 01:03:00 +00:00
self.func_relocs.push((
Relocation {
reloc,
offset,
addend,
},
RelocationType::Normal(index as _),
));
}
ExternalName::TestCase { length, ascii } => {
2018-10-15 00:48:59 +00:00
let (slice, _) = ascii.split_at(length as usize);
let name = String::from_utf8(slice.to_vec()).unwrap();
let relocation_type = match name.as_str() {
"current_memory" => RelocationType::CurrentMemory,
"grow_memory" => RelocationType::GrowMemory,
_ => RelocationType::Intrinsic(name),
};
2018-10-15 01:03:00 +00:00
self.func_relocs.push((
Relocation {
reloc,
offset,
addend,
},
relocation_type,
2018-10-15 01:03:00 +00:00
));
}
2018-10-23 23:14:59 +00:00
ExternalName::LibCall(libcall) => {
let relocation_type = RelocationType::LibCall(libcall);
self.func_relocs.push((
Relocation {
reloc,
offset,
addend,
},
relocation_type,
));
}
2018-10-15 00:48:59 +00:00
_ => {
unimplemented!();
}
}
}
fn reloc_jt(
&mut self,
_offset: binemit::CodeOffset,
_reloc: binemit::Reloc,
_jt: ir::JumpTable,
) {
unimplemented!();
}
}
impl RelocSink {
pub fn new() -> RelocSink {
RelocSink {
func_relocs: Vec::new(),
}
}
}
2018-10-15 22:04:05 +00:00
/// Implementation of a relocation sink that just saves all the information for later
// pub struct RelocSink {
// /// Relocations recorded for the function.
// pub func_relocs: Vec<Relocation>,
// }
// impl binemit::RelocSink for RelocSink {
// fn reloc_ebb(
// &mut self,
// _offset: binemit::CodeOffset,
// _reloc: binemit::Reloc,
// _ebb_offset: binemit::CodeOffset,
// ) {
// // This should use the `offsets` field of `ir::Function`.
// panic!("ebb headers not yet implemented");
// }
// fn reloc_external(
// &mut self,
// offset: binemit::CodeOffset,
// reloc: binemit::Reloc,
// name: &ExternalName,
// addend: binemit::Addend,
// ) {
// let reloc_target = if let ExternalName::User { namespace, index } = *name {
// debug_assert!(namespace == 0);
// RelocationTarget::UserFunc(FuncIndex::new(index as usize))
// } else if *name == ExternalName::testcase("grow_memory") {
// RelocationTarget::GrowMemory
// } else if *name == ExternalName::testcase("current_memory") {
// RelocationTarget::CurrentMemory
// } else {
// panic!("unrecognized external name")
// };
// self.func_relocs.push(Relocation {
// reloc,
// reloc_target,
// offset,
// addend,
// });
// }
// fn reloc_jt(
// &mut self,
// _offset: binemit::CodeOffset,
// _reloc: binemit::Reloc,
// _jt: ir::JumpTable,
// ) {
// panic!("jump tables not yet implemented");
// }
// }
// impl RelocSink {
// pub fn new() -> Self {
// Self {
// func_relocs: Vec::new(),
// }
// }
// }
// /// A record of a relocation to perform.
// #[derive(Debug, Clone)]
// pub struct Relocation {
// /// The relocation code.
// pub reloc: binemit::Reloc,
// /// Relocation target.
// pub reloc_target: RelocationTarget,
// /// The offset where to apply the relocation.
// pub offset: binemit::CodeOffset,
// /// The addend to add to the relocation value.
// pub addend: binemit::Addend,
// }
// /// Destination function. Can be either user function or some special one, like grow_memory.
// #[derive(Debug, Copy, Clone)]
// pub enum RelocationTarget {
// /// The user function index.
// UserFunc(FuncIndex),
// /// Function for growing the default memory by the specified amount of pages.
// GrowMemory,
// /// Function for query current size of the default linear memory.
// CurrentMemory,
// }
2018-10-15 00:48:59 +00:00
pub struct TrapData {
pub offset: usize,
pub code: TrapCode,
}
/// Simple implementation of a TrapSink
/// that saves the info for later.
pub struct TrapSink {
current_func_offset: usize,
trap_datas: Vec<TrapData>,
}
impl TrapSink {
pub fn new(current_func_offset: usize) -> TrapSink {
TrapSink {
current_func_offset,
trap_datas: Vec::new(),
}
}
}
impl binemit::TrapSink for TrapSink {
fn trap(&mut self, offset: u32, _: SourceLoc, code: TrapCode) {
self.trap_datas.push(TrapData {
offset: self.current_func_offset + offset as usize,
code,
});
}
}