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