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}