Struct iced_x86::SpecializedFormatter [−][src]
pub struct SpecializedFormatter<TraitOptions: SpecializedFormatterTraitOptions> { /* fields omitted */ }
Expand description
Fast specialized formatter with less formatting options and with a masm-like syntax. Use it if formatting speed is more important than being able to re-assemble formatted instructions.
The TraitOptions
generic parameter is a SpecializedFormatterTraitOptions
trait. It can
be used to hard code options so the compiler can create a smaller and faster formatter.
See also FastFormatter
which allows changing the options at runtime at the cost of
being a little bit slower and using a little bit more code.
This formatter is ~3.3x faster than the gas/intel/masm/nasm formatters (the time includes decoding + formatting).
Examples
use iced_x86::*;
let bytes = b"\x62\xF2\x4F\xDD\x72\x50\x01";
let mut decoder = Decoder::new(64, bytes, DecoderOptions::NONE);
let instr = decoder.decode();
// If you like the default options, you can also use DefaultSpecializedFormatterTraitOptions
// instead of impl the options trait.
struct MyTraitOptions;
impl SpecializedFormatterTraitOptions for MyTraitOptions {
fn space_after_operand_separator(_options: &FastFormatterOptions) -> bool {
// We hard code the value to `true` which means it's not possible to
// change this option at runtime, i.e., this will do nothing:
// formatter.options_mut().set_space_after_operand_separator(false);
true
}
fn rip_relative_addresses(options: &FastFormatterOptions) -> bool {
// Since we return the input, we can change this value at runtime, i.e.,
// this works:
// formatter.options_mut().set_rip_relative_addresses(false);
options.rip_relative_addresses()
}
}
type MyFormatter = SpecializedFormatter<MyTraitOptions>;
let mut output = String::new();
let mut formatter = MyFormatter::new();
formatter.format(&instr, &mut output);
assert_eq!(output, "vcvtne2ps2bf16 zmm2{k5}{z}, zmm6, dword bcst [rax+0x4]");
Fastest possible disassembly
For fastest possible disassembly, you should not enable the db
feature (or you should set ENABLE_DB_DW_DD_DQ
to false
)
and you should also override the unsafe verify_output_has_enough_bytes_left()
and return false
.
use iced_x86::*;
struct MyTraitOptions;
impl SpecializedFormatterTraitOptions for MyTraitOptions {
// If you never create a db/dw/dd/dq 'instruction', we don't need this feature.
const ENABLE_DB_DW_DD_DQ: bool = false;
// For a few percent faster code, you can also override `verify_output_has_enough_bytes_left()` and return `false`
// unsafe fn verify_output_has_enough_bytes_left() -> bool {
// false
// }
}
type MyFormatter = SpecializedFormatter<MyTraitOptions>;
// Assume this is a big slice and not just one instruction
let bytes = b"\x62\xF2\x4F\xDD\x72\x50\x01";
let mut decoder = Decoder::new(64, bytes, DecoderOptions::NONE);
let mut output = String::new();
let mut instruction = Instruction::default();
let mut formatter = MyFormatter::new();
while decoder.can_decode() {
decoder.decode_out(&mut instruction);
output.clear();
formatter.format(&instruction, &mut output);
// do something with 'output' here, eg.:
// println!("{}", output);
}
Also add this to your Cargo.toml
file:
[profile.release]
codegen-units = 1
lto = true
opt-level = 3
Using a symbol resolver
The symbol resolver is disabled by default, but it’s easy to enable it (or you can just use FastFormatter
)
use iced_x86::*;
use std::collections::HashMap;
let bytes = b"\x48\x8B\x8A\xA5\x5A\xA5\x5A";
let mut decoder = Decoder::new(64, bytes, DecoderOptions::NONE);
let instr = decoder.decode();
struct MyTraitOptions;
impl SpecializedFormatterTraitOptions for MyTraitOptions {
const ENABLE_SYMBOL_RESOLVER: bool = true;
}
type MyFormatter = SpecializedFormatter<MyTraitOptions>;
struct MySymbolResolver { map: HashMap<u64, String> }
impl SymbolResolver for MySymbolResolver {
fn symbol(&mut self, _instruction: &Instruction, _operand: u32, _instruction_operand: Option<u32>,
address: u64, _address_size: u32) -> Option<SymbolResult> {
if let Some(symbol_string) = self.map.get(&address) {
// The 'address' arg is the address of the symbol and doesn't have to be identical
// to the 'address' arg passed to symbol(). If it's different from the input
// address, the formatter will add +N or -N, eg. '[rax+symbol+123]'
Some(SymbolResult::with_str(address, symbol_string.as_str()))
} else {
None
}
}
}
// Hard code the symbols, it's just an example!😄
let mut sym_map: HashMap<u64, String> = HashMap::new();
sym_map.insert(0x5AA55AA5, String::from("my_data"));
let mut output = String::new();
let resolver = Box::new(MySymbolResolver { map: sym_map });
let mut formatter = MyFormatter::try_with_options(Some(resolver)).unwrap();
formatter.format(&instr, &mut output);
assert_eq!("mov rcx,[rdx+my_data]", output);
Implementations
pub fn try_with_options(
symbol_resolver: Option<Box<dyn SymbolResolver>>
) -> Result<Self, IcedError>
pub fn try_with_options(
symbol_resolver: Option<Box<dyn SymbolResolver>>
) -> Result<Self, IcedError>
Creates a new instance of this formatter
Errors
Fails if TraitOptions::ENABLE_SYMBOL_RESOLVER
is false
and symbol_resolver.is_some()
Arguments
symbol_resolver
: Symbol resolver orNone
Gets the formatter options (immutable)
Note that the TraitOptions
generic parameter can override any option and hard code them,
see SpecializedFormatterTraitOptions
Gets the formatter options (mutable)
Note that the TraitOptions
generic parameter can override any option and hard code them,
see SpecializedFormatterTraitOptions
Formats the whole instruction: prefixes, mnemonic, operands
Arguments
instruction
: Instructionoutput
: Output