Handle select relocations while generating trampolines (#1347)
* Handle select relocations while generating trampolines Trampoline generation for all function signatures exposed a preexisting bug in wasmtime where trampoline generation occasionally does have relocations, but it's asserted that trampolines don't generate relocations, causing a panic. The relocation is currently primarily the probestack function which happens when functions might have a huge number of parameters, but not so huge as to blow the wasmparser limit of how many parameters are allowed. This commit fixes the issue by handling relocations for trampolines in the same manner as the rest of the code. Note that dynamically-generated trampolines via the `Func` API still panic if they have too many arguments and generate a relocation, but it seems like we can try to fix that later if the need truly arises. Closes #1322 * Log trampoline relocations
This commit is contained in:
@@ -289,13 +289,14 @@ pub fn create_handle_with_function(
|
||||
// ... and then we also need a trampoline with the standard "trampoline ABI"
|
||||
// which enters into the ABI specified by `ft`. Note that this is only used
|
||||
// if `Func::call` is called on an object created by `Func::new`.
|
||||
let trampoline = wasmtime_jit::make_trampoline(
|
||||
let (trampoline, relocations) = wasmtime_jit::make_trampoline(
|
||||
&*isa,
|
||||
&mut code_memory,
|
||||
&mut fn_builder_ctx,
|
||||
&sig,
|
||||
mem::size_of::<u128>(),
|
||||
)?;
|
||||
assert!(relocations.is_empty());
|
||||
let sig_id = store.compiler().signatures().register(&sig);
|
||||
trampolines.insert(sig_id, trampoline);
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ wasmparser = "0.51.2"
|
||||
more-asserts = "0.2.1"
|
||||
anyhow = "1.0"
|
||||
cfg-if = "0.1.9"
|
||||
log = "0.4"
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
winapi = { version = "0.3.7", features = ["winnt", "impl-default"] }
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
use crate::code_memory::CodeMemory;
|
||||
use crate::instantiate::SetupError;
|
||||
use crate::target_tunables::target_tunables;
|
||||
use cranelift_codegen::ir::ExternalName;
|
||||
use cranelift_codegen::ir::InstBuilder;
|
||||
use cranelift_codegen::print_errors::pretty_error;
|
||||
use cranelift_codegen::Context;
|
||||
@@ -15,10 +16,11 @@ use wasmtime_debug::{emit_debugsections_image, DebugInfoData};
|
||||
use wasmtime_environ::entity::{EntityRef, PrimaryMap};
|
||||
use wasmtime_environ::isa::{TargetFrontendConfig, TargetIsa};
|
||||
use wasmtime_environ::wasm::{DefinedFuncIndex, DefinedMemoryIndex, MemoryIndex};
|
||||
use wasmtime_environ::RelocationTarget;
|
||||
use wasmtime_environ::{
|
||||
CacheConfig, Compilation, CompileError, CompiledFunction, CompiledFunctionUnwindInfo,
|
||||
Compiler as _C, FunctionBodyData, Module, ModuleMemoryOffset, ModuleVmctxInfo, Relocations,
|
||||
Traps, Tunables, VMOffsets,
|
||||
CacheConfig, CompileError, CompiledFunction, CompiledFunctionUnwindInfo, Compiler as _C,
|
||||
FunctionBodyData, Module, ModuleMemoryOffset, ModuleVmctxInfo, Relocation, Relocations, Traps,
|
||||
Tunables, VMOffsets,
|
||||
};
|
||||
use wasmtime_profiling::ProfilingAgent;
|
||||
use wasmtime_runtime::{
|
||||
@@ -76,6 +78,17 @@ impl Compiler {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub struct Compilation {
|
||||
pub finished_functions: PrimaryMap<DefinedFuncIndex, *mut [VMFunctionBody]>,
|
||||
pub relocations: Relocations,
|
||||
pub trampolines: HashMap<VMSharedSignatureIndex, VMTrampoline>,
|
||||
pub trampoline_relocations: HashMap<VMSharedSignatureIndex, Vec<Relocation>>,
|
||||
pub jt_offsets: PrimaryMap<DefinedFuncIndex, ir::JumpTableOffsets>,
|
||||
pub dbg_image: Option<Vec<u8>>,
|
||||
pub trap_registration: TrapRegistration,
|
||||
}
|
||||
|
||||
impl Compiler {
|
||||
/// Return the target's frontend configuration settings.
|
||||
pub fn frontend_config(&self) -> TargetFrontendConfig {
|
||||
@@ -94,17 +107,7 @@ impl Compiler {
|
||||
module_translation: &ModuleTranslationState,
|
||||
function_body_inputs: PrimaryMap<DefinedFuncIndex, FunctionBodyData<'data>>,
|
||||
debug_data: Option<DebugInfoData>,
|
||||
) -> Result<
|
||||
(
|
||||
PrimaryMap<DefinedFuncIndex, *mut [VMFunctionBody]>,
|
||||
HashMap<VMSharedSignatureIndex, VMTrampoline>,
|
||||
PrimaryMap<DefinedFuncIndex, ir::JumpTableOffsets>,
|
||||
Relocations,
|
||||
Option<Vec<u8>>,
|
||||
TrapRegistration,
|
||||
),
|
||||
SetupError,
|
||||
> {
|
||||
) -> Result<Compilation, SetupError> {
|
||||
let (
|
||||
compilation,
|
||||
relocations,
|
||||
@@ -142,7 +145,7 @@ impl Compiler {
|
||||
|
||||
// Allocate all of the compiled functions into executable memory,
|
||||
// copying over their contents.
|
||||
let allocated_functions =
|
||||
let finished_functions =
|
||||
allocate_functions(&mut self.code_memory, &compilation).map_err(|message| {
|
||||
SetupError::Instantiate(InstantiationError::Resource(format!(
|
||||
"failed to allocate memory for functions: {}",
|
||||
@@ -153,7 +156,7 @@ impl Compiler {
|
||||
// Create a registration value for all traps in our allocated
|
||||
// functions. This registration will allow us to map a trapping PC
|
||||
// value to what the trap actually means if it came from JIT code.
|
||||
let trap_registration = register_traps(&allocated_functions, &traps, &self.trap_registry);
|
||||
let trap_registration = register_traps(&finished_functions, &traps, &self.trap_registry);
|
||||
|
||||
// Eagerly generate a entry trampoline for every type signature in the
|
||||
// module. This should be "relatively lightweight" for most modules and
|
||||
@@ -161,38 +164,37 @@ impl Compiler {
|
||||
// tables) have a trampoline when invoked through the wasmtime API.
|
||||
let mut cx = FunctionBuilderContext::new();
|
||||
let mut trampolines = HashMap::new();
|
||||
let mut trampoline_relocations = HashMap::new();
|
||||
for sig in module.local.signatures.values() {
|
||||
let index = self.signatures.register(sig);
|
||||
if trampolines.contains_key(&index) {
|
||||
continue;
|
||||
}
|
||||
// FIXME(#1322) we should be generating a trampoline for all
|
||||
// functions in a module, not just those with less than 40
|
||||
// arguments. Currently there is no relocation support for
|
||||
// trampoline compilation; when that is added this check can
|
||||
// go away.
|
||||
if sig.params.len() > 40 {
|
||||
continue;
|
||||
let (trampoline, relocations) = make_trampoline(
|
||||
&*self.isa,
|
||||
&mut self.code_memory,
|
||||
&mut cx,
|
||||
sig,
|
||||
std::mem::size_of::<u128>(),
|
||||
)?;
|
||||
trampolines.insert(index, trampoline);
|
||||
|
||||
// Typically trampolines do not have relocations, so if one does
|
||||
// show up be sure to log it in case anyone's listening and there's
|
||||
// an accidental bug.
|
||||
if relocations.len() > 0 {
|
||||
log::info!("relocations found in trampoline for {:?}", sig);
|
||||
trampoline_relocations.insert(index, relocations);
|
||||
}
|
||||
trampolines.insert(
|
||||
index,
|
||||
make_trampoline(
|
||||
&*self.isa,
|
||||
&mut self.code_memory,
|
||||
&mut cx,
|
||||
sig,
|
||||
std::mem::size_of::<u128>(),
|
||||
)?,
|
||||
);
|
||||
}
|
||||
|
||||
// Translate debug info (DWARF) only if at least one function is present.
|
||||
let dbg = if debug_data.is_some() && !allocated_functions.is_empty() {
|
||||
let dbg_image = if debug_data.is_some() && !finished_functions.is_empty() {
|
||||
let target_config = self.isa.frontend_config();
|
||||
let ofs = VMOffsets::new(target_config.pointer_bytes(), &module.local);
|
||||
|
||||
let mut funcs = Vec::new();
|
||||
for (i, allocated) in allocated_functions.into_iter() {
|
||||
for (i, allocated) in finished_functions.into_iter() {
|
||||
let ptr = (*allocated) as *const u8;
|
||||
let body_len = compilation.get(i).body.len();
|
||||
funcs.push((ptr, body_len));
|
||||
@@ -228,14 +230,15 @@ impl Compiler {
|
||||
|
||||
let jt_offsets = compilation.get_jt_offsets();
|
||||
|
||||
Ok((
|
||||
allocated_functions,
|
||||
trampolines,
|
||||
jt_offsets,
|
||||
Ok(Compilation {
|
||||
finished_functions,
|
||||
relocations,
|
||||
dbg,
|
||||
trampolines,
|
||||
trampoline_relocations,
|
||||
jt_offsets,
|
||||
dbg_image,
|
||||
trap_registration,
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
/// Make memory containing compiled code executable.
|
||||
@@ -271,7 +274,7 @@ pub fn make_trampoline(
|
||||
fn_builder_ctx: &mut FunctionBuilderContext,
|
||||
signature: &ir::Signature,
|
||||
value_size: usize,
|
||||
) -> Result<VMTrampoline, SetupError> {
|
||||
) -> Result<(VMTrampoline, Vec<Relocation>), SetupError> {
|
||||
let pointer_type = isa.pointer_type();
|
||||
let mut wrapper_sig = ir::Signature::new(isa.frontend_config().default_call_conv);
|
||||
|
||||
@@ -352,7 +355,7 @@ pub fn make_trampoline(
|
||||
}
|
||||
|
||||
let mut code_buf = Vec::new();
|
||||
let mut reloc_sink = RelocSink {};
|
||||
let mut reloc_sink = RelocSink::default();
|
||||
let mut trap_sink = binemit::NullTrapSink {};
|
||||
let mut stackmap_sink = binemit::NullStackmapSink {};
|
||||
context
|
||||
@@ -381,12 +384,15 @@ pub fn make_trampoline(
|
||||
})
|
||||
.map_err(|message| SetupError::Instantiate(InstantiationError::Resource(message)))?
|
||||
.as_ptr();
|
||||
Ok(unsafe { std::mem::transmute::<*const VMFunctionBody, VMTrampoline>(ptr) })
|
||||
Ok((
|
||||
unsafe { std::mem::transmute::<*const VMFunctionBody, VMTrampoline>(ptr) },
|
||||
reloc_sink.relocs,
|
||||
))
|
||||
}
|
||||
|
||||
fn allocate_functions(
|
||||
code_memory: &mut CodeMemory,
|
||||
compilation: &Compilation,
|
||||
compilation: &wasmtime_environ::Compilation,
|
||||
) -> Result<PrimaryMap<DefinedFuncIndex, *mut [VMFunctionBody]>, String> {
|
||||
let fat_ptrs = code_memory.allocate_for_compilation(compilation)?;
|
||||
|
||||
@@ -419,9 +425,13 @@ fn register_traps(
|
||||
registry.register_traps(traps)
|
||||
}
|
||||
|
||||
/// We don't expect trampoline compilation to produce any relocations, so
|
||||
/// this `RelocSink` just asserts that it doesn't recieve any.
|
||||
struct RelocSink {}
|
||||
/// We don't expect trampoline compilation to produce many relocations, so
|
||||
/// this `RelocSink` just asserts that it doesn't recieve most of them, but
|
||||
/// handles libcall ones.
|
||||
#[derive(Default)]
|
||||
struct RelocSink {
|
||||
relocs: Vec<Relocation>,
|
||||
}
|
||||
|
||||
impl binemit::RelocSink for RelocSink {
|
||||
fn reloc_block(
|
||||
@@ -434,12 +444,22 @@ impl binemit::RelocSink for RelocSink {
|
||||
}
|
||||
fn reloc_external(
|
||||
&mut self,
|
||||
_offset: binemit::CodeOffset,
|
||||
_reloc: binemit::Reloc,
|
||||
_name: &ir::ExternalName,
|
||||
_addend: binemit::Addend,
|
||||
offset: binemit::CodeOffset,
|
||||
reloc: binemit::Reloc,
|
||||
name: &ir::ExternalName,
|
||||
addend: binemit::Addend,
|
||||
) {
|
||||
panic!("trampoline compilation should not produce external symbol relocs");
|
||||
let reloc_target = if let ExternalName::LibCall(libcall) = *name {
|
||||
RelocationTarget::LibCall(libcall)
|
||||
} else {
|
||||
panic!("unrecognized external name")
|
||||
};
|
||||
self.relocs.push(Relocation {
|
||||
reloc,
|
||||
reloc_target,
|
||||
offset,
|
||||
addend,
|
||||
});
|
||||
}
|
||||
fn reloc_constant(
|
||||
&mut self,
|
||||
|
||||
@@ -80,26 +80,14 @@ impl<'data> RawCompiledModule<'data> {
|
||||
None
|
||||
};
|
||||
|
||||
let (
|
||||
finished_functions,
|
||||
trampolines,
|
||||
jt_offsets,
|
||||
relocations,
|
||||
dbg_image,
|
||||
trap_registration,
|
||||
) = compiler.compile(
|
||||
let compilation = compiler.compile(
|
||||
&translation.module,
|
||||
translation.module_translation.as_ref().unwrap(),
|
||||
translation.function_body_inputs,
|
||||
debug_data,
|
||||
)?;
|
||||
|
||||
link_module(
|
||||
&translation.module,
|
||||
&finished_functions,
|
||||
&jt_offsets,
|
||||
relocations,
|
||||
);
|
||||
link_module(&translation.module, &compilation);
|
||||
|
||||
// Compute indices into the shared signature table.
|
||||
let signatures = {
|
||||
@@ -121,7 +109,7 @@ impl<'data> RawCompiledModule<'data> {
|
||||
Some(_) => {
|
||||
let region_name = String::from("wasm_module");
|
||||
let mut profiler = profiler.unwrap().lock().unwrap();
|
||||
match &dbg_image {
|
||||
match &compilation.dbg_image {
|
||||
Some(dbg) => {
|
||||
compiler.profiler_module_load(&mut profiler, ®ion_name, Some(&dbg))
|
||||
}
|
||||
@@ -131,7 +119,7 @@ impl<'data> RawCompiledModule<'data> {
|
||||
_ => (),
|
||||
};
|
||||
|
||||
let dbg_jit_registration = if let Some(img) = dbg_image {
|
||||
let dbg_jit_registration = if let Some(img) = compilation.dbg_image {
|
||||
let mut bytes = Vec::new();
|
||||
bytes.write_all(&img).expect("all written");
|
||||
let reg = GdbJitImageRegistration::register(bytes);
|
||||
@@ -142,12 +130,12 @@ impl<'data> RawCompiledModule<'data> {
|
||||
|
||||
Ok(Self {
|
||||
module: translation.module,
|
||||
finished_functions: finished_functions.into_boxed_slice(),
|
||||
trampolines,
|
||||
finished_functions: compilation.finished_functions.into_boxed_slice(),
|
||||
trampolines: compilation.trampolines,
|
||||
data_initializers: translation.data_initializers.into_boxed_slice(),
|
||||
signatures: signatures.into_boxed_slice(),
|
||||
dbg_jit_registration,
|
||||
trap_registration,
|
||||
trap_registration: compilation.trap_registration,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ pub mod native;
|
||||
pub mod trampoline;
|
||||
|
||||
pub use crate::code_memory::CodeMemory;
|
||||
pub use crate::compiler::{make_trampoline, CompilationStrategy, Compiler};
|
||||
pub use crate::compiler::{make_trampoline, Compilation, CompilationStrategy, Compiler};
|
||||
pub use crate::instantiate::{instantiate, CompiledModule, SetupError};
|
||||
pub use crate::link::link_module;
|
||||
pub use crate::resolver::{NullResolver, Resolver};
|
||||
|
||||
@@ -1,96 +1,107 @@
|
||||
//! Linking for JIT-compiled code.
|
||||
|
||||
use crate::Compilation;
|
||||
use cranelift_codegen::binemit::Reloc;
|
||||
use cranelift_codegen::ir::JumpTableOffsets;
|
||||
use std::ptr::write_unaligned;
|
||||
use wasmtime_environ::entity::PrimaryMap;
|
||||
use wasmtime_environ::wasm::DefinedFuncIndex;
|
||||
use wasmtime_environ::{Module, RelocationTarget, Relocations};
|
||||
use wasmtime_environ::{Module, Relocation, RelocationTarget};
|
||||
use wasmtime_runtime::libcalls;
|
||||
use wasmtime_runtime::VMFunctionBody;
|
||||
|
||||
/// Links a module that has been compiled with `compiled_module` in `wasmtime-environ`.
|
||||
///
|
||||
/// Performs all required relocations inside the function code, provided the necessary metadata.
|
||||
pub fn link_module(
|
||||
module: &Module,
|
||||
allocated_functions: &PrimaryMap<DefinedFuncIndex, *mut [VMFunctionBody]>,
|
||||
jt_offsets: &PrimaryMap<DefinedFuncIndex, JumpTableOffsets>,
|
||||
relocations: Relocations,
|
||||
) {
|
||||
for (i, function_relocs) in relocations.into_iter() {
|
||||
for r in function_relocs {
|
||||
use self::libcalls::*;
|
||||
let target_func_address: usize = match r.reloc_target {
|
||||
RelocationTarget::UserFunc(index) => match module.local.defined_func_index(index) {
|
||||
Some(f) => {
|
||||
let fatptr: *const [VMFunctionBody] = allocated_functions[f];
|
||||
fatptr as *const VMFunctionBody as usize
|
||||
}
|
||||
None => panic!("direct call to import"),
|
||||
},
|
||||
RelocationTarget::LibCall(libcall) => {
|
||||
use cranelift_codegen::ir::LibCall::*;
|
||||
match libcall {
|
||||
CeilF32 => wasmtime_f32_ceil as usize,
|
||||
FloorF32 => wasmtime_f32_floor as usize,
|
||||
TruncF32 => wasmtime_f32_trunc as usize,
|
||||
NearestF32 => wasmtime_f32_nearest as usize,
|
||||
CeilF64 => wasmtime_f64_ceil as usize,
|
||||
FloorF64 => wasmtime_f64_floor as usize,
|
||||
TruncF64 => wasmtime_f64_trunc as usize,
|
||||
NearestF64 => wasmtime_f64_nearest as usize,
|
||||
Probestack => PROBESTACK as usize,
|
||||
other => panic!("unexpected libcall: {}", other),
|
||||
}
|
||||
}
|
||||
RelocationTarget::JumpTable(func_index, jt) => {
|
||||
match module.local.defined_func_index(func_index) {
|
||||
Some(f) => {
|
||||
let offset = *jt_offsets
|
||||
.get(f)
|
||||
.and_then(|ofs| ofs.get(jt))
|
||||
.expect("func jump table");
|
||||
let fatptr: *const [VMFunctionBody] = allocated_functions[f];
|
||||
fatptr as *const VMFunctionBody as usize + offset as usize
|
||||
}
|
||||
None => panic!("func index of jump table"),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let fatptr: *const [VMFunctionBody] = allocated_functions[i];
|
||||
pub fn link_module(module: &Module, compilation: &Compilation) {
|
||||
for (i, function_relocs) in compilation.relocations.iter() {
|
||||
for r in function_relocs.iter() {
|
||||
let fatptr: *const [VMFunctionBody] = compilation.finished_functions[i];
|
||||
let body = fatptr as *const VMFunctionBody;
|
||||
match r.reloc {
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
Reloc::Abs8 => unsafe {
|
||||
let reloc_address = body.add(r.offset as usize) as usize;
|
||||
let reloc_addend = r.addend as isize;
|
||||
let reloc_abs = (target_func_address as u64)
|
||||
.checked_add(reloc_addend as u64)
|
||||
.unwrap();
|
||||
write_unaligned(reloc_address as *mut u64, reloc_abs);
|
||||
},
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
Reloc::X86PCRel4 => unsafe {
|
||||
let reloc_address = body.add(r.offset as usize) as usize;
|
||||
let reloc_addend = r.addend as isize;
|
||||
let reloc_delta_u32 = (target_func_address as u32)
|
||||
.wrapping_sub(reloc_address as u32)
|
||||
.checked_add(reloc_addend as u32)
|
||||
.unwrap();
|
||||
write_unaligned(reloc_address as *mut u32, reloc_delta_u32);
|
||||
},
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
Reloc::X86CallPCRel4 => {
|
||||
// ignore
|
||||
}
|
||||
Reloc::X86PCRelRodata4 => {
|
||||
// ignore
|
||||
}
|
||||
_ => panic!("unsupported reloc kind"),
|
||||
apply_reloc(module, compilation, body, r);
|
||||
}
|
||||
}
|
||||
|
||||
for (i, function_relocs) in compilation.trampoline_relocations.iter() {
|
||||
for r in function_relocs.iter() {
|
||||
println!("tramopline relocation");
|
||||
let body = compilation.trampolines[&i] as *const VMFunctionBody;
|
||||
apply_reloc(module, compilation, body, r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_reloc(
|
||||
module: &Module,
|
||||
compilation: &Compilation,
|
||||
body: *const VMFunctionBody,
|
||||
r: &Relocation,
|
||||
) {
|
||||
use self::libcalls::*;
|
||||
let target_func_address: usize = match r.reloc_target {
|
||||
RelocationTarget::UserFunc(index) => match module.local.defined_func_index(index) {
|
||||
Some(f) => {
|
||||
let fatptr: *const [VMFunctionBody] = compilation.finished_functions[f];
|
||||
fatptr as *const VMFunctionBody as usize
|
||||
}
|
||||
None => panic!("direct call to import"),
|
||||
},
|
||||
RelocationTarget::LibCall(libcall) => {
|
||||
use cranelift_codegen::ir::LibCall::*;
|
||||
match libcall {
|
||||
CeilF32 => wasmtime_f32_ceil as usize,
|
||||
FloorF32 => wasmtime_f32_floor as usize,
|
||||
TruncF32 => wasmtime_f32_trunc as usize,
|
||||
NearestF32 => wasmtime_f32_nearest as usize,
|
||||
CeilF64 => wasmtime_f64_ceil as usize,
|
||||
FloorF64 => wasmtime_f64_floor as usize,
|
||||
TruncF64 => wasmtime_f64_trunc as usize,
|
||||
NearestF64 => wasmtime_f64_nearest as usize,
|
||||
Probestack => PROBESTACK as usize,
|
||||
other => panic!("unexpected libcall: {}", other),
|
||||
}
|
||||
}
|
||||
RelocationTarget::JumpTable(func_index, jt) => {
|
||||
match module.local.defined_func_index(func_index) {
|
||||
Some(f) => {
|
||||
let offset = *compilation
|
||||
.jt_offsets
|
||||
.get(f)
|
||||
.and_then(|ofs| ofs.get(jt))
|
||||
.expect("func jump table");
|
||||
let fatptr: *const [VMFunctionBody] = compilation.finished_functions[f];
|
||||
fatptr as *const VMFunctionBody as usize + offset as usize
|
||||
}
|
||||
None => panic!("func index of jump table"),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
match r.reloc {
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
Reloc::Abs8 => unsafe {
|
||||
let reloc_address = body.add(r.offset as usize) as usize;
|
||||
let reloc_addend = r.addend as isize;
|
||||
let reloc_abs = (target_func_address as u64)
|
||||
.checked_add(reloc_addend as u64)
|
||||
.unwrap();
|
||||
write_unaligned(reloc_address as *mut u64, reloc_abs);
|
||||
},
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
Reloc::X86PCRel4 => unsafe {
|
||||
let reloc_address = body.add(r.offset as usize) as usize;
|
||||
let reloc_addend = r.addend as isize;
|
||||
let reloc_delta_u32 = (target_func_address as u32)
|
||||
.wrapping_sub(reloc_address as u32)
|
||||
.checked_add(reloc_addend as u32)
|
||||
.unwrap();
|
||||
write_unaligned(reloc_address as *mut u32, reloc_delta_u32);
|
||||
},
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
Reloc::X86CallPCRel4 => {
|
||||
// ignore
|
||||
}
|
||||
Reloc::X86PCRelRodata4 => {
|
||||
// ignore
|
||||
}
|
||||
_ => panic!("unsupported reloc kind"),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user