Line data Source code
1 : use lief_ffi as ffi;
2 :
3 : use crate::{assembly::aarch64::registers::Reg, common::FromFFI};
4 :
5 : use super::Operand;
6 :
7 : /// This structure represents a memory operand.
8 : ///
9 : /// ```text
10 : /// ldr x0, [x1, x2, lsl #3]
11 : /// | | |
12 : /// +------------+ | +--------+
13 : /// | | |
14 : /// v v v
15 : /// Base Reg Offset Shift
16 : ///
17 : /// ```
18 : pub struct Memory {
19 : ptr: cxx::UniquePtr<ffi::asm_aarch64_operands_Memory>,
20 : }
21 :
22 : impl FromFFI<ffi::asm_aarch64_operands_Memory> for Memory {
23 0 : fn from_ffi(ptr: cxx::UniquePtr<ffi::asm_aarch64_operands_Memory>) -> Self {
24 0 : Self { ptr }
25 0 : }
26 : }
27 :
28 : impl Operand for Memory {
29 : #[doc(hidden)]
30 0 : fn as_generic(&self) -> &ffi::asm_aarch64_Operand {
31 0 : self.ptr.as_ref().unwrap().as_ref()
32 0 : }
33 : }
34 :
35 : /// Wraps a memory offset as an integer offset or as a register offset
36 0 : #[derive(Debug)]
37 : pub enum Offset {
38 : /// Register offset
39 : Reg(Reg),
40 : /// Integer offset
41 : Displacement(i64),
42 : }
43 :
44 : #[allow(non_camel_case_types)]
45 0 : #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
46 : pub enum Shift {
47 : Unknown,
48 : Lsl,
49 : Uxtx,
50 : Uxtw,
51 : Sxtx,
52 : Sxtw,
53 : }
54 :
55 : impl From<i32> for Shift {
56 0 : fn from(value: i32) -> Self {
57 0 : match value {
58 0 : 0 => Shift::Unknown,
59 0 : 1 => Shift::Lsl,
60 0 : 2 => Shift::Uxtx,
61 0 : 3 => Shift::Uxtw,
62 0 : 4 => Shift::Sxtx,
63 0 : 5 => Shift::Sxtw,
64 0 : _ => Shift::Unknown,
65 : }
66 0 : }
67 : }
68 :
69 : /// This structure holds shift info (type + value)
70 0 : #[derive(Debug)]
71 : pub struct ShiftInfo {
72 : pub shift_type: Shift,
73 : pub value: i8,
74 : }
75 :
76 : impl ShiftInfo {
77 0 : pub fn new(shift: Shift, value: i8) -> Self {
78 0 : Self {
79 0 : shift_type: shift,
80 0 : value,
81 0 : }
82 0 : }
83 : }
84 :
85 : impl Memory {
86 : /// The base register.
87 : ///
88 : /// For `str x3, [x8, #8]` it would return `x8`
89 0 : pub fn base(&self) -> Reg {
90 0 : Reg::from(self.ptr.base())
91 0 : }
92 :
93 : /// The addressing offset.
94 : ///
95 : /// It can be either:
96 : /// - A register (e.g. `ldr x0, [x1, x3]`)
97 : /// - An offset (e.g. `ldr x0, [x1, #8]`)
98 0 : pub fn offset(&self) -> Option<Offset> {
99 0 : let ffi_offset = self.ptr.offset();
100 0 : match ffi_offset.enum_type {
101 0 : 1 => Some(Offset::Reg(Reg::from(ffi_offset.value))),
102 0 : 2 => Some(Offset::Displacement(ffi_offset.value as i64)),
103 0 : _ => None,
104 : }
105 0 : }
106 :
107 : /// Shift information.
108 : ///
109 : /// For instance, for `ldr x1, [x2, x3, lsl #3]` it would
110 : /// return a [`Shift::Lsl`] with a [`ShiftInfo::value`] set to `3`
111 0 : pub fn shift(&self) -> Option<ShiftInfo> {
112 0 : let ffi_shift = self.ptr.shift();
113 0 : if ffi_shift.value == 0 {
114 0 : return None;
115 0 : }
116 0 : Some(ShiftInfo::new(
117 0 : Shift::from(ffi_shift.enum_type),
118 0 : ffi_shift.value,
119 0 : ))
120 0 : }
121 : }
|