retour\arch\x86\thunk/
x86.rs1use crate::pic::{FixedThunk, Thunkable};
2use generic_array::{typenum, GenericArray};
3use std::mem;
4
5#[repr(packed)]
6pub struct JumpRel {
7 opcode: u8,
8 operand: u32,
9}
10
11fn relative32(destination: usize, is_jump: bool) -> Box<dyn Thunkable> {
13 const CALL: u8 = 0xE8;
14 const JMP: u8 = 0xE9;
15
16 Box::new(FixedThunk::<typenum::U5>::new(move |source| {
17 let code = JumpRel {
18 opcode: if is_jump { JMP } else { CALL },
19 operand: calculate_displacement(source, destination, mem::size_of::<JumpRel>()),
20 };
21
22 let slice: [u8; 5] = unsafe { mem::transmute(code) };
23 GenericArray::clone_from_slice(&slice)
24 }))
25}
26
27pub fn nop() -> Box<dyn Thunkable> {
29 Box::new([0x90].to_vec())
30}
31
32pub fn call_rel32(destination: usize) -> Box<dyn Thunkable> {
34 relative32(destination, false)
35}
36
37pub fn jmp_rel32(destination: usize) -> Box<dyn Thunkable> {
39 relative32(destination, true)
40}
41
42#[repr(packed)]
43struct JccRel {
44 opcode0: u8,
45 opcode1: u8,
46 operand: u32,
47}
48
49pub fn jcc_rel32(destination: usize, condition: u8) -> Box<dyn Thunkable> {
51 Box::new(FixedThunk::<typenum::U6>::new(move |source| {
52 let code = JccRel {
53 opcode0: 0x0F,
54 opcode1: 0x80 | condition,
55 operand: calculate_displacement(source, destination, mem::size_of::<JccRel>()),
56 };
57
58 let slice: [u8; 6] = unsafe { mem::transmute(code) };
59 GenericArray::clone_from_slice(&slice)
60 }))
61}
62
63#[repr(packed)]
64pub struct JumpShort {
65 opcode: u8,
66 operand: i8,
67}
68
69pub fn jmp_rel8(displacement: i8) -> Box<dyn Thunkable> {
71 Box::new(FixedThunk::<typenum::U2>::new(move |_| {
72 let code = JumpShort {
73 opcode: 0xEB,
74 operand: displacement - mem::size_of::<JumpShort>() as i8,
75 };
76
77 let slice: [u8; 2] = unsafe { mem::transmute(code) };
78 GenericArray::clone_from_slice(&slice)
79 }))
80}
81
82fn calculate_displacement(source: usize, destination: usize, instruction_size: usize) -> u32 {
84 let displacement =
85 (destination as isize).wrapping_sub(source as isize + instruction_size as isize);
86
87 #[cfg(target_arch = "x86_64")]
90 assert!(crate::arch::is_within_range(displacement));
91
92 displacement as u32
93}