Skip to main content

zydis_rs/encoder/
operand.rs

1//! Encoder operand types
2//!
3//! This module provides types for representing operands when encoding x86/x64 instructions.
4
5use crate::isa::Register;
6
7/// Memory operand for encoding
8///
9/// Represents a memory reference with all addressing components needed for encoding.
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub struct MemoryOperand {
12    /// Segment register (use Register::None for default segment)
13    pub segment: Register,
14    /// Base register
15    pub base: Register,
16    /// Index register
17    pub index: Register,
18    /// Scale factor (1, 2, 4, or 8)
19    pub scale: u8,
20    /// Displacement value
21    pub displacement: i64,
22    /// Size of the displacement in bytes (0, 1, 2, 4, or 8)
23    pub disp_size: u8,
24}
25
26impl MemoryOperand {
27    /// Create a new empty memory operand
28    #[must_use]
29    pub const fn new() -> Self {
30        Self {
31            segment: Register::None,
32            base: Register::None,
33            index: Register::None,
34            scale: 1,
35            displacement: 0,
36            disp_size: 0,
37        }
38    }
39
40    /// Create a memory operand with just a base register
41    #[must_use]
42    pub const fn base(base: Register) -> Self {
43        Self {
44            segment: Register::None,
45            base,
46            index: Register::None,
47            scale: 1,
48            displacement: 0,
49            disp_size: 0,
50        }
51    }
52
53    /// Create a memory operand with base and displacement
54    #[must_use]
55    pub const fn base_disp(base: Register, displacement: i64) -> Self {
56        Self {
57            segment: Register::None,
58            base,
59            index: Register::None,
60            scale: 1,
61            displacement,
62            disp_size: 0, // Will be determined during encoding
63        }
64    }
65
66    /// Create a memory operand with base, index, and scale
67    #[must_use]
68    pub const fn base_index_scale(base: Register, index: Register, scale: u8) -> Self {
69        Self {
70            segment: Register::None,
71            base,
72            index,
73            scale,
74            displacement: 0,
75            disp_size: 0,
76        }
77    }
78
79    /// Create a full memory operand with all components
80    #[must_use]
81    pub const fn full(
82        segment: Register,
83        base: Register,
84        index: Register,
85        scale: u8,
86        displacement: i64,
87    ) -> Self {
88        Self {
89            segment,
90            base,
91            index,
92            scale,
93            displacement,
94            disp_size: 0,
95        }
96    }
97
98    /// Set the segment register
99    #[must_use]
100    pub const fn with_segment(mut self, segment: Register) -> Self {
101        self.segment = segment;
102        self
103    }
104
105    /// Set the displacement
106    #[must_use]
107    pub const fn with_displacement(mut self, displacement: i64) -> Self {
108        self.displacement = displacement;
109        self
110    }
111
112    /// Check if this uses RIP-relative addressing
113    #[must_use]
114    pub const fn is_rip_relative(&self) -> bool {
115        matches!(self.base, Register::RIP | Register::EIP | Register::IP)
116    }
117
118    /// Check if this requires a SIB byte
119    #[must_use]
120    pub fn requires_sib(&self) -> bool {
121        // SIB is required if:
122        // 1. There is an index register
123        // 2. The base is RSP/ESP/SP or R12/R12D/R12W (without index)
124        self.index != Register::None
125            || matches!(
126                self.base,
127                Register::RSP
128                    | Register::ESP
129                    | Register::SP
130                    | Register::R12
131                    | Register::R12D
132                    | Register::R12W
133            )
134    }
135
136    /// Check if scale value is valid (1, 2, 4, or 8)
137    #[must_use]
138    pub const fn is_valid_scale(&self) -> bool {
139        matches!(self.scale, 1 | 2 | 4 | 8)
140    }
141
142    /// Check if there is a base register
143    #[must_use]
144    pub fn has_base(&self) -> bool {
145        self.base != Register::None
146    }
147
148    /// Check if there is an index register
149    #[must_use]
150    pub fn has_index(&self) -> bool {
151        self.index != Register::None
152    }
153
154    /// Check if there is a displacement
155    #[must_use]
156    pub const fn has_displacement(&self) -> bool {
157        self.displacement != 0
158    }
159}
160
161impl Default for MemoryOperand {
162    fn default() -> Self {
163        Self::new()
164    }
165}
166
167/// Operand for encoding
168///
169/// Represents the different types of operands that can be used when encoding instructions.
170#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
171pub enum EncoderOperand {
172    /// No operand (placeholder)
173    #[default]
174    None,
175    /// Register operand
176    Reg(Register),
177    /// Memory operand
178    Mem(MemoryOperand),
179    /// Unsigned immediate value
180    Imm(u64),
181    /// Signed relative offset (for branches)
182    Rel(i32),
183}
184
185impl EncoderOperand {
186    /// Create a register operand
187    #[must_use]
188    pub const fn reg(register: Register) -> Self {
189        Self::Reg(register)
190    }
191
192    /// Create a memory operand
193    #[must_use]
194    pub const fn mem(memory: MemoryOperand) -> Self {
195        Self::Mem(memory)
196    }
197
198    /// Create an immediate operand
199    #[must_use]
200    pub const fn imm(value: u64) -> Self {
201        Self::Imm(value)
202    }
203
204    /// Create a relative offset operand
205    #[must_use]
206    pub const fn rel(offset: i32) -> Self {
207        Self::Rel(offset)
208    }
209
210    /// Check if this is a register operand
211    #[must_use]
212    pub const fn is_register(&self) -> bool {
213        matches!(self, Self::Reg(_))
214    }
215
216    /// Check if this is a memory operand
217    #[must_use]
218    pub const fn is_memory(&self) -> bool {
219        matches!(self, Self::Mem(_))
220    }
221
222    /// Check if this is an immediate operand
223    #[must_use]
224    pub const fn is_immediate(&self) -> bool {
225        matches!(self, Self::Imm(_))
226    }
227
228    /// Check if this is a relative offset operand
229    #[must_use]
230    pub const fn is_relative(&self) -> bool {
231        matches!(self, Self::Rel(_))
232    }
233
234    /// Get the register if this is a register operand
235    #[must_use]
236    pub const fn as_register(&self) -> Option<Register> {
237        match self {
238            Self::Reg(reg) => Some(*reg),
239            _ => None,
240        }
241    }
242
243    /// Get the memory operand if this is a memory operand
244    #[must_use]
245    pub const fn as_memory(&self) -> Option<&MemoryOperand> {
246        match self {
247            Self::Mem(mem) => Some(mem),
248            _ => None,
249        }
250    }
251
252    /// Get the immediate value if this is an immediate operand
253    #[must_use]
254    pub const fn as_immediate(&self) -> Option<u64> {
255        match self {
256            Self::Imm(value) => Some(*value),
257            _ => None,
258        }
259    }
260
261    /// Get the relative offset if this is a relative operand
262    #[must_use]
263    pub const fn as_relative(&self) -> Option<i32> {
264        match self {
265            Self::Rel(offset) => Some(*offset),
266            _ => None,
267        }
268    }
269}
270
271#[cfg(test)]
272mod tests {
273    use super::*;
274
275    #[test]
276    fn test_memory_operand_new() {
277        let mem = MemoryOperand::new();
278        assert_eq!(mem.base, Register::None);
279        assert_eq!(mem.index, Register::None);
280        assert_eq!(mem.scale, 1);
281        assert_eq!(mem.displacement, 0);
282    }
283
284    #[test]
285    fn test_memory_operand_base() {
286        let mem = MemoryOperand::base(Register::RAX);
287        assert_eq!(mem.base, Register::RAX);
288        assert_eq!(mem.index, Register::None);
289        assert!(!mem.requires_sib());
290    }
291
292    #[test]
293    fn test_memory_operand_base_disp() {
294        let mem = MemoryOperand::base_disp(Register::RBP, -16);
295        assert_eq!(mem.base, Register::RBP);
296        assert_eq!(mem.displacement, -16);
297    }
298
299    #[test]
300    fn test_memory_operand_base_index_scale() {
301        let mem = MemoryOperand::base_index_scale(Register::RAX, Register::RCX, 4);
302        assert_eq!(mem.base, Register::RAX);
303        assert_eq!(mem.index, Register::RCX);
304        assert_eq!(mem.scale, 4);
305        assert!(mem.requires_sib());
306    }
307
308    #[test]
309    fn test_memory_operand_requires_sib() {
310        // RSP as base requires SIB
311        let mem = MemoryOperand::base(Register::RSP);
312        assert!(mem.requires_sib());
313
314        // R12 as base requires SIB
315        let mem = MemoryOperand::base(Register::R12);
316        assert!(mem.requires_sib());
317
318        // Index register requires SIB
319        let mem = MemoryOperand::base_index_scale(Register::RAX, Register::RCX, 1);
320        assert!(mem.requires_sib());
321
322        // Simple base without SIB
323        let mem = MemoryOperand::base(Register::RAX);
324        assert!(!mem.requires_sib());
325    }
326
327    #[test]
328    fn test_memory_operand_rip_relative() {
329        let mem = MemoryOperand::base(Register::RIP);
330        assert!(mem.is_rip_relative());
331
332        let mem = MemoryOperand::base(Register::RAX);
333        assert!(!mem.is_rip_relative());
334    }
335
336    #[test]
337    fn test_encoder_operand_reg() {
338        let op = EncoderOperand::reg(Register::RAX);
339        assert!(op.is_register());
340        assert!(!op.is_memory());
341        assert_eq!(op.as_register(), Some(Register::RAX));
342    }
343
344    #[test]
345    fn test_encoder_operand_mem() {
346        let mem = MemoryOperand::base(Register::RBP);
347        let op = EncoderOperand::mem(mem);
348        assert!(op.is_memory());
349        assert!(!op.is_register());
350    }
351
352    #[test]
353    fn test_encoder_operand_imm() {
354        let op = EncoderOperand::imm(0x12345678);
355        assert!(op.is_immediate());
356        assert_eq!(op.as_immediate(), Some(0x12345678));
357    }
358
359    #[test]
360    fn test_encoder_operand_rel() {
361        let op = EncoderOperand::rel(-128);
362        assert!(op.is_relative());
363        assert_eq!(op.as_relative(), Some(-128));
364    }
365
366    #[test]
367    fn test_encoder_operand_default() {
368        let op = EncoderOperand::default();
369        assert!(matches!(op, EncoderOperand::None));
370    }
371}