use crate::arch::x86::{DecodedInsn, Mnemonic, format_intel};
use crate::ast::Stmt;
use super::{Candidate, Pattern, PatternCtx};
pub struct Lea;
impl Pattern for Lea {
fn name(&self) -> &'static str {
"lea"
}
fn tentative(
&self,
ctx: &PatternCtx,
insns: &[DecodedInsn],
start: usize,
) -> Option<Candidate> {
let ins = insns.get(start)?;
if ins.iced.mnemonic() != Mnemonic::Lea {
return None;
}
let (dst, src) = super::mov::split_two_operands(&format_intel(&ins.iced), "lea ")?;
let sp = ctx.sp_delta_at.get(&ins.iced.ip()).copied();
let src = format!("&{}", crate::arch::x86::rename_operand_in_ctx(&src, sp));
Some(Candidate {
pattern: self.name(),
start,
consumed: 1,
priority: 50,
stmts: vec![Stmt::Move {
dst: crate::arch::x86::rename_operand_in_ctx(&dst, sp),
src,
bytes: ins.original_bytes.clone(),
}],
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::arch::x86::{Bitness, decode};
use std::collections::HashMap;
fn ctx() -> PatternCtx<'static> {
let map: &'static HashMap<u64, String> = Box::leak(Box::new(HashMap::new()));
let sp_map: &'static HashMap<u64, i64> = Box::leak(Box::new(HashMap::new()));
PatternCtx {
fn_addr_start: 0,
fn_addr_end: u64::MAX,
name_at: map,
sp_delta_at: sp_map,
}
}
#[test]
fn lifts_lea_reg_mem() {
let bytes = [0x8d, 0x04, 0x8b];
let insns = decode(Bitness::Bits32, &bytes, 0).unwrap();
let c = Lea.tentative(&ctx(), &insns, 0).expect("match");
if let Some(Stmt::Move { dst, src, .. }) = c.stmts.first() {
assert_eq!(dst, "eax");
assert!(src.starts_with('&'), "src should start with &, got {src}");
}
}
}