wasmer_compiler/relocation.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
//! Relocation is the process of assigning load addresses for position-dependent
//! code and data of a program and adjusting the code and data to reflect the
//! assigned addresses.
//!
//! [Learn more](https://en.wikipedia.org/wiki/Relocation_(computing)).
//!
//! Each time a `Compiler` compiles a WebAssembly function (into machine code),
//! it also attaches if there are any relocations that need to be patched into
//! the generated machine code, so a given frontend (JIT or native) can
//! do the corresponding work to run it.
use crate::lib::std::fmt;
use crate::lib::std::vec::Vec;
use crate::section::SectionIndex;
use crate::{Addend, CodeOffset, JumpTable};
use wasmer_types::entity::PrimaryMap;
use wasmer_types::LocalFunctionIndex;
use wasmer_vm::libcalls::LibCall;
/// Relocation kinds for every ISA.
#[derive(rkyv::Serialize, rkyv::Deserialize, rkyv::Archive, Copy, Clone, Debug, PartialEq, Eq)]
pub enum RelocationKind {
/// absolute 4-byte
Abs4,
/// absolute 8-byte
Abs8,
/// x86 PC-relative 4-byte
X86PCRel4,
/// x86 PC-relative 8-byte
X86PCRel8,
/// x86 PC-relative 4-byte offset to trailing rodata
X86PCRelRodata4,
/// x86 call to PC-relative 4-byte
X86CallPCRel4,
/// x86 call to PLT-relative 4-byte
X86CallPLTRel4,
/// x86 GOT PC-relative 4-byte
X86GOTPCRel4,
/// Arm32 call target
Arm32Call,
/// Arm64 call target
Arm64Call,
/// Arm64 movk/z part 0
Arm64Movw0,
/// Arm64 movk/z part 1
Arm64Movw1,
/// Arm64 movk/z part 2
Arm64Movw2,
/// Arm64 movk/z part 3
Arm64Movw3,
// /// RISC-V call target
// RiscvCall,
/// Elf x86_64 32 bit signed PC relative offset to two GOT entries for GD symbol.
ElfX86_64TlsGd,
// /// Mach-O x86_64 32 bit signed PC relative offset to a `__thread_vars` entry.
// MachOX86_64Tlv,
}
impl fmt::Display for RelocationKind {
/// Display trait implementation drops the arch, since its used in contexts where the arch is
/// already unambiguous, e.g. clif syntax with isa specified. In other contexts, use Debug.
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Self::Abs4 => write!(f, "Abs4"),
Self::Abs8 => write!(f, "Abs8"),
Self::X86PCRel4 => write!(f, "PCRel4"),
Self::X86PCRel8 => write!(f, "PCRel8"),
Self::X86PCRelRodata4 => write!(f, "PCRelRodata4"),
Self::X86CallPCRel4 => write!(f, "CallPCRel4"),
Self::X86CallPLTRel4 => write!(f, "CallPLTRel4"),
Self::X86GOTPCRel4 => write!(f, "GOTPCRel4"),
Self::Arm32Call | Self::Arm64Call => write!(f, "Call"),
Self::Arm64Movw0 => write!(f, "Arm64MovwG0"),
Self::Arm64Movw1 => write!(f, "Arm64MovwG1"),
Self::Arm64Movw2 => write!(f, "Arm64MovwG2"),
Self::Arm64Movw3 => write!(f, "Arm64MovwG3"),
Self::ElfX86_64TlsGd => write!(f, "ElfX86_64TlsGd"),
// Self::MachOX86_64Tlv => write!(f, "MachOX86_64Tlv"),
}
}
}
/// A record of a relocation to perform.
#[derive(rkyv::Serialize, rkyv::Deserialize, rkyv::Archive, Debug, Clone, PartialEq, Eq)]
pub struct Relocation {
/// The relocation kind.
pub kind: RelocationKind,
/// Relocation target.
pub reloc_target: RelocationTarget,
/// The offset where to apply the relocation.
pub offset: CodeOffset,
/// The addend to add to the relocation value.
pub addend: Addend,
}
/// Destination function. Can be either user function or some special one, like `memory.grow`.
#[derive(rkyv::Serialize, rkyv::Deserialize, rkyv::Archive, Debug, Copy, Clone, PartialEq, Eq)]
pub enum RelocationTarget {
/// A relocation to a function defined locally in the wasm (not an imported one).
LocalFunc(LocalFunctionIndex),
/// A compiler-generated libcall.
LibCall(LibCall),
/// Jump table index.
JumpTable(LocalFunctionIndex, JumpTable),
/// Custom sections generated by the compiler
CustomSection(SectionIndex),
}
impl Relocation {
/// Given a function start address, provide the relocation relative
/// to that address.
///
/// The function returns the relocation address and the delta.
pub fn for_address(&self, start: usize, target_func_address: u64) -> (usize, u64) {
match self.kind {
RelocationKind::Abs8
| RelocationKind::Arm64Movw0
| RelocationKind::Arm64Movw1
| RelocationKind::Arm64Movw2
| RelocationKind::Arm64Movw3 => {
let reloc_address = start + self.offset as usize;
let reloc_addend = self.addend as isize;
let reloc_abs = target_func_address
.checked_add(reloc_addend as u64)
.unwrap();
(reloc_address, reloc_abs)
}
RelocationKind::X86PCRel4 => {
let reloc_address = start + self.offset as usize;
let reloc_addend = self.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();
(reloc_address, reloc_delta_u32 as u64)
}
RelocationKind::X86PCRel8 => {
let reloc_address = start + self.offset as usize;
let reloc_addend = self.addend as isize;
let reloc_delta = target_func_address
.wrapping_sub(reloc_address as u64)
.checked_add(reloc_addend as u64)
.unwrap();
(reloc_address, reloc_delta)
}
RelocationKind::X86CallPCRel4 | RelocationKind::X86CallPLTRel4 => {
let reloc_address = start + self.offset as usize;
let reloc_addend = self.addend as isize;
let reloc_delta_u32 = (target_func_address as u32)
.wrapping_sub(reloc_address as u32)
.wrapping_add(reloc_addend as u32);
(reloc_address, reloc_delta_u32 as u64)
}
RelocationKind::Arm64Call => {
let reloc_address = start + self.offset as usize;
let reloc_addend = self.addend as isize;
let reloc_delta_u32 = target_func_address
.wrapping_sub(reloc_address as u64)
.wrapping_add(reloc_addend as u64);
(reloc_address, reloc_delta_u32)
}
// RelocationKind::X86PCRelRodata4 => {
// (start, target_func_address)
// }
_ => panic!("Relocation kind unsupported"),
}
}
}
/// Relocations to apply to function bodies.
pub type Relocations = PrimaryMap<LocalFunctionIndex, Vec<Relocation>>;