iced_x86/formatter/fast/
trait_options.rs

1// SPDX-License-Identifier: MIT
2// Copyright (C) 2018-present iced project and contributors
3
4use crate::formatter::fast::options::FastFormatterOptions;
5
6/// A trait that allows you to hard code some formatter options which can make
7/// the formatter faster and use less code.
8///
9/// The implementing struct can return hard coded values and/or return a value from the
10/// passed in options. If it returns the value from the passed in options, that option can
11/// be modified at runtime by calling `formatter.options_mut().set_<option>(new_value)`,
12/// else it's ignored and calling that method has no effect (except wasting CPU cycles).
13///
14/// Every `fn` must be a pure function and must return a value from the `options` input or
15/// a literal (`true` or `false`). Returning a literal is recommended since the compiler can
16/// remove unused formatter code.
17///
18/// # Fastest possible disassembly
19///
20/// For fastest possible disassembly, you should *not* enable the `db` feature (or you should set [`ENABLE_DB_DW_DD_DQ`] to `false`)
21/// and you should also override the unsafe [`verify_output_has_enough_bytes_left()`] and return `false`.
22///
23/// [`ENABLE_DB_DW_DD_DQ`]: trait.SpecializedFormatterTraitOptions.html#associatedconstant.ENABLE_DB_DW_DD_DQ
24/// [`verify_output_has_enough_bytes_left()`]: trait.SpecializedFormatterTraitOptions.html#method.verify_output_has_enough_bytes_left
25///
26/// ```
27/// use iced_x86::*;
28///
29/// struct MyTraitOptions;
30/// impl SpecializedFormatterTraitOptions for MyTraitOptions {
31///     // If you never create a db/dw/dd/dq 'instruction', we don't need this feature.
32///     const ENABLE_DB_DW_DD_DQ: bool = false;
33///     // For a few percent faster code, you can also override `verify_output_has_enough_bytes_left()` and return `false`
34///     // unsafe fn verify_output_has_enough_bytes_left() -> bool {
35///     //     false
36///     // }
37/// }
38/// type MyFormatter = SpecializedFormatter<MyTraitOptions>;
39///
40/// // Assume this is a big slice and not just one instruction
41/// let bytes = b"\x62\xF2\x4F\xDD\x72\x50\x01";
42/// let mut decoder = Decoder::new(64, bytes, DecoderOptions::NONE);
43///
44/// let mut output = String::new();
45/// let mut instruction = Instruction::default();
46/// let mut formatter = MyFormatter::new();
47/// while decoder.can_decode() {
48///     decoder.decode_out(&mut instruction);
49///     output.clear();
50///     formatter.format(&instruction, &mut output);
51///     // do something with 'output' here, eg.:
52///     //     println!("{}", output);
53/// }
54/// ```
55///
56/// Also add this to your `Cargo.toml` file:
57///
58/// ```toml
59/// [profile.release]
60/// codegen-units = 1
61/// lto = true
62/// opt-level = 3
63/// ```
64///
65/// See [`SpecializedFormatter<TraitOptions>`] for more examples
66///
67/// [`SpecializedFormatter<TraitOptions>`]: struct.SpecializedFormatter.html
68pub trait SpecializedFormatterTraitOptions {
69	// Not a public API.
70	// It's used by the formatter to detect FastFormatter so its speed doesn't regress
71	// when we optimize SpecializedFormatter with hard coded options.
72	#[doc(hidden)]
73	const __IS_FAST_FORMATTER: bool = false;
74
75	/// Enables support for a symbol resolver. This is disabled by default. If this
76	/// is disabled, you must not pass in a symbol resolver to the constructor.
77	///
78	/// For fastest code, this should be *disabled*, not enabled.
79	const ENABLE_SYMBOL_RESOLVER: bool = false;
80
81	/// Enables support for formatting `db`, `dw`, `dd`, `dq`.
82	///
83	/// For fastest code, this should be *disabled*, not enabled.
84	const ENABLE_DB_DW_DD_DQ: bool = false;
85
86	/// The formatter makes sure that the `output` string has at least 300 bytes left at
87	/// the start of `format()` and also after appending symbols to `output`. This is enough
88	/// space for all formatted instructions.
89	///
90	/// *No formatted instruction will ever get close to being 300 bytes long!*
91	///
92	/// If this function returns `false`, the formatter won't verify that it has
93	/// enough bytes left when writing to the `output` string. Note that it will
94	/// always reserve at least 300 bytes at the start of `format()` and after
95	/// appending symbols.
96	///
97	/// For fastest code, this method should return `false`. Default is `true`.
98	///
99	/// # Safety
100	///
101	/// See the above description.
102	#[must_use]
103	#[inline]
104	unsafe fn verify_output_has_enough_bytes_left() -> bool {
105		// It's not possible to create 'unsafe const' items so we use a fn here
106		true
107	}
108
109	/// Add a space after the operand separator
110	///
111	/// Default | Value | Example
112	/// --------|-------|--------
113	/// _ | `true` | `mov rax, rcx`
114	/// 👍 | `false` | `mov rax,rcx`
115	///
116	/// # Arguments
117	///
118	/// * `options`: Current formatter options
119	#[must_use]
120	#[inline]
121	fn space_after_operand_separator(_options: &FastFormatterOptions) -> bool {
122		false
123	}
124
125	/// Show `RIP+displ` or the virtual address
126	///
127	/// Default | Value | Example
128	/// --------|-------|--------
129	/// 👍 | `true` | `mov eax,[rip+12345678h]`
130	/// _ | `false` | `mov eax,[1029384756AFBECDh]`
131	///
132	/// # Arguments
133	///
134	/// * `options`: Current formatter options
135	#[must_use]
136	#[inline]
137	fn rip_relative_addresses(_options: &FastFormatterOptions) -> bool {
138		true
139	}
140
141	/// Use pseudo instructions
142	///
143	/// Default | Value | Example
144	/// --------|-------|--------
145	/// _ | `true` | `vcmpnltsd xmm2,xmm6,xmm3`
146	/// 👍 | `false` | `vcmpsd xmm2,xmm6,xmm3,5h`
147	///
148	/// # Arguments
149	///
150	/// * `options`: Current formatter options
151	#[must_use]
152	#[inline]
153	fn use_pseudo_ops(_options: &FastFormatterOptions) -> bool {
154		false
155	}
156
157	/// Show the original value after the symbol name
158	///
159	/// Default | Value | Example
160	/// --------|-------|--------
161	/// _ | `true` | `mov eax,[myfield (12345678)]`
162	/// 👍 | `false` | `mov eax,[myfield]`
163	///
164	/// # Arguments
165	///
166	/// * `options`: Current formatter options
167	#[must_use]
168	#[inline]
169	fn show_symbol_address(_options: &FastFormatterOptions) -> bool {
170		false
171	}
172
173	/// Always show the effective segment register. If the option is `false`, only show the segment register if
174	/// there's a segment override prefix.
175	///
176	/// Default | Value | Example
177	/// --------|-------|--------
178	/// _ | `true` | `mov eax,ds:[ecx]`
179	/// 👍 | `false` | `mov eax,[ecx]`
180	///
181	/// # Arguments
182	///
183	/// * `options`: Current formatter options
184	#[must_use]
185	#[inline]
186	fn always_show_segment_register(_options: &FastFormatterOptions) -> bool {
187		false
188	}
189
190	/// Always show the size of memory operands
191	///
192	/// Default | Value | Example | Example
193	/// --------|-------|---------|--------
194	/// _ | `true` | `mov eax,dword ptr [ebx]` | `add byte ptr [eax],0x12`
195	/// 👍 | `false` | `mov eax,[ebx]` | `add byte ptr [eax],0x12`
196	///
197	/// # Arguments
198	///
199	/// * `options`: Current formatter options
200	#[must_use]
201	#[inline]
202	fn always_show_memory_size(_options: &FastFormatterOptions) -> bool {
203		false
204	}
205
206	/// Use uppercase hex digits
207	///
208	/// Default | Value | Example
209	/// --------|-------|--------
210	/// 👍 | `true` | `0xFF`
211	/// _ | `false` | `0xff`
212	///
213	/// # Arguments
214	///
215	/// * `options`: Current formatter options
216	#[must_use]
217	#[inline]
218	fn uppercase_hex(_options: &FastFormatterOptions) -> bool {
219		true
220	}
221
222	/// Use a hex prefix (`0x`) or a hex suffix (`h`)
223	///
224	/// Default | Value | Example
225	/// --------|-------|--------
226	/// 👍 | `true` | `0x5A`
227	/// _ | `false` | `5Ah`
228	///
229	/// # Arguments
230	///
231	/// * `options`: Current formatter options
232	#[must_use]
233	#[inline]
234	fn use_hex_prefix(_options: &FastFormatterOptions) -> bool {
235		true
236	}
237}