logo
pub struct SpecializedFormatter<TraitOptions: SpecializedFormatterTraitOptions> { /* private fields */ }
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

Creates a new instance of this formatter

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 or None

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: Instruction
  • output: Output

Trait Implementations

Returns the “default value” for a type. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more

Returns the argument unchanged.

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.