use lief_ffi as ffi;
use crate::{assembly::aarch64::registers::Reg, common::FromFFI};
use super::Operand;
pub struct Memory {
ptr: cxx::UniquePtr<ffi::asm_aarch64_operands_Memory>,
}
impl FromFFI<ffi::asm_aarch64_operands_Memory> for Memory {
fn from_ffi(ptr: cxx::UniquePtr<ffi::asm_aarch64_operands_Memory>) -> Self {
Self { ptr }
}
}
impl Operand for Memory {
#[doc(hidden)]
fn as_generic(&self) -> &ffi::asm_aarch64_Operand {
self.ptr.as_ref().unwrap().as_ref()
}
}
#[derive(Debug)]
pub enum Offset {
Reg(Reg),
Displacement(i64),
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Shift {
Unknown,
Lsl,
Uxtx,
Uxtw,
Sxtx,
Sxtw,
}
impl From<i32> for Shift {
fn from(value: i32) -> Self {
match value {
0 => Shift::Unknown,
1 => Shift::Lsl,
2 => Shift::Uxtx,
3 => Shift::Uxtw,
4 => Shift::Sxtx,
5 => Shift::Sxtw,
_ => Shift::Unknown,
}
}
}
#[derive(Debug)]
pub struct ShiftInfo {
pub shift_type: Shift,
pub value: i8,
}
impl ShiftInfo {
pub fn new(shift: Shift, value: i8) -> Self {
Self {
shift_type: shift,
value,
}
}
}
impl Memory {
pub fn base(&self) -> Reg {
Reg::from(self.ptr.base())
}
pub fn offset(&self) -> Option<Offset> {
let ffi_offset = self.ptr.offset();
match ffi_offset.enum_type {
1 => Some(Offset::Reg(Reg::from(ffi_offset.value))),
2 => Some(Offset::Displacement(ffi_offset.value as i64)),
_ => None,
}
}
pub fn shift(&self) -> Option<ShiftInfo> {
let ffi_shift = self.ptr.shift();
if ffi_shift.value == 0 {
return None;
}
Some(ShiftInfo::new(
Shift::from(ffi_shift.enum_type),
ffi_shift.value,
))
}
}