use crate::{Displacement, Encoding, GeneralPurposeRegister, Immediate, ModRM, Operand, REXPrefix, SIBByte};
#[derive(Eq, Ord, PartialOrd, PartialEq, Debug, Clone)]
pub enum Opcode {
MOVRM8R8 { r8: Operand, rm8: Operand },
MOVRM64R64 { r64: Operand, rm64: Operand },
MOVRM64IMM32 { imm: Immediate, rm64: Operand },
PUSHRM64 { rm64: Operand },
PUSHR64 { r64: GeneralPurposeRegister },
PUSHIMM32 { imm: Immediate },
}
impl Opcode {
pub fn to_bytes(&self) -> Vec<u8> {
match self {
Opcode::MOVRM8R8 { r8: _, rm8: _ } => vec![0x88],
Opcode::MOVRM64R64 { r64: _, rm64: _ } => vec![0x89],
Opcode::MOVRM64IMM32 { imm: _, rm64: _ } => vec![0xc7],
Opcode::PUSHRM64 { rm64: _ } => vec![0xff],
Opcode::PUSHR64 { r64 } => vec![0x50 + r64.number()],
Opcode::PUSHIMM32 { imm: _ } => vec![0x68],
}
}
pub fn encoding(&self) -> Encoding {
match self {
Opcode::MOVRM8R8 { r8: _, rm8: _ } => Encoding::MR,
Opcode::MOVRM64R64 { r64: _, rm64: _ } => Encoding::MR,
Opcode::MOVRM64IMM32 { rm64: _, imm: _ } => Encoding::MI,
Opcode::PUSHRM64 { rm64: _ } => Encoding::M,
Opcode::PUSHR64 { r64: _ } => Encoding::O,
Opcode::PUSHIMM32 { imm: _ } => Encoding::I,
}
}
pub fn rex_prefix(&self) -> Option<REXPrefix> {
match &self {
Opcode::MOVRM8R8 { rm8: _, r8: _ } => None,
Opcode::MOVRM64R64 { rm64, r64 } => {
Some(REXPrefix {
w_bit: true,
r_bit: rm64.is_expanded(),
x_bit: rm64.req_sib_byte() && rm64.index_reg_is_expanded(),
b_bit: r64.is_expanded(),
})
}
Opcode::MOVRM64IMM32 { rm64, imm: _ } => {
Some(
REXPrefix {
w_bit: true,
r_bit: rm64.is_expanded(),
x_bit: rm64.req_sib_byte() && rm64.index_reg_is_expanded(),
b_bit: false,
}
)
}
Opcode::PUSHRM64 { rm64: _ } => None,
Opcode::PUSHR64 { r64 } => {
if r64.is_expanded() {
Some(REXPrefix {
w_bit: false,
r_bit: false,
x_bit: false,
b_bit: true,
})
} else {
None
}
}
Opcode::PUSHIMM32 { imm: _ } => None,
}
}
#[allow(unreachable_patterns)]
pub fn modrm(&self) -> Option<ModRM> {
match &self {
Opcode::MOVRM8R8 { rm8, r8 } => {
Some(ModRM::new_mr(rm8.addressing_mode(), rm8, r8))
}
Opcode::MOVRM64R64 { rm64, r64 } => {
Some(ModRM::new_mr(rm64.addressing_mode(), rm64, r64))
}
Opcode::MOVRM64IMM32 { rm64, imm: _ } => {
Some(ModRM::new_mi(rm64.addressing_mode(), rm64))
}
Opcode::PUSHRM64 { rm64 } => {
Some(ModRM::new_mr(rm64.addressing_mode(), rm64, &Operand::GENERALREGISTER(GeneralPurposeRegister::RSI)))
}
_ => None,
}
}
pub fn get_displacement(&self) -> Option<Displacement> {
match &self {
Opcode::MOVRM8R8 { rm8, r8: _ } => rm8.get_displacement(),
Opcode::MOVRM64R64 { rm64, r64: _ } => rm64.get_displacement(),
Opcode::PUSHRM64 { rm64 } => rm64.get_displacement(),
_ => None,
}
}
pub fn get_immediate(&self) -> Option<Immediate> {
match &self {
Opcode::MOVRM64IMM32 { rm64: _, imm } => Some(*imm),
Opcode::PUSHIMM32 { imm } => Some(*imm),
_ => None,
}
}
pub fn sib_bite(&self) -> Option<SIBByte> {
match &self {
Opcode::MOVRM8R8 { rm8, r8: _ } => rm8.sib_byte(),
Opcode::MOVRM64R64 { rm64, r64: _ } => rm64.sib_byte(),
Opcode::PUSHRM64 { rm64 } => rm64.sib_byte(),
_ => None,
}
}
pub fn to_intel_string(&self) -> String {
match &self {
Opcode::MOVRM8R8 { rm8, r8 } => {
format!("mov {}, {}", rm8.to_intel_string(), r8.to_intel_string())
}
Opcode::MOVRM64R64 { rm64, r64 } => {
format!("mov {}, {}", rm64.to_intel_string(), r64.to_intel_string())
}
Opcode::MOVRM64IMM32 { rm64, imm } => {
format!("mov {}, {}", rm64.to_intel_string(), imm.to_intel_string())
}
Opcode::PUSHRM64 { rm64 } => {
format!("push {}", rm64.to_intel_string())
}
Opcode::PUSHR64 { r64 } => format!("push {}", r64.to_intel_string()),
Opcode::PUSHIMM32 { imm } => format!("push {}", imm.to_intel_string()),
}
}
pub fn to_at_string(&self) -> String {
match &self {
Opcode::MOVRM8R8 { rm8, r8 } => {
format!("movb {}, {}", r8.to_at_string(), rm8.to_at_string())
}
Opcode::MOVRM64R64 { rm64, r64 } => {
format!("movq {}, {}", r64.to_at_string(), rm64.to_at_string())
}
Opcode::MOVRM64IMM32 { rm64, imm } => {
format!("movq {}, {}", imm.to_at_string(), rm64.to_at_string())
}
Opcode::PUSHRM64 { rm64 } => {
format!("pushq {}", rm64.to_at_string())
}
Opcode::PUSHR64 { r64 } => format!("pushq {}", r64.to_at_string()),
Opcode::PUSHIMM32 { imm } => format!("pushq {}", imm.to_at_string()),
}
}
}