use crate::iced_constants::IcedConstants;
#[cfg(feature = "encoder")]
use crate::iced_error::IcedError;
use crate::*;
#[cfg(feature = "decoder")]
#[inline]
pub(crate) fn internal_set_len(this: &mut Instruction, len: u32) {
debug_assert!(len <= IcedConstants::MAX_INSTRUCTION_LENGTH as u32);
this.len = len as u8;
}
#[cfg(feature = "decoder")]
#[inline]
pub(crate) fn internal_set_code_size(this: &mut Instruction, new_value: CodeSize) {
this.flags1 |= (new_value as u32) << InstrFlags1::CODE_SIZE_SHIFT;
}
#[cfg(feature = "instr_info")]
#[must_use]
#[inline]
pub(crate) const fn internal_has_repe_or_repne_prefix(this: &Instruction) -> bool {
(this.flags1 & (InstrFlags1::REPE_PREFIX | InstrFlags1::REPNE_PREFIX)) != 0
}
#[cfg(any(feature = "decoder", feature = "encoder"))]
#[inline]
pub(crate) fn internal_set_has_repe_prefix(this: &mut Instruction) {
this.flags1 = (this.flags1 & !InstrFlags1::REPNE_PREFIX) | InstrFlags1::REPE_PREFIX
}
#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm", feature = "fast_fmt"))]
#[inline]
pub(crate) const fn internal_has_any_of_lock_rep_repne_prefix(this: &Instruction) -> u32 {
this.flags1 & (InstrFlags1::LOCK_PREFIX | InstrFlags1::REPE_PREFIX | InstrFlags1::REPNE_PREFIX)
}
#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm", feature = "fast_fmt"))]
#[inline]
pub(crate) const fn internal_has_op_mask_or_zeroing_masking(this: &Instruction) -> bool {
(this.flags1 & ((InstrFlags1::OP_MASK_MASK << InstrFlags1::OP_MASK_SHIFT) | InstrFlags1::ZEROING_MASKING)) != 0
}
#[cfg(feature = "decoder")]
#[inline]
pub(crate) fn internal_clear_has_repe_repne_prefix(this: &mut Instruction) {
this.flags1 &= !(InstrFlags1::REPE_PREFIX | InstrFlags1::REPNE_PREFIX)
}
#[cfg(any(feature = "decoder", feature = "encoder"))]
#[inline]
pub(crate) fn internal_set_has_repne_prefix(this: &mut Instruction) {
this.flags1 = (this.flags1 & !InstrFlags1::REPE_PREFIX) | InstrFlags1::REPNE_PREFIX
}
#[cfg(feature = "instr_info")]
#[must_use]
#[inline]
pub(crate) const fn internal_op0_is_not_reg_or_op1_is_not_reg(this: &Instruction) -> bool {
const _: () = assert!(Register::None as u32 == 0);
((this.op_kinds[0] as RegisterUnderlyingType) | (this.op_kinds[1] as RegisterUnderlyingType)) != 0
}
#[cfg(feature = "decoder")]
#[inline]
pub(crate) fn internal_set_memory_displ_size(this: &mut Instruction, new_value: u32) {
debug_assert!(new_value <= 4);
this.displ_size = new_value as u8;
}
#[must_use]
#[inline]
pub(crate) const fn internal_get_memory_index_scale(this: &Instruction) -> u32 {
this.scale as u32
}
#[cfg(feature = "decoder")]
#[inline]
pub(crate) fn internal_set_memory_index_scale(this: &mut Instruction, new_value: InstrScale) {
this.scale = new_value;
}
#[cfg(any(feature = "decoder", feature = "encoder"))]
#[inline]
pub(crate) fn internal_set_immediate8(this: &mut Instruction, new_value: u32) {
this.immediate = new_value;
}
#[cfg(any(feature = "decoder", feature = "encoder"))]
#[inline]
pub(crate) fn internal_set_immediate8_2nd(this: &mut Instruction, new_value: u32) {
this.mem_displ = new_value as u64;
}
#[cfg(any(feature = "decoder", feature = "encoder"))]
#[inline]
pub(crate) fn internal_set_immediate16(this: &mut Instruction, new_value: u32) {
this.immediate = new_value;
}
#[cfg(feature = "decoder")]
#[inline]
pub(crate) fn internal_set_immediate64_lo(this: &mut Instruction, new_value: u32) {
this.immediate = new_value;
}
#[cfg(feature = "decoder")]
#[inline]
pub(crate) fn internal_set_immediate64_hi(this: &mut Instruction, new_value: u32) {
this.mem_displ = new_value as u64;
}
#[cfg(feature = "decoder")]
#[inline]
pub(crate) fn internal_set_near_branch16(this: &mut Instruction, new_value: u32) {
this.mem_displ = new_value as u64;
}
#[cfg(feature = "decoder")]
#[inline]
pub(crate) fn internal_set_far_branch16(this: &mut Instruction, new_value: u32) {
this.immediate = new_value;
}
#[cfg(feature = "decoder")]
#[inline]
pub(crate) fn internal_set_far_branch_selector(this: &mut Instruction, new_value: u32) {
this.mem_displ = new_value as u64;
}
#[cfg(feature = "fast_fmt")]
#[inline]
pub(crate) const fn internal_segment_prefix_raw(this: &Instruction) -> u32 {
((this.flags1 >> InstrFlags1::SEGMENT_PREFIX_SHIFT) & InstrFlags1::SEGMENT_PREFIX_MASK).wrapping_sub(1)
}
#[cfg(feature = "fast_fmt")]
#[inline]
pub(crate) fn internal_op_register(this: &Instruction, operand: u32) -> Register {
const _: () = assert!(IcedConstants::MAX_OP_COUNT == 5);
if let Some(®) = this.regs.get(operand as usize) {
reg
} else {
debug_assert_eq!(operand, 4);
this.op4_register()
}
}
#[cfg(feature = "encoder")]
#[cfg(any(not(feature = "no_evex"), feature = "mvex"))]
#[must_use]
#[inline]
pub(crate) const fn internal_op_mask(this: &Instruction) -> u32 {
(this.flags1 >> InstrFlags1::OP_MASK_SHIFT) & InstrFlags1::OP_MASK_MASK
}
#[cfg(feature = "decoder")]
#[cfg(any(not(feature = "no_evex"), feature = "mvex"))]
#[inline]
pub(crate) fn internal_set_op_mask(this: &mut Instruction, new_value: u32) {
debug_assert!(new_value <= 7);
this.flags1 |= new_value << InstrFlags1::OP_MASK_SHIFT
}
#[cfg(feature = "decoder")]
#[cfg(any(not(feature = "no_evex"), feature = "mvex"))]
#[inline]
pub(crate) fn internal_set_rounding_control(this: &mut Instruction, new_value: u32) {
debug_assert!(new_value < IcedConstants::ROUNDING_CONTROL_ENUM_COUNT as u32);
this.flags1 |= new_value << InstrFlags1::ROUNDING_CONTROL_SHIFT;
}
#[cfg(any(feature = "intel", feature = "masm", feature = "fast_fmt"))]
#[inline]
pub(crate) const fn internal_has_rounding_control_or_sae(this: &Instruction) -> bool {
(this.flags1 & ((InstrFlags1::ROUNDING_CONTROL_MASK << InstrFlags1::ROUNDING_CONTROL_SHIFT) | InstrFlags1::SUPPRESS_ALL_EXCEPTIONS)) != 0
}
#[cfg(feature = "encoder")]
#[inline]
pub(crate) fn internal_set_declare_data_len(this: &mut Instruction, new_value: u32) {
debug_assert!(new_value <= 0x10);
this.flags1 |= (new_value - 1) << InstrFlags1::DATA_LENGTH_SHIFT;
}
#[cfg(all(feature = "decoder", feature = "mvex"))]
#[inline]
pub(crate) fn internal_set_mvex_reg_mem_conv(this: &mut Instruction, new_value: u32) {
debug_assert!(new_value < IcedConstants::MVEX_REG_MEM_CONV_ENUM_COUNT as u32);
this.immediate |= new_value << MvexInstrFlags::MVEX_REG_MEM_CONV_SHIFT;
}
#[rustfmt::skip]
static REG_TO_ADDR_SIZE: [u8; IcedConstants::REGISTER_ENUM_COUNT] = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ];
#[must_use]
pub(crate) fn get_address_size_in_bytes(base_reg: Register, index_reg: Register, displ_size: u32, code_size: CodeSize) -> u32 {
let size = REG_TO_ADDR_SIZE[base_reg as usize] | REG_TO_ADDR_SIZE[index_reg as usize];
if size != 0 {
size as u32
} else if displ_size >= 2 {
displ_size
} else {
match code_size {
CodeSize::Code64 => 8,
CodeSize::Code32 => 4,
CodeSize::Code16 => 2,
_ => 8,
}
}
}
#[cfg(feature = "encoder")]
pub(crate) fn initialize_signed_immediate(instruction: &mut Instruction, operand: usize, immediate: i64) -> Result<(), IcedError> {
let op_kind = get_immediate_op_kind(instruction.code(), operand)?;
instruction.try_set_op_kind(operand as u32, op_kind)?;
match op_kind {
OpKind::Immediate8 => {
if i8::MIN as i64 <= immediate && immediate <= u8::MAX as i64 {
internal_set_immediate8(instruction, immediate as u8 as u32);
return Ok(());
}
}
OpKind::Immediate8_2nd => {
if i8::MIN as i64 <= immediate && immediate <= u8::MAX as i64 {
internal_set_immediate8_2nd(instruction, immediate as u8 as u32);
return Ok(());
}
}
OpKind::Immediate8to16 => {
if i8::MIN as i64 <= immediate && immediate <= i8::MAX as i64 {
internal_set_immediate8(instruction, immediate as u8 as u32);
return Ok(());
}
}
OpKind::Immediate8to32 => {
if i8::MIN as i64 <= immediate && immediate <= i8::MAX as i64 {
internal_set_immediate8(instruction, immediate as u8 as u32);
return Ok(());
}
}
OpKind::Immediate8to64 => {
if i8::MIN as i64 <= immediate && immediate <= i8::MAX as i64 {
internal_set_immediate8(instruction, immediate as u8 as u32);
return Ok(());
}
}
OpKind::Immediate16 => {
if i16::MIN as i64 <= immediate && immediate <= u16::MAX as i64 {
internal_set_immediate16(instruction, immediate as u16 as u32);
return Ok(());
}
}
OpKind::Immediate32 => {
if i32::MIN as i64 <= immediate && immediate <= u32::MAX as i64 {
instruction.set_immediate32(immediate as u32);
return Ok(());
}
}
OpKind::Immediate32to64 => {
if i32::MIN as i64 <= immediate && immediate <= i32::MAX as i64 {
instruction.set_immediate32(immediate as u32);
return Ok(());
}
}
OpKind::Immediate64 => {
instruction.set_immediate64(immediate as u64);
return Ok(());
}
_ => return Err(IcedError::new("Not an immediate operand")),
}
Err(IcedError::new("Invalid signed immediate"))
}
#[cfg(feature = "encoder")]
pub(crate) fn initialize_unsigned_immediate(instruction: &mut Instruction, operand: usize, immediate: u64) -> Result<(), IcedError> {
let op_kind = get_immediate_op_kind(instruction.code(), operand)?;
instruction.try_set_op_kind(operand as u32, op_kind)?;
match op_kind {
OpKind::Immediate8 => {
if immediate <= u8::MAX as u64 {
internal_set_immediate8(instruction, immediate as u8 as u32);
return Ok(());
}
}
OpKind::Immediate8_2nd => {
if immediate <= u8::MAX as u64 {
internal_set_immediate8_2nd(instruction, immediate as u8 as u32);
return Ok(());
}
}
OpKind::Immediate8to16 => {
if immediate <= i8::MAX as u64 || (0xFF80 <= immediate && immediate <= 0xFFFF) {
internal_set_immediate8(instruction, immediate as u8 as u32);
return Ok(());
}
}
OpKind::Immediate8to32 => {
if immediate <= i8::MAX as u64 || (0xFFFF_FF80 <= immediate && immediate <= 0xFFFF_FFFF) {
internal_set_immediate8(instruction, immediate as u8 as u32);
return Ok(());
}
}
OpKind::Immediate8to64 => {
if immediate.wrapping_add(0x80) <= u8::MAX as u64 {
internal_set_immediate8(instruction, immediate as u8 as u32);
return Ok(());
}
}
OpKind::Immediate16 => {
if immediate <= u16::MAX as u64 {
internal_set_immediate16(instruction, immediate as u16 as u32);
return Ok(());
}
}
OpKind::Immediate32 => {
if immediate <= u32::MAX as u64 {
instruction.set_immediate32(immediate as u32);
return Ok(());
}
}
OpKind::Immediate32to64 => {
if immediate.wrapping_add(0x8000_0000) <= u32::MAX as u64 {
instruction.set_immediate32(immediate as u32);
return Ok(());
}
}
OpKind::Immediate64 => {
instruction.set_immediate64(immediate);
return Ok(());
}
_ => return Err(IcedError::new("Not an immediate operand")),
}
Err(IcedError::new("Invalid unsigned immediate"))
}
#[cfg(feature = "encoder")]
fn get_immediate_op_kind(code: Code, operand: usize) -> Result<OpKind, IcedError> {
let operands = &crate::encoder::handlers_table::HANDLERS_TABLE[code as usize].operands;
if let Some(op) = operands.get(operand) {
match op.immediate_op_kind() {
Some(op_kind) => {
if op_kind == OpKind::Immediate8 && operand > 0 && operand + 1 == operands.len() {
if let Some(op_prev) = operands.get(operand.wrapping_sub(1)) {
match op_prev.immediate_op_kind() {
Some(OpKind::Immediate8) | Some(OpKind::Immediate16) => Ok(OpKind::Immediate8_2nd),
_ => Ok(op_kind),
}
} else {
Ok(op_kind)
}
} else {
Ok(op_kind)
}
}
None => {
if cfg!(debug_assertions) {
Err(IcedError::with_string(format!("{:?}'s op{} isn't an immediate operand", code, operand)))
} else {
Err(IcedError::with_string(format!("Code value {}'s op{} isn't an immediate operand", code as u32, operand)))
}
}
}
} else {
if cfg!(debug_assertions) {
Err(IcedError::with_string(format!("{:?} doesn't have at least {} operands", code, operand + 1)))
} else {
Err(IcedError::with_string(format!("Code value {} doesn't have at least {} operands", code as u32, operand + 1)))
}
}
}
#[cfg(feature = "encoder")]
pub(crate) fn get_near_branch_op_kind(code: Code, operand: usize) -> Result<OpKind, IcedError> {
let operands = &crate::encoder::handlers_table::HANDLERS_TABLE[code as usize].operands;
if let Some(op) = operands.get(operand) {
match op.near_branch_op_kind() {
Some(op_kind) => Ok(op_kind),
None => {
if cfg!(debug_assertions) {
Err(IcedError::with_string(format!("{:?}'s op{} isn't a near branch operand", code, operand)))
} else {
Err(IcedError::with_string(format!("Code value {}'s op{} isn't a near branch operand", code as u32, operand)))
}
}
}
} else {
if cfg!(debug_assertions) {
Err(IcedError::with_string(format!("{:?} doesn't have at least {} operands", code, operand + 1)))
} else {
Err(IcedError::with_string(format!("Code value {} doesn't have at least {} operands", code as u32, operand + 1)))
}
}
}
#[cfg(feature = "encoder")]
pub(crate) fn get_far_branch_op_kind(code: Code, operand: usize) -> Result<OpKind, IcedError> {
let operands = &crate::encoder::handlers_table::HANDLERS_TABLE[code as usize].operands;
if let Some(op) = operands.get(operand) {
match op.far_branch_op_kind() {
Some(op_kind) => Ok(op_kind),
None => {
if cfg!(debug_assertions) {
Err(IcedError::with_string(format!("{:?}'s op{} isn't a far branch operand", code, operand)))
} else {
Err(IcedError::with_string(format!("Code value {}'s op{} isn't a far branch operand", code as u32, operand)))
}
}
}
} else {
if cfg!(debug_assertions) {
Err(IcedError::with_string(format!("{:?} doesn't have at least {} operands", code, operand + 1)))
} else {
Err(IcedError::with_string(format!("Code value {} doesn't have at least {} operands", code as u32, operand + 1)))
}
}
}
#[cfg(feature = "encoder")]
pub(crate) fn with_string_reg_segrsi(
code: Code, address_size: u32, register: Register, segment_prefix: Register, rep_prefix: RepPrefixKind,
) -> Result<Instruction, IcedError> {
let mut instruction = Instruction::default();
instruction.set_code(code);
match rep_prefix {
RepPrefixKind::None => {}
RepPrefixKind::Repe => internal_set_has_repe_prefix(&mut instruction),
RepPrefixKind::Repne => internal_set_has_repne_prefix(&mut instruction),
}
const _: () = assert!(OpKind::Register as u32 == 0);
instruction.set_op0_register(register);
match address_size {
64 => instruction.set_op1_kind(OpKind::MemorySegRSI),
32 => instruction.set_op1_kind(OpKind::MemorySegESI),
16 => instruction.set_op1_kind(OpKind::MemorySegSI),
_ => return Err(IcedError::new("Invalid address size")),
}
instruction.set_segment_prefix(segment_prefix);
debug_assert_eq!(instruction.op_count(), 2);
Ok(instruction)
}
#[cfg(feature = "encoder")]
pub(crate) fn with_string_reg_esrdi(code: Code, address_size: u32, register: Register, rep_prefix: RepPrefixKind) -> Result<Instruction, IcedError> {
let mut instruction = Instruction::default();
instruction.set_code(code);
match rep_prefix {
RepPrefixKind::None => {}
RepPrefixKind::Repe => internal_set_has_repe_prefix(&mut instruction),
RepPrefixKind::Repne => internal_set_has_repne_prefix(&mut instruction),
}
const _: () = assert!(OpKind::Register as u32 == 0);
instruction.set_op0_register(register);
match address_size {
64 => instruction.set_op1_kind(OpKind::MemoryESRDI),
32 => instruction.set_op1_kind(OpKind::MemoryESEDI),
16 => instruction.set_op1_kind(OpKind::MemoryESDI),
_ => return Err(IcedError::new("Invalid address size")),
}
debug_assert_eq!(instruction.op_count(), 2);
Ok(instruction)
}
#[cfg(feature = "encoder")]
pub(crate) fn with_string_esrdi_reg(code: Code, address_size: u32, register: Register, rep_prefix: RepPrefixKind) -> Result<Instruction, IcedError> {
let mut instruction = Instruction::default();
instruction.set_code(code);
match rep_prefix {
RepPrefixKind::None => {}
RepPrefixKind::Repe => internal_set_has_repe_prefix(&mut instruction),
RepPrefixKind::Repne => internal_set_has_repne_prefix(&mut instruction),
}
match address_size {
64 => instruction.set_op0_kind(OpKind::MemoryESRDI),
32 => instruction.set_op0_kind(OpKind::MemoryESEDI),
16 => instruction.set_op0_kind(OpKind::MemoryESDI),
_ => return Err(IcedError::new("Invalid address size")),
}
const _: () = assert!(OpKind::Register as u32 == 0);
instruction.set_op1_register(register);
debug_assert_eq!(instruction.op_count(), 2);
Ok(instruction)
}
#[cfg(feature = "encoder")]
pub(crate) fn with_string_segrsi_esrdi(
code: Code, address_size: u32, segment_prefix: Register, rep_prefix: RepPrefixKind,
) -> Result<Instruction, IcedError> {
let mut instruction = Instruction::default();
instruction.set_code(code);
match rep_prefix {
RepPrefixKind::None => {}
RepPrefixKind::Repe => internal_set_has_repe_prefix(&mut instruction),
RepPrefixKind::Repne => internal_set_has_repne_prefix(&mut instruction),
}
match address_size {
64 => {
instruction.set_op0_kind(OpKind::MemorySegRSI);
instruction.set_op1_kind(OpKind::MemoryESRDI);
}
32 => {
instruction.set_op0_kind(OpKind::MemorySegESI);
instruction.set_op1_kind(OpKind::MemoryESEDI);
}
16 => {
instruction.set_op0_kind(OpKind::MemorySegSI);
instruction.set_op1_kind(OpKind::MemoryESDI);
}
_ => return Err(IcedError::new("Invalid address size")),
}
instruction.set_segment_prefix(segment_prefix);
debug_assert_eq!(instruction.op_count(), 2);
Ok(instruction)
}
#[cfg(feature = "encoder")]
pub(crate) fn with_string_esrdi_segrsi(
code: Code, address_size: u32, segment_prefix: Register, rep_prefix: RepPrefixKind,
) -> Result<Instruction, IcedError> {
let mut instruction = Instruction::default();
instruction.set_code(code);
match rep_prefix {
RepPrefixKind::None => {}
RepPrefixKind::Repe => internal_set_has_repe_prefix(&mut instruction),
RepPrefixKind::Repne => internal_set_has_repne_prefix(&mut instruction),
}
match address_size {
64 => {
instruction.set_op0_kind(OpKind::MemoryESRDI);
instruction.set_op1_kind(OpKind::MemorySegRSI);
}
32 => {
instruction.set_op0_kind(OpKind::MemoryESEDI);
instruction.set_op1_kind(OpKind::MemorySegESI);
}
16 => {
instruction.set_op0_kind(OpKind::MemoryESDI);
instruction.set_op1_kind(OpKind::MemorySegSI);
}
_ => return Err(IcedError::new("Invalid address size")),
}
instruction.set_segment_prefix(segment_prefix);
debug_assert_eq!(instruction.op_count(), 2);
Ok(instruction)
}
#[cfg(feature = "encoder")]
pub(crate) fn with_maskmov(
code: Code, address_size: u32, register1: Register, register2: Register, segment_prefix: Register,
) -> Result<Instruction, IcedError> {
let mut instruction = Instruction::default();
instruction.set_code(code);
match address_size {
64 => instruction.set_op0_kind(OpKind::MemorySegRDI),
32 => instruction.set_op0_kind(OpKind::MemorySegEDI),
16 => instruction.set_op0_kind(OpKind::MemorySegDI),
_ => return Err(IcedError::new("Invalid address size")),
}
const _: () = assert!(OpKind::Register as u32 == 0);
instruction.set_op1_register(register1);
const _: () = assert!(OpKind::Register as u32 == 0);
instruction.set_op2_register(register2);
instruction.set_segment_prefix(segment_prefix);
debug_assert_eq!(instruction.op_count(), 3);
Ok(instruction)
}