pub(super) mod enums;
mod fmt_data;
mod fmt_tbl;
mod mem_size_tbl;
mod options;
mod pseudo_ops_fast;
mod regs;
#[cfg(test)]
mod tests;
mod trait_options;
mod trait_options_fast_fmt;
use crate::formatter::fast::enums::*;
use crate::formatter::fast::fmt_tbl::FMT_DATA;
use crate::formatter::fast::mem_size_tbl::MEM_SIZE_TBL;
pub use crate::formatter::fast::options::*;
use crate::formatter::fast::pseudo_ops_fast::get_pseudo_ops;
use crate::formatter::fast::regs::REGS_TBL;
pub use crate::formatter::fast::trait_options::*;
pub use crate::formatter::fast::trait_options_fast_fmt::*;
use crate::formatter::fmt_utils_all::*;
use crate::formatter::instruction_internal::{self, get_address_size_in_bytes};
use crate::formatter::*;
use crate::iced_constants::IcedConstants;
use crate::*;
use alloc::boxed::Box;
use alloc::vec::Vec;
use core::marker::PhantomData;
use core::{mem, ptr, slice};
#[allow(dead_code)]
const MAX_FMT_INSTR_LEN: usize = {
const MAX_PREFIXES_LEN: usize = "es xacquire xrelease lock notrack repe repne ".len();
const MAX_OPERAND_LEN: usize = "fpustate108 ptr fs:[rax+zmm31*8+0x12345678]".len();
const MAX_DECORATOR1_LEN: usize = "{k3}{z}{eh}".len();
const MAX_DECORATOR2_LEN: usize = "{rn-sae}{float16}".len();
MAX_PREFIXES_LEN
+ crate::formatter::strings_data::MAX_STRING_LEN
+ MAX_DECORATOR1_LEN
+ (IcedConstants::MAX_OP_COUNT * (2+ MAX_OPERAND_LEN)) - 1+ MAX_DECORATOR2_LEN
};
const _: () = assert!(
MAX_FMT_INSTR_LEN ==
crate::formatter::strings_data::MAX_STRING_LEN
+ "es xacquire xrelease lock notrack repe repne \
fpustate108 ptr fs:[rax+zmm31*8+0x12345678]{k3}{z}{eh}, \
fpustate108 ptr fs:[rax+zmm31*8+0x12345678], \
fpustate108 ptr fs:[rax+zmm31*8+0x12345678], \
fpustate108 ptr fs:[rax+zmm31*8+0x12345678], \
fpustate108 ptr fs:[rax+zmm31*8+0x12345678]{rn-sae}{float16}"
.len()
);
const _: () = assert!(MAX_FMT_INSTR_LEN < 350);
macro_rules! mk_fast_str_ty {
($ty_name:ident, $size:literal) => {
#[repr(transparent)]
#[derive(Copy, Clone)]
struct $ty_name {
len_data: *const u8,
}
impl $ty_name {
const SIZE: usize = $size;
#[allow(dead_code)]
fn new(len_data: *const u8) -> Self {
debug_assert!(unsafe { *len_data as usize <= <$ty_name>::SIZE });
Self { len_data }
}
fn len(self) -> usize {
unsafe { *self.len_data as usize }
}
fn utf8_data(self) -> *const u8 {
unsafe { self.len_data.add(1) }
}
#[allow(dead_code)]
fn get_slice(self) -> &'static [u8] {
unsafe { slice::from_raw_parts(self.utf8_data(), self.len()) }
}
}
unsafe impl Send for $ty_name {}
unsafe impl Sync for $ty_name {}
};
}
mk_fast_str_ty! {FastString4, 4} mk_fast_str_ty! {FastString8, 8} mk_fast_str_ty! {FastString12, 12} mk_fast_str_ty! {FastString16, 16} mk_fast_str_ty! {FastString20, 20} type FastStringMnemonic = FastString20;
type FastStringMemorySize = FastString16;
type FastStringRegister = FastString8;
macro_rules! mk_const_fast_str {
($fast_ty:tt, $str:literal) => {{
const STR: &str = $str;
const _: () = assert!(STR.len() == 1 + <$fast_ty>::SIZE);
const _: () = assert!(STR.as_bytes()[0] as usize <= <$fast_ty>::SIZE);
$fast_ty { len_data: STR.as_ptr() }
}};
}
macro_rules! verify_output_has_enough_bytes_left {
($dst:ident, $dst_next_p:ident, $num_bytes:expr) => {
if unsafe { TraitOptions::verify_output_has_enough_bytes_left() } {
iced_assert!($dst.capacity() - ($dst_next_p as usize - $dst.as_ptr() as usize) >= $num_bytes);
}
};
}
macro_rules! write_fast_str {
($dst:ident, $dst_next_p:ident, $source_ty:ty, $source:ident) => {{
const DATA_LEN: usize = <$source_ty>::SIZE;
verify_output_has_enough_bytes_left!($dst, $dst_next_p, DATA_LEN);
unsafe {
ptr::copy_nonoverlapping(<$source_ty>::utf8_data($source), $dst_next_p, DATA_LEN);
}
debug_assert!(<$source_ty>::len($source) <= DATA_LEN);
$dst_next_p = unsafe { $dst_next_p.add(<$source_ty>::len($source)) };
}};
}
static HEX_GROUP2_UPPER: &str = "\
000102030405060708090A0B0C0D0E0F\
101112131415161718191A1B1C1D1E1F\
202122232425262728292A2B2C2D2E2F\
303132333435363738393A3B3C3D3E3F\
404142434445464748494A4B4C4D4E4F\
505152535455565758595A5B5C5D5E5F\
606162636465666768696A6B6C6D6E6F\
707172737475767778797A7B7C7D7E7F\
808182838485868788898A8B8C8D8E8F\
909192939495969798999A9B9C9D9E9F\
A0A1A2A3A4A5A6A7A8A9AAABACADAEAF\
B0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF\
C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF\
D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF\
E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF\
F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF\
__"; macro_rules! write_fast_hex2_rw_4bytes {
($dst:ident, $dst_next_p:ident, $value:ident, $lower_or_value:ident, $check_limit:literal) => {{
const DATA_LEN: usize = 4;
const REAL_LEN: usize = 2;
if $check_limit {
verify_output_has_enough_bytes_left!($dst, $dst_next_p, DATA_LEN);
}
debug_assert_eq!(HEX_GROUP2_UPPER.len(), 0xFF * REAL_LEN + DATA_LEN);
debug_assert!($value < 0x100);
debug_assert!($lower_or_value == 0 || $lower_or_value == 0x2020_2020);
#[allow(trivial_numeric_casts)]
unsafe {
let src_ptr = HEX_GROUP2_UPPER.as_ptr().add(($value as usize) * REAL_LEN) as *const u32;
ptr::write_unaligned($dst_next_p as *mut u32, ptr::read_unaligned(src_ptr) | $lower_or_value);
}
const _: () = assert!(REAL_LEN <= DATA_LEN);
$dst_next_p = unsafe { $dst_next_p.add(REAL_LEN) };
}};
}
macro_rules! write_fast_ascii_char {
($dst:ident, $dst_next_p:ident, $ch:expr, $check_limit:literal) => {{
const DATA_LEN: usize = 1;
if $check_limit {
verify_output_has_enough_bytes_left!($dst, $dst_next_p, DATA_LEN);
}
#[allow(trivial_numeric_casts)]
{
debug_assert!($ch as u32 <= 0x7F);
}
#[allow(trivial_numeric_casts)]
unsafe {
*$dst_next_p = $ch as u8;
}
$dst_next_p = unsafe { $dst_next_p.add(1) };
}};
}
macro_rules! write_fast_ascii_char_lit {
($dst:ident, $dst_next_p:ident, $ch:tt, $check_limit:literal) => {{
const _: () = assert!($ch as u32 <= 0x7F);
write_fast_ascii_char!($dst, $dst_next_p, $ch, $check_limit);
}};
}
macro_rules! update_vec_len {
($dst:ident, $dst_next_p:ident) => {
unsafe {
$dst.set_len($dst_next_p as usize - $dst.as_ptr() as usize);
}
};
}
macro_rules! use_dst_only_now {
($dst:ident, $dst_next_p:ident) => {
update_vec_len!($dst, $dst_next_p);
#[allow(unused_variables)]
let $dst_next_p: () = ();
};
}
macro_rules! use_dst_next_p_now {
($dst:ident, $dst_next_p:ident) => {
$dst.reserve(MAX_FMT_INSTR_LEN);
let mut $dst_next_p = unsafe { $dst.as_mut_ptr().add($dst.len()) };
};
}
macro_rules! call_format_register {
($slf:ident, $dst:ident, $dst_next_p:ident, $reg:expr) => {{
$dst_next_p = $slf.format_register($dst, $dst_next_p, $reg);
}};
}
macro_rules! call_format_number {
($slf:ident, $dst:ident, $dst_next_p:ident, $imm:expr) => {{
$dst_next_p = $slf.format_number($dst, $dst_next_p, $imm);
}};
}
macro_rules! call_write_symbol {
($slf:ident, $dst:ident, $dst_next_p:ident, $imm:expr, $sym:expr) => {{
$dst_next_p = $slf.write_symbol($dst, $dst_next_p, $imm, $sym);
}};
}
macro_rules! call_write_symbol2 {
($slf:ident, $dst:ident, $dst_next_p:ident, $imm:expr, $sym:expr, $write_minus_if_signed:literal) => {{
$dst_next_p = $slf.write_symbol2($dst, $dst_next_p, $imm, $sym, $write_minus_if_signed);
}};
}
macro_rules! format_memory_else_block {
($slf:ident, $dst:ident, $dst_next_p:ident, $need_plus:ident, $displ_size:ident, $displ:ident, $addr_size:ident) => {
if !$need_plus || ($displ_size != 0 && $displ != 0) {
if $need_plus {
let c = if $addr_size == 8 {
if $displ < 0 {
$displ = $displ.wrapping_neg();
'-'
} else {
'+'
}
} else if $addr_size == 4 {
if ($displ as i32) < 0 {
$displ = ($displ as i32).wrapping_neg() as u32 as i64;
'-'
} else {
'+'
}
} else {
debug_assert_eq!($addr_size, 2);
if ($displ as i16) < 0 {
$displ = ($displ as i16).wrapping_neg() as u16 as i64;
'-'
} else {
'+'
}
};
write_fast_ascii_char!($dst, $dst_next_p, c, true);
}
call_format_number!($slf, $dst, $dst_next_p, $displ as u64);
}
};
}
macro_rules! format_memory_code {
($slf:ident, $dst:ident, $dst_next_p:ident, $instruction:ident, $operand:expr, $seg_reg:expr, $base_reg:expr, $index_reg:expr,
$scale:expr, $displ_size:expr, $displ:expr, $addr_size:expr) => {
#[allow(trivial_numeric_casts)]
{
let mut base_reg = $base_reg;
let mut displ_size: u32 = $displ_size;
let mut displ: i64 = $displ;
debug_assert!(get_address_size_in_bytes(base_reg, $index_reg, displ_size, $instruction.code_size()) == $addr_size);
let abs_addr;
if base_reg == Register::RIP {
abs_addr = displ as u64;
if TraitOptions::rip_relative_addresses(&$slf.d.options) {
displ = displ.wrapping_sub($instruction.next_ip() as i64);
} else {
debug_assert_eq!($index_reg, Register::None);
base_reg = Register::None;
}
displ_size = 8;
} else if base_reg == Register::EIP {
abs_addr = displ as u32 as u64;
if TraitOptions::rip_relative_addresses(&$slf.d.options) {
displ = (displ as u32).wrapping_sub($instruction.next_ip32()) as i32 as i64;
} else {
debug_assert_eq!($index_reg, Register::None);
base_reg = Register::None;
}
displ_size = 4;
} else {
abs_addr = displ as u64;
}
let show_mem_size = TraitOptions::always_show_memory_size(&$slf.d.options) || {
let flags = $slf.d.code_flags[$instruction.code() as usize];
(flags & (FastFmtFlags::FORCE_MEM_SIZE as u8)) != 0 || $instruction.is_broadcast()
};
if show_mem_size {
let keywords = $slf.d.all_memory_sizes[$instruction.memory_size() as usize];
write_fast_str!($dst, $dst_next_p, FastStringMemorySize, keywords);
}
let seg_override;
if TraitOptions::always_show_segment_register(&$slf.d.options)
|| ({
seg_override = $instruction.segment_prefix();
seg_override != Register::None
} && !{
let notrack_prefix = seg_override == Register::DS && is_notrack_prefix_branch($instruction.code()) && {
let code_size = $instruction.code_size();
!((code_size == CodeSize::Code16 || code_size == CodeSize::Code32)
&& (base_reg == Register::BP || base_reg == Register::EBP || base_reg == Register::ESP))
};
notrack_prefix
} && (SpecializedFormatter::<TraitOptions>::SHOW_USELESS_PREFIXES
|| show_segment_prefix_bool(Register::None, $instruction, SpecializedFormatter::<TraitOptions>::SHOW_USELESS_PREFIXES)))
{
call_format_register!($slf, $dst, $dst_next_p, $seg_reg);
write_fast_ascii_char_lit!($dst, $dst_next_p, ':', true);
}
write_fast_ascii_char_lit!($dst, $dst_next_p, '[', true);
let mut need_plus = if base_reg != Register::None {
call_format_register!($slf, $dst, $dst_next_p, base_reg);
true
} else {
false
};
if $index_reg != Register::None {
if need_plus {
write_fast_ascii_char_lit!($dst, $dst_next_p, '+', true);
}
need_plus = true;
call_format_register!($slf, $dst, $dst_next_p, $index_reg);
if $addr_size != 2 && ($scale != 0 || base_reg == Register::None) {
let scale_str = SCALE_NUMBERS[$scale as usize];
write_fast_str!($dst, $dst_next_p, FastString4, scale_str);
}
}
if TraitOptions::ENABLE_SYMBOL_RESOLVER {
let mut vec: Vec<SymResTextPart<'_>> = Vec::new();
if let Some(ref symbol) = if let Some(ref mut symbol_resolver) = $slf.symbol_resolver {
to_owned(symbol_resolver.symbol($instruction, $operand, Some($operand), abs_addr, $addr_size), &mut vec)
} else {
None
} {
if need_plus {
let c = if (symbol.flags & SymbolFlags::SIGNED) != 0 { '-' } else { '+' };
write_fast_ascii_char!($dst, $dst_next_p, c, true);
} else if (symbol.flags & SymbolFlags::SIGNED) != 0 {
write_fast_ascii_char_lit!($dst, $dst_next_p, '-', true);
}
call_write_symbol2!($slf, $dst, $dst_next_p, abs_addr, symbol, false);
} else {
let addr_size = $addr_size;
format_memory_else_block!($slf, $dst, $dst_next_p, need_plus, displ_size, displ, addr_size);
}
} else {
let addr_size = $addr_size;
format_memory_else_block!($slf, $dst, $dst_next_p, need_plus, displ_size, displ, addr_size);
}
write_fast_ascii_char_lit!($dst, $dst_next_p, ']', true);
}
};
}
macro_rules! call_format_memory {
($slf:ident, $dst:ident, $dst_next_p:ident, $instruction:ident, $operand:ident, $seg_reg:expr, $base_reg:tt,
$index_reg:tt, $scale:tt, $displ_size:tt, $displ:tt, $addr_size:tt $(,)?) => {
{
if TraitOptions::__IS_FAST_FORMATTER {
$dst_next_p = $slf.format_memory(
$dst,
$dst_next_p,
$instruction,
$operand,
$seg_reg,
$base_reg,
$index_reg,
$scale,
$displ_size,
$displ,
$addr_size,
)
} else {
format_memory_code!(
$slf,
$dst,
$dst_next_p,
$instruction,
$operand,
$seg_reg,
$base_reg,
$index_reg,
$scale,
$displ_size,
$displ,
$addr_size
)
}
}
};
}
static SCALE_NUMBERS: [FastString4; 4] = [
mk_const_fast_str!(FastString4, "\x02*1 "),
mk_const_fast_str!(FastString4, "\x02*2 "),
mk_const_fast_str!(FastString4, "\x02*4 "),
mk_const_fast_str!(FastString4, "\x02*8 "),
];
const _: () = assert!(RoundingControl::None as u32 == 0);
const _: () = assert!(RoundingControl::RoundToNearest as u32 == 1);
const _: () = assert!(RoundingControl::RoundDown as u32 == 2);
const _: () = assert!(RoundingControl::RoundUp as u32 == 3);
const _: () = assert!(RoundingControl::RoundTowardZero as u32 == 4);
static RC_SAE_STRINGS: [FastString8; IcedConstants::ROUNDING_CONTROL_ENUM_COUNT] = [
mk_const_fast_str!(FastString8, "\x00 "),
mk_const_fast_str!(FastString8, "\x08{rn-sae}"),
mk_const_fast_str!(FastString8, "\x08{rd-sae}"),
mk_const_fast_str!(FastString8, "\x08{ru-sae}"),
mk_const_fast_str!(FastString8, "\x08{rz-sae}"),
];
static RC_STRINGS: [FastString4; IcedConstants::ROUNDING_CONTROL_ENUM_COUNT] = [
mk_const_fast_str!(FastString4, "\x00 "),
mk_const_fast_str!(FastString4, "\x04{rn}"),
mk_const_fast_str!(FastString4, "\x04{rd}"),
mk_const_fast_str!(FastString4, "\x04{ru}"),
mk_const_fast_str!(FastString4, "\x04{rz}"),
];
#[cfg(feature = "mvex")]
static MVEX_REG_MEM_CONSTS_32: [FastString12; IcedConstants::MVEX_REG_MEM_CONV_ENUM_COUNT] = [
mk_const_fast_str!(FastString12, "\x00 "),
mk_const_fast_str!(FastString12, "\x00 "),
mk_const_fast_str!(FastString12, "\x06{cdab} "),
mk_const_fast_str!(FastString12, "\x06{badc} "),
mk_const_fast_str!(FastString12, "\x06{dacb} "),
mk_const_fast_str!(FastString12, "\x06{aaaa} "),
mk_const_fast_str!(FastString12, "\x06{bbbb} "),
mk_const_fast_str!(FastString12, "\x06{cccc} "),
mk_const_fast_str!(FastString12, "\x06{dddd} "),
mk_const_fast_str!(FastString12, "\x00 "),
mk_const_fast_str!(FastString12, "\x07{1to16} "),
mk_const_fast_str!(FastString12, "\x07{4to16} "),
mk_const_fast_str!(FastString12, "\x09{float16} "),
mk_const_fast_str!(FastString12, "\x07{uint8} "),
mk_const_fast_str!(FastString12, "\x07{sint8} "),
mk_const_fast_str!(FastString12, "\x08{uint16} "),
mk_const_fast_str!(FastString12, "\x08{sint16} "),
];
#[cfg(feature = "mvex")]
static MVEX_REG_MEM_CONSTS_64: [FastString12; IcedConstants::MVEX_REG_MEM_CONV_ENUM_COUNT] = [
mk_const_fast_str!(FastString12, "\x00 "),
mk_const_fast_str!(FastString12, "\x00 "),
mk_const_fast_str!(FastString12, "\x06{cdab} "),
mk_const_fast_str!(FastString12, "\x06{badc} "),
mk_const_fast_str!(FastString12, "\x06{dacb} "),
mk_const_fast_str!(FastString12, "\x06{aaaa} "),
mk_const_fast_str!(FastString12, "\x06{bbbb} "),
mk_const_fast_str!(FastString12, "\x06{cccc} "),
mk_const_fast_str!(FastString12, "\x06{dddd} "),
mk_const_fast_str!(FastString12, "\x00 "),
mk_const_fast_str!(FastString12, "\x06{1to8} "),
mk_const_fast_str!(FastString12, "\x06{4to8} "),
mk_const_fast_str!(FastString12, "\x09{float16} "),
mk_const_fast_str!(FastString12, "\x07{uint8} "),
mk_const_fast_str!(FastString12, "\x07{sint8} "),
mk_const_fast_str!(FastString12, "\x08{uint16} "),
mk_const_fast_str!(FastString12, "\x08{sint16} "),
];
struct FmtTableData {
mnemonics: Box<[FastStringMnemonic; IcedConstants::CODE_ENUM_COUNT]>,
flags: Box<[u8; IcedConstants::CODE_ENUM_COUNT]>, }
#[allow(missing_debug_implementations)]
pub struct SpecializedFormatter<TraitOptions: SpecializedFormatterTraitOptions> {
d: SelfData,
symbol_resolver: Option<Box<dyn SymbolResolver>>,
_required_by_rustc: PhantomData<fn() -> TraitOptions>,
}
impl<TraitOptions: SpecializedFormatterTraitOptions> Default for SpecializedFormatter<TraitOptions> {
#[must_use]
#[inline]
fn default() -> Self {
SpecializedFormatter::<TraitOptions>::new()
}
}
struct SelfData {
options: FastFormatterOptions,
all_registers: &'static [FastStringRegister; IcedConstants::REGISTER_ENUM_COUNT],
code_mnemonics: &'static [FastStringMnemonic; IcedConstants::CODE_ENUM_COUNT],
code_flags: &'static [u8; IcedConstants::CODE_ENUM_COUNT],
all_memory_sizes: &'static [FastStringMemorySize; IcedConstants::MEMORY_SIZE_ENUM_COUNT],
}
impl<TraitOptions: SpecializedFormatterTraitOptions> SpecializedFormatter<TraitOptions> {
const SHOW_USELESS_PREFIXES: bool = true;
#[must_use]
#[inline]
#[allow(clippy::unwrap_used)]
pub fn new() -> Self {
SpecializedFormatter::<TraitOptions>::try_with_options(None).unwrap()
}
#[allow(clippy::missing_inline_in_public_items)]
pub fn try_with_options(symbol_resolver: Option<Box<dyn SymbolResolver>>) -> Result<Self, IcedError> {
if !TraitOptions::ENABLE_SYMBOL_RESOLVER && symbol_resolver.is_some() {
Err(IcedError::new(concat!(stringify!(TraitOptions::ENABLE_SYMBOL_RESOLVER), " is disabled so symbol resolvers aren't supported")))
} else {
Ok(Self {
d: SelfData {
options: FastFormatterOptions::new(),
all_registers: ®S_TBL,
code_mnemonics: &FMT_DATA.mnemonics,
code_flags: &FMT_DATA.flags,
all_memory_sizes: &MEM_SIZE_TBL,
},
symbol_resolver,
_required_by_rustc: PhantomData,
})
}
}
#[must_use]
#[inline]
pub fn options(&self) -> &FastFormatterOptions {
&self.d.options
}
#[must_use]
#[inline]
pub fn options_mut(&mut self) -> &mut FastFormatterOptions {
&mut self.d.options
}
#[allow(clippy::missing_inline_in_public_items)]
#[allow(clippy::let_unit_value)]
#[allow(clippy::useless_let_if_seq)]
pub fn format(&mut self, instruction: &Instruction, output: &mut String) {
let dst = unsafe { output.as_mut_vec() };
dst.reserve(MAX_FMT_INSTR_LEN);
let mut dst_next_p = unsafe { dst.as_mut_ptr().add(dst.len()) };
let code = instruction.code();
let mut mnemonic = self.d.code_mnemonics[code as usize];
let mut op_count = instruction.op_count();
if TraitOptions::use_pseudo_ops(&self.d.options) {
let flags = self.d.code_flags[code as usize];
let pseudo_ops_num = flags >> FastFmtFlags::PSEUDO_OPS_KIND_SHIFT;
if pseudo_ops_num != 0 && instruction.op_kind(op_count - 1) == OpKind::Immediate8 {
let mut index = instruction.immediate8() as usize;
let pseudo_ops_kind: PseudoOpsKind = unsafe { mem::transmute(pseudo_ops_num - 1) };
let pseudo_ops_kind = if pseudo_ops_kind == PseudoOpsKind::vpcmpd6 {
match code {
#[cfg(feature = "mvex")]
Code::MVEX_Vpcmpud_kr_k1_zmm_zmmmt_imm8 => PseudoOpsKind::vpcmpud6,
_ => pseudo_ops_kind,
}
} else {
pseudo_ops_kind
};
let pseudo_ops = get_pseudo_ops(pseudo_ops_kind);
if pseudo_ops_kind == PseudoOpsKind::pclmulqdq || pseudo_ops_kind == PseudoOpsKind::vpclmulqdq {
if index <= 1 {
} else if index == 0x10 {
index = 2;
} else if index == 0x11 {
index = 3;
} else {
index = usize::MAX;
}
}
if let Some(&pseudo_op_mnemonic) = pseudo_ops.get(index) {
mnemonic = pseudo_op_mnemonic;
op_count -= 1;
}
}
}
let prefix_seg = instruction_internal::internal_segment_prefix_raw(instruction);
const _: () = assert!(Register::None as u32 == 0);
if prefix_seg < 6 || instruction_internal::internal_has_any_of_lock_rep_repne_prefix(instruction) != 0 {
const DS_REG: u32 = Register::DS as u32 - Register::ES as u32;
let has_notrack_prefix = prefix_seg == DS_REG && is_notrack_prefix_branch(code);
if !has_notrack_prefix && prefix_seg < 6 && SpecializedFormatter::<TraitOptions>::show_segment_prefix(instruction, op_count) {
let prefix_seg = unsafe { mem::transmute((Register::ES as u32 + prefix_seg) as RegisterUnderlyingType) };
call_format_register!(self, dst, dst_next_p, prefix_seg);
write_fast_ascii_char_lit!(dst, dst_next_p, ' ', true);
}
let mut has_xacquire_xrelease = false;
if instruction.has_xacquire_prefix() {
const FAST_STR: FastString12 = mk_const_fast_str!(FastString12, "\x09xacquire ");
write_fast_str!(dst, dst_next_p, FastString12, FAST_STR);
has_xacquire_xrelease = true;
}
if instruction.has_xrelease_prefix() {
const FAST_STR: FastString12 = mk_const_fast_str!(FastString12, "\x09xrelease ");
write_fast_str!(dst, dst_next_p, FastString12, FAST_STR);
has_xacquire_xrelease = true;
}
if instruction.has_lock_prefix() {
const FAST_STR: FastString8 = mk_const_fast_str!(FastString8, "\x05lock ");
write_fast_str!(dst, dst_next_p, FastString8, FAST_STR);
}
if has_notrack_prefix {
const FAST_STR: FastString8 = mk_const_fast_str!(FastString8, "\x08notrack ");
write_fast_str!(dst, dst_next_p, FastString8, FAST_STR);
}
if !has_xacquire_xrelease {
if instruction.has_repe_prefix()
&& (SpecializedFormatter::<TraitOptions>::SHOW_USELESS_PREFIXES
|| show_rep_or_repe_prefix_bool(code, SpecializedFormatter::<TraitOptions>::SHOW_USELESS_PREFIXES))
{
if is_repe_or_repne_instruction(code) {
const FAST_STR: FastString8 = mk_const_fast_str!(FastString8, "\x05repe ");
write_fast_str!(dst, dst_next_p, FastString8, FAST_STR);
} else {
const FAST_STR: FastString4 = mk_const_fast_str!(FastString4, "\x04rep ");
write_fast_str!(dst, dst_next_p, FastString4, FAST_STR);
}
}
if instruction.has_repne_prefix() {
if (Code::Retnw_imm16 <= code && code <= Code::Retnq)
|| (Code::Call_rel16 <= code && code <= Code::Jmp_rel32_64)
|| (Code::Call_rm16 <= code && code <= Code::Call_rm64)
|| (Code::Jmp_rm16 <= code && code <= Code::Jmp_rm64)
|| code.is_jcc_short_or_near()
{
const FAST_STR: FastString4 = mk_const_fast_str!(FastString4, "\x04bnd ");
write_fast_str!(dst, dst_next_p, FastString4, FAST_STR);
} else if SpecializedFormatter::<TraitOptions>::SHOW_USELESS_PREFIXES
|| show_repne_prefix_bool(code, SpecializedFormatter::<TraitOptions>::SHOW_USELESS_PREFIXES)
{
const FAST_STR: FastString8 = mk_const_fast_str!(FastString8, "\x06repne ");
write_fast_str!(dst, dst_next_p, FastString8, FAST_STR);
}
}
}
}
write_fast_str!(dst, dst_next_p, FastStringMnemonic, mnemonic);
let is_declare_data;
let declare_data_kind = if !TraitOptions::ENABLE_DB_DW_DD_DQ {
is_declare_data = false;
OpKind::Register
} else if (code as u32).wrapping_sub(Code::DeclareByte as u32) <= (Code::DeclareQword as u32 - Code::DeclareByte as u32) {
op_count = instruction.declare_data_len() as u32;
is_declare_data = true;
match code {
Code::DeclareByte => OpKind::Immediate8,
Code::DeclareWord => OpKind::Immediate16,
Code::DeclareDword => OpKind::Immediate32,
_ => {
debug_assert_eq!(code, Code::DeclareQword);
OpKind::Immediate64
}
}
} else {
is_declare_data = false;
OpKind::Register
};
if op_count > 0 {
write_fast_ascii_char_lit!(dst, dst_next_p, ' ', true);
#[cfg(feature = "mvex")]
let mvex_rm_operand = {
if IcedConstants::is_mvex(instruction.code()) {
debug_assert_ne!(op_count, 0);
if instruction.op_kind(op_count.wrapping_sub(1)) == OpKind::Immediate8 {
op_count.wrapping_sub(2)
} else {
op_count.wrapping_sub(1)
}
} else {
u32::MAX
}
};
let mut operand = 0;
loop {
let imm8;
let imm16;
let imm32;
let imm64;
let imm_size;
let op_kind = if TraitOptions::ENABLE_DB_DW_DD_DQ && is_declare_data { declare_data_kind } else { instruction.op_kind(operand) };
macro_rules! fmt_near_branch {
($slf:ident, $dst:ident, $dst_next_p:ident, $instruction:ident, $imm_size:expr, $imm:ident) => {{
if TraitOptions::ENABLE_SYMBOL_RESOLVER {
let mut vec: Vec<SymResTextPart<'_>> = Vec::new();
if let Some(ref symbol) = if let Some(ref mut symbol_resolver) = $slf.symbol_resolver {
to_owned(symbol_resolver.symbol($instruction, operand, Some(operand), $imm, $imm_size), &mut vec)
} else {
None
} {
call_write_symbol!($slf, $dst, $dst_next_p, $imm, symbol);
} else {
call_format_number!($slf, $dst, $dst_next_p, $imm);
}
} else {
call_format_number!($slf, $dst, $dst_next_p, $imm);
}
}};
}
macro_rules! fmt_far_branch {
($slf:ident, $dst:ident, $dst_next_p:ident, $instruction:ident, $op_kind:ident, $imm_size_ident:ident, $imm64:ident) => {{
if $op_kind == OpKind::FarBranch32 {
$imm_size_ident = 4;
$imm64 = $instruction.far_branch32() as u64;
} else {
$imm_size_ident = 2;
$imm64 = $instruction.far_branch16() as u64;
}
if TraitOptions::ENABLE_SYMBOL_RESOLVER {
let mut vec: Vec<SymResTextPart<'_>> = Vec::new();
let mut vec2: Vec<SymResTextPart<'_>> = Vec::new();
if let Some(ref symbol) = if let Some(ref mut symbol_resolver) = $slf.symbol_resolver {
to_owned(
symbol_resolver.symbol($instruction, operand, Some(operand), $imm64 as u32 as u64, $imm_size_ident),
&mut vec,
)
} else {
None
} {
debug_assert!(operand + 1 == 1);
let selector_symbol = if let Some(ref mut symbol_resolver) = $slf.symbol_resolver {
to_owned(
symbol_resolver.symbol(
$instruction,
operand + 1,
Some(operand),
$instruction.far_branch_selector() as u64,
2,
),
&mut vec2,
)
} else {
None
};
if let Some(ref selector_symbol) = selector_symbol {
call_write_symbol!($slf, $dst, $dst_next_p, $instruction.far_branch_selector() as u64, selector_symbol);
} else {
call_format_number!($slf, $dst, $dst_next_p, $instruction.far_branch_selector() as u64);
}
write_fast_ascii_char_lit!(dst, dst_next_p, ':', true);
call_write_symbol!($slf, $dst, $dst_next_p, $imm64, symbol);
} else {
call_format_number!($slf, $dst, $dst_next_p, $instruction.far_branch_selector() as u64);
write_fast_ascii_char_lit!(dst, dst_next_p, ':', true);
call_format_number!($slf, $dst, $dst_next_p, $imm64);
}
} else {
call_format_number!($slf, $dst, $dst_next_p, $instruction.far_branch_selector() as u64);
write_fast_ascii_char_lit!(dst, dst_next_p, ':', true);
call_format_number!($slf, $dst, $dst_next_p, $imm64);
}
}};
}
macro_rules! fmt_imm {
($slf:ident, $dst:ident, $dst_next_p:ident, $instruction:ident, $imm:ident, $imm_size:literal) => {
#[allow(trivial_numeric_casts)]
{
if TraitOptions::ENABLE_SYMBOL_RESOLVER {
let mut vec: Vec<SymResTextPart<'_>> = Vec::new();
if let Some(ref symbol) = if let Some(ref mut symbol_resolver) = $slf.symbol_resolver {
to_owned(symbol_resolver.symbol($instruction, operand, Some(operand), $imm as u64, $imm_size), &mut vec)
} else {
None
} {
if (symbol.flags & SymbolFlags::RELATIVE) == 0 {
const FAST_STR: FastString8 = mk_const_fast_str!(FastString8, "\x07offset ");
write_fast_str!($dst, $dst_next_p, FastString8, FAST_STR);
}
call_write_symbol!($slf, $dst, $dst_next_p, $imm as u64, symbol);
} else {
call_format_number!($slf, $dst, $dst_next_p, $imm as u64);
}
} else {
call_format_number!($slf, $dst, $dst_next_p, $imm as u64);
}
}
};
}
macro_rules! fmt_register {
() => {{
call_format_register!(self, dst, dst_next_p, instruction_internal::internal_op_register(instruction, operand))
}};
}
macro_rules! fmt_far_br_16_32 {
() => {{
fmt_far_branch!(self, dst, dst_next_p, instruction, op_kind, imm_size, imm64)
}};
}
macro_rules! fmt_memory_seg_si {
() => {{
call_format_memory!(
self,
dst,
dst_next_p,
instruction,
operand,
(instruction.memory_segment()),
(Register::SI),
(Register::None),
0,
0,
0,
2,
)
}};
}
macro_rules! fmt_memory_seg_esi {
() => {{
call_format_memory!(
self,
dst,
dst_next_p,
instruction,
operand,
(instruction.memory_segment()),
(Register::ESI),
(Register::None),
0,
0,
0,
4,
)
}};
}
macro_rules! fmt_memory_seg_rsi {
() => {{
call_format_memory!(
self,
dst,
dst_next_p,
instruction,
operand,
(instruction.memory_segment()),
(Register::RSI),
(Register::None),
0,
0,
0,
8,
)
}};
}
macro_rules! fmt_memory_seg_di {
() => {{
call_format_memory!(
self,
dst,
dst_next_p,
instruction,
operand,
(instruction.memory_segment()),
(Register::DI),
(Register::None),
0,
0,
0,
2,
)
}};
}
macro_rules! fmt_memory_seg_edi {
() => {{
call_format_memory!(
self,
dst,
dst_next_p,
instruction,
operand,
(instruction.memory_segment()),
(Register::EDI),
(Register::None),
0,
0,
0,
4,
)
}};
}
macro_rules! fmt_memory_seg_rdi {
() => {{
call_format_memory!(
self,
dst,
dst_next_p,
instruction,
operand,
(instruction.memory_segment()),
(Register::RDI),
(Register::None),
0,
0,
0,
8,
)
}};
}
macro_rules! fmt_memory_es_di {
() => {{
call_format_memory!(self, dst, dst_next_p, instruction, operand, (Register::ES), (Register::DI), (Register::None), 0, 0, 0, 2)
}};
}
macro_rules! fmt_memory_es_edi {
() => {{
call_format_memory!(
self,
dst,
dst_next_p,
instruction,
operand,
(Register::ES),
(Register::EDI),
(Register::None),
0,
0,
0,
4
)
}};
}
macro_rules! fmt_memory_es_rdi {
() => {{
call_format_memory!(
self,
dst,
dst_next_p,
instruction,
operand,
(Register::ES),
(Register::RDI),
(Register::None),
0,
0,
0,
8
)
}};
}
macro_rules! fmt_memory {
() => {{
let displ_size = instruction.memory_displ_size();
let base_reg = instruction.memory_base();
let mut index_reg = instruction.memory_index();
let addr_size = get_address_size_in_bytes(base_reg, index_reg, displ_size, instruction.code_size());
let displ =
if addr_size == 8 { instruction.memory_displacement64() as i64 } else { instruction.memory_displacement32() as i64 };
if code == Code::Xlat_m8 {
index_reg = Register::None;
}
call_format_memory!(
self,
dst,
dst_next_p,
instruction,
operand,
(instruction.memory_segment()),
base_reg,
index_reg,
(instruction_internal::internal_get_memory_index_scale(instruction)),
displ_size,
displ,
addr_size,
);
#[cfg(feature = "mvex")]
if instruction.is_mvex_eviction_hint() {
const FAST_STR: FastString4 = mk_const_fast_str!(FastString4, "\x04{eh}");
write_fast_str!(dst, dst_next_p, FastString4, FAST_STR);
}
}};
}
if TraitOptions::__IS_FAST_FORMATTER {
match op_kind {
OpKind::Register => fmt_register!(),
OpKind::NearBranch16 | OpKind::NearBranch32 | OpKind::NearBranch64 => {
if op_kind == OpKind::NearBranch64 {
imm_size = 8;
imm64 = instruction.near_branch64();
} else if op_kind == OpKind::NearBranch32 {
imm_size = 4;
imm64 = instruction.near_branch32() as u64;
} else {
imm_size = 2;
imm64 = instruction.near_branch16() as u64;
}
fmt_near_branch!(self, dst, dst_next_p, instruction, imm_size, imm64);
}
OpKind::FarBranch16 | OpKind::FarBranch32 => fmt_far_br_16_32!(),
OpKind::Immediate8 | OpKind::Immediate8_2nd => {
if TraitOptions::ENABLE_DB_DW_DD_DQ && is_declare_data {
imm8 = instruction.get_declare_byte_value(operand as usize);
} else if op_kind == OpKind::Immediate8 {
imm8 = instruction.immediate8();
} else {
debug_assert_eq!(op_kind, OpKind::Immediate8_2nd);
imm8 = instruction.immediate8_2nd();
}
fmt_imm!(self, dst, dst_next_p, instruction, imm8, 1);
}
OpKind::Immediate16 | OpKind::Immediate8to16 => {
if TraitOptions::ENABLE_DB_DW_DD_DQ && is_declare_data {
imm16 = instruction.get_declare_word_value(operand as usize);
} else if op_kind == OpKind::Immediate16 {
imm16 = instruction.immediate16();
} else {
debug_assert_eq!(op_kind, OpKind::Immediate8to16);
imm16 = instruction.immediate8to16() as u16;
}
fmt_imm!(self, dst, dst_next_p, instruction, imm16, 2)
}
OpKind::Immediate32 | OpKind::Immediate8to32 => {
if TraitOptions::ENABLE_DB_DW_DD_DQ && is_declare_data {
imm32 = instruction.get_declare_dword_value(operand as usize);
} else if op_kind == OpKind::Immediate32 {
imm32 = instruction.immediate32();
} else {
debug_assert_eq!(op_kind, OpKind::Immediate8to32);
imm32 = instruction.immediate8to32() as u32;
}
fmt_imm!(self, dst, dst_next_p, instruction, imm32, 4)
}
OpKind::Immediate64 | OpKind::Immediate8to64 | OpKind::Immediate32to64 => {
if TraitOptions::ENABLE_DB_DW_DD_DQ && is_declare_data {
imm64 = instruction.get_declare_qword_value(operand as usize);
} else if op_kind == OpKind::Immediate32to64 {
imm64 = instruction.immediate32to64() as u64;
} else if op_kind == OpKind::Immediate8to64 {
imm64 = instruction.immediate8to64() as u64;
} else {
debug_assert_eq!(op_kind, OpKind::Immediate64);
imm64 = instruction.immediate64();
}
fmt_imm!(self, dst, dst_next_p, instruction, imm64, 8)
}
OpKind::MemorySegSI => fmt_memory_seg_si!(),
OpKind::MemorySegESI => fmt_memory_seg_esi!(),
OpKind::MemorySegRSI => fmt_memory_seg_rsi!(),
OpKind::MemorySegDI => fmt_memory_seg_di!(),
OpKind::MemorySegEDI => fmt_memory_seg_edi!(),
OpKind::MemorySegRDI => fmt_memory_seg_rdi!(),
OpKind::MemoryESDI => fmt_memory_es_di!(),
OpKind::MemoryESEDI => fmt_memory_es_edi!(),
OpKind::MemoryESRDI => fmt_memory_es_rdi!(),
OpKind::Memory => fmt_memory!(),
}
} else {
match op_kind {
OpKind::Register => fmt_register!(),
OpKind::NearBranch16 => {
imm64 = instruction.near_branch16() as u64;
fmt_near_branch!(self, dst, dst_next_p, instruction, 2, imm64);
}
OpKind::NearBranch32 => {
imm64 = instruction.near_branch32() as u64;
fmt_near_branch!(self, dst, dst_next_p, instruction, 4, imm64);
}
OpKind::NearBranch64 => {
imm64 = instruction.near_branch64();
fmt_near_branch!(self, dst, dst_next_p, instruction, 8, imm64);
}
OpKind::FarBranch16 | OpKind::FarBranch32 => fmt_far_br_16_32!(),
OpKind::Immediate8 => {
imm8 = if TraitOptions::ENABLE_DB_DW_DD_DQ && is_declare_data {
instruction.get_declare_byte_value(operand as usize)
} else {
instruction.immediate8()
};
fmt_imm!(self, dst, dst_next_p, instruction, imm8, 1);
}
OpKind::Immediate8_2nd => {
imm8 = instruction.immediate8_2nd();
fmt_imm!(self, dst, dst_next_p, instruction, imm8, 1);
}
OpKind::Immediate16 => {
imm16 = if TraitOptions::ENABLE_DB_DW_DD_DQ && is_declare_data {
instruction.get_declare_word_value(operand as usize)
} else {
instruction.immediate16()
};
fmt_imm!(self, dst, dst_next_p, instruction, imm16, 2)
}
OpKind::Immediate8to16 => {
imm16 = instruction.immediate8to16() as u16;
fmt_imm!(self, dst, dst_next_p, instruction, imm16, 2)
}
OpKind::Immediate32 => {
imm32 = if TraitOptions::ENABLE_DB_DW_DD_DQ && is_declare_data {
instruction.get_declare_dword_value(operand as usize)
} else {
instruction.immediate32()
};
fmt_imm!(self, dst, dst_next_p, instruction, imm32, 4)
}
OpKind::Immediate8to32 => {
imm32 = instruction.immediate8to32() as u32;
fmt_imm!(self, dst, dst_next_p, instruction, imm32, 4)
}
OpKind::Immediate64 => {
imm64 = if TraitOptions::ENABLE_DB_DW_DD_DQ && is_declare_data {
instruction.get_declare_qword_value(operand as usize)
} else {
instruction.immediate64()
};
fmt_imm!(self, dst, dst_next_p, instruction, imm64, 8)
}
OpKind::Immediate8to64 => {
imm64 = instruction.immediate8to64() as u64;
fmt_imm!(self, dst, dst_next_p, instruction, imm64, 8)
}
OpKind::Immediate32to64 => {
imm64 = instruction.immediate32to64() as u64;
fmt_imm!(self, dst, dst_next_p, instruction, imm64, 8)
}
OpKind::MemorySegSI => fmt_memory_seg_si!(),
OpKind::MemorySegESI => fmt_memory_seg_esi!(),
OpKind::MemorySegRSI => fmt_memory_seg_rsi!(),
OpKind::MemorySegDI => fmt_memory_seg_di!(),
OpKind::MemorySegEDI => fmt_memory_seg_edi!(),
OpKind::MemorySegRDI => fmt_memory_seg_rdi!(),
OpKind::MemoryESDI => fmt_memory_es_di!(),
OpKind::MemoryESEDI => fmt_memory_es_edi!(),
OpKind::MemoryESRDI => fmt_memory_es_rdi!(),
OpKind::Memory => fmt_memory!(),
}
}
if operand == 0 && instruction_internal::internal_has_op_mask_or_zeroing_masking(instruction) {
if instruction.has_op_mask() {
write_fast_ascii_char_lit!(dst, dst_next_p, '{', true);
call_format_register!(self, dst, dst_next_p, instruction.op_mask());
write_fast_ascii_char_lit!(dst, dst_next_p, '}', true);
}
if instruction.zeroing_masking() {
const FAST_STR: FastString4 = mk_const_fast_str!(FastString4, "\x03{z} ");
write_fast_str!(dst, dst_next_p, FastString4, FAST_STR);
}
}
#[cfg(feature = "mvex")]
if mvex_rm_operand == operand {
let conv = instruction.mvex_reg_mem_conv();
if conv != MvexRegMemConv::None {
let mvex = crate::mvex::get_mvex_info(instruction.code());
if mvex.conv_fn != MvexConvFn::None {
let tbl = if mvex.is_conv_fn_32() { &MVEX_REG_MEM_CONSTS_32 } else { &MVEX_REG_MEM_CONSTS_64 };
let s = tbl[conv as usize];
write_fast_str!(dst, dst_next_p, FastString12, s);
}
}
}
operand += 1;
if operand >= op_count {
break;
}
if TraitOptions::space_after_operand_separator(&self.d.options) {
const FAST_STR: FastString4 = mk_const_fast_str!(FastString4, "\x02, ");
write_fast_str!(dst, dst_next_p, FastString4, FAST_STR);
} else {
write_fast_ascii_char_lit!(dst, dst_next_p, ',', true);
}
}
if instruction_internal::internal_has_rounding_control_or_sae(instruction) {
let rc = instruction.rounding_control();
if rc != RoundingControl::None {
if IcedConstants::is_mvex(instruction.code()) && !instruction.suppress_all_exceptions() {
let fast_str = RC_STRINGS[rc as usize];
write_fast_str!(dst, dst_next_p, FastString4, fast_str);
} else {
let fast_str = RC_SAE_STRINGS[rc as usize];
write_fast_str!(dst, dst_next_p, FastString8, fast_str);
}
} else {
debug_assert!(instruction.suppress_all_exceptions());
const FAST_STR: FastString8 = mk_const_fast_str!(FastString8, "\x05{sae} ");
write_fast_str!(dst, dst_next_p, FastString8, FAST_STR);
}
}
}
update_vec_len!(dst, dst_next_p);
}
#[must_use]
#[inline]
fn show_segment_prefix(instruction: &Instruction, op_count: u32) -> bool {
for i in 0..op_count {
match instruction.op_kind(i) {
OpKind::Register
| OpKind::NearBranch16
| OpKind::NearBranch32
| OpKind::NearBranch64
| OpKind::FarBranch16
| OpKind::FarBranch32
| OpKind::Immediate8
| OpKind::Immediate8_2nd
| OpKind::Immediate16
| OpKind::Immediate32
| OpKind::Immediate64
| OpKind::Immediate8to16
| OpKind::Immediate8to32
| OpKind::Immediate8to64
| OpKind::Immediate32to64
| OpKind::MemoryESDI
| OpKind::MemoryESEDI
| OpKind::MemoryESRDI => {}
OpKind::MemorySegSI
| OpKind::MemorySegESI
| OpKind::MemorySegRSI
| OpKind::MemorySegDI
| OpKind::MemorySegEDI
| OpKind::MemorySegRDI
| OpKind::Memory => return false,
}
}
SpecializedFormatter::<TraitOptions>::SHOW_USELESS_PREFIXES
}
#[inline]
#[must_use]
fn format_register(&self, dst: &mut Vec<u8>, mut dst_next_p: *mut u8, register: Register) -> *mut u8 {
let reg_str = self.d.all_registers[register as usize];
write_fast_str!(dst, dst_next_p, FastStringRegister, reg_str);
dst_next_p
}
#[must_use]
fn format_number(&self, dst: &mut Vec<u8>, mut dst_next_p: *mut u8, value: u64) -> *mut u8 {
macro_rules! format_number_impl {
($dst:ident, $dst_next_p:ident, $value:ident, $uppercase_hex:literal, $use_hex_prefix:literal) => {{
if $use_hex_prefix {
const FAST_STR: FastString4 = mk_const_fast_str!(FastString4, "\x020x ");
write_fast_str!($dst, $dst_next_p, FastString4, FAST_STR);
}
if $value < 0x10 {
if $use_hex_prefix {
let hex_table = if $uppercase_hex { b"0123456789ABCDEF" } else { b"0123456789abcdef" };
let c = unsafe { *hex_table.get_unchecked($value as usize) };
write_fast_ascii_char!($dst, $dst_next_p, c, true);
$dst_next_p
} else {
verify_output_has_enough_bytes_left!($dst, $dst_next_p, 1 + 1 + 1);
if $value > 9 {
write_fast_ascii_char_lit!($dst, $dst_next_p, '0', false);
}
let hex_table = if $uppercase_hex { b"0123456789ABCDEF" } else { b"0123456789abcdef" };
let c = unsafe { *hex_table.get_unchecked($value as usize) };
write_fast_ascii_char!($dst, $dst_next_p, c, false);
write_fast_ascii_char_lit!($dst, $dst_next_p, 'h', false);
$dst_next_p
}
} else if $value < 0x100 {
if $use_hex_prefix {
let lower_or_value = if $uppercase_hex { 0 } else { 0x2020_2020 };
write_fast_hex2_rw_4bytes!($dst, $dst_next_p, $value, lower_or_value, true);
$dst_next_p
} else {
verify_output_has_enough_bytes_left!($dst, $dst_next_p, 1 + 2 + 2);
if $value > 0x9F {
write_fast_ascii_char_lit!($dst, $dst_next_p, '0', false);
}
let lower_or_value = if $uppercase_hex { 0 } else { 0x2020_2020 };
write_fast_hex2_rw_4bytes!($dst, $dst_next_p, $value, lower_or_value, false);
write_fast_ascii_char_lit!($dst, $dst_next_p, 'h', false);
$dst_next_p
}
} else {
let mut rshift = ((64 - u64::leading_zeros($value) + 3) & !3) as usize;
verify_output_has_enough_bytes_left!($dst, $dst_next_p, 1 + rshift / 4 + 2);
if !$use_hex_prefix && (($value >> (rshift - 4)) & 0xF) > 9 {
write_fast_ascii_char_lit!($dst, $dst_next_p, '0', false);
}
if (rshift & 4) != 0 {
rshift -= 4;
let hex_table = if $uppercase_hex { b"0123456789ABCDEF" } else { b"0123456789abcdef" };
let digit = (($value >> rshift) & 0xF) as usize;
let c = unsafe { *hex_table.get_unchecked(digit) };
write_fast_ascii_char!($dst, $dst_next_p, c, false);
}
debug_assert!(rshift >= 8);
let lower_or_value = if $uppercase_hex { 0 } else { 0x2020_2020 };
loop {
rshift -= 8;
let digits2 = (($value >> rshift) & 0xFF) as usize;
write_fast_hex2_rw_4bytes!($dst, $dst_next_p, digits2, lower_or_value, false);
if rshift == 0 {
break;
}
}
if !$use_hex_prefix {
write_fast_ascii_char_lit!($dst, $dst_next_p, 'h', false);
}
$dst_next_p
}
}};
}
if TraitOptions::uppercase_hex(&self.d.options) {
if TraitOptions::use_hex_prefix(&self.d.options) {
format_number_impl!(dst, dst_next_p, value, true, true)
} else {
format_number_impl!(dst, dst_next_p, value, true, false)
}
} else {
if TraitOptions::use_hex_prefix(&self.d.options) {
format_number_impl!(dst, dst_next_p, value, false, true)
} else {
format_number_impl!(dst, dst_next_p, value, false, false)
}
}
}
#[inline]
#[must_use]
fn write_symbol(&self, dst: &mut Vec<u8>, mut dst_next_p: *mut u8, address: u64, symbol: &SymbolResult<'_>) -> *mut u8 {
call_write_symbol2!(self, dst, dst_next_p, address, symbol, true);
dst_next_p
}
#[cold]
#[must_use]
fn write_symbol2(
&self, dst: &mut Vec<u8>, mut dst_next_p: *mut u8, address: u64, symbol: &SymbolResult<'_>, write_minus_if_signed: bool,
) -> *mut u8 {
let mut displ = address.wrapping_sub(symbol.address) as i64;
if (symbol.flags & SymbolFlags::SIGNED) != 0 {
if write_minus_if_signed {
write_fast_ascii_char_lit!(dst, dst_next_p, '-', true);
}
displ = displ.wrapping_neg();
}
use_dst_only_now!(dst, dst_next_p);
match symbol.text {
SymResTextInfo::Text(ref part) => {
let s = match &part.text {
&SymResString::Str(s) => s,
SymResString::String(s) => s.as_str(),
};
dst.extend_from_slice(s.as_bytes());
}
SymResTextInfo::TextVec(v) => {
for part in v {
let s = match &part.text {
&SymResString::Str(s) => s,
SymResString::String(s) => s.as_str(),
};
dst.extend_from_slice(s.as_bytes());
}
}
}
use_dst_next_p_now!(dst, dst_next_p);
if displ != 0 {
let c = if displ < 0 {
displ = displ.wrapping_neg();
'-'
} else {
'+'
};
write_fast_ascii_char!(dst, dst_next_p, c, true);
call_format_number!(self, dst, dst_next_p, displ as u64);
}
if TraitOptions::show_symbol_address(&self.d.options) {
const FAST_STR: FastString4 = mk_const_fast_str!(FastString4, "\x02 ( ");
write_fast_str!(dst, dst_next_p, FastString4, FAST_STR);
call_format_number!(self, dst, dst_next_p, address);
write_fast_ascii_char_lit!(dst, dst_next_p, ')', true);
}
dst_next_p
}
#[must_use]
fn format_memory(
&mut self, dst: &mut Vec<u8>, mut dst_next_p: *mut u8, instruction: &Instruction, operand: u32, seg_reg: Register, base_reg: Register,
index_reg: Register, scale: u32, displ_size: u32, displ: i64, addr_size: u32,
) -> *mut u8 {
format_memory_code!(self, dst, dst_next_p, instruction, operand, seg_reg, base_reg, index_reg, scale, displ_size, displ, addr_size);
dst_next_p
}
}
pub type FastFormatter = SpecializedFormatter<DefaultFastFormatterTraitOptions>;
#[allow(missing_copy_implementations)]
#[allow(missing_debug_implementations)]
pub struct DefaultSpecializedFormatterTraitOptions;
impl SpecializedFormatterTraitOptions for DefaultSpecializedFormatterTraitOptions {}