x86emu/emulator/
shift_rotate.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4use super::Emulator;
5use super::InternalError;
6use super::rflags::update_flags_szp;
7use crate::Cpu;
8use iced_x86::Instruction;
9use x86defs::RFlags;
10
11const LSB_MASK: u64 = 0x1;
12
13impl<T: Cpu> Emulator<'_, T> {
14    // shr/shl/sal/rol/ror/rcl/rcr rm, 1/imm/cl
15    pub(super) async fn shift_sign_unextended<Op: ShiftingOp>(
16        &mut self,
17        instr: &Instruction,
18    ) -> Result<(), InternalError<T::Error>> {
19        let left = self.op_value(instr, 0).await?;
20        self.shift::<Op>(instr, left, 1).await
21    }
22
23    // sar rm, 1/imm/cl
24    pub(super) async fn shift_arithmetic_right(
25        &mut self,
26        instr: &Instruction,
27    ) -> Result<(), InternalError<T::Error>> {
28        let left = self.op_value_sign_extend(instr, 0).await?;
29        self.shift::<SarOp>(instr, left as u64, 1).await
30    }
31
32    // shld rm, r, imm/cl
33    pub(super) async fn shld(
34        &mut self,
35        instr: &Instruction,
36    ) -> Result<(), InternalError<T::Error>> {
37        let left = self.op_value(instr, 0).await?;
38        self.shift::<ShldOp>(instr, left, 2).await
39    }
40
41    // shld rm, r, imm/cl
42    pub(super) async fn shrd(
43        &mut self,
44        instr: &Instruction,
45    ) -> Result<(), InternalError<T::Error>> {
46        let left = self.op_value(instr, 0).await?;
47        self.shift::<ShrdOp>(instr, left, 2).await
48    }
49
50    // performs a shift or rotate operation
51    async fn shift<Op: ShiftingOp>(
52        &mut self,
53        instr: &Instruction,
54        left: u64,
55        count_op: u32,
56    ) -> Result<(), InternalError<T::Error>> {
57        let operand_size = instr.memory_size().size();
58        let operand_bit_size = operand_size as u32 * 8;
59
60        let masked_count = shift_count(self.op_value(instr, count_op).await?, operand_bit_size);
61        let count = Op::mod_count(masked_count, operand_bit_size);
62
63        let right = self.op_value(instr, 1).await?;
64        let mut rflags = self.cpu.rflags();
65
66        if count == 0 {
67            if Op::ZERO_SHIFT_UPDATES_CARRY && masked_count != 0 {
68                // left is unchanged, so left is the result
69                rflags.set_carry(Op::carry_flag(left, right, left, count, operand_bit_size));
70                self.cpu.set_rflags(rflags);
71            }
72            // flags unchanged
73            return Ok(());
74        }
75        let result = Op::op(left, right, count, rflags, operand_bit_size);
76        let carry = Op::carry_flag(left, right, result, count, operand_bit_size);
77
78        self.write_op_0(instr, result).await?;
79
80        if Op::UPDATE_SZP {
81            update_flags_szp(&mut rflags, operand_size, result);
82        }
83
84        rflags.set_carry(carry);
85
86        if (Op::MASKED_COUNT_UPDATES_OF && masked_count == 1)
87            || (!Op::MASKED_COUNT_UPDATES_OF && count == 1)
88        {
89            rflags.set_overflow(Op::overflow_flag(left, result, carry, operand_bit_size));
90        }
91
92        self.cpu.set_rflags(rflags);
93
94        Ok(())
95    }
96}
97
98/// Trait for rotate and shift operations
99pub(super) trait ShiftingOp {
100    /// Whether sign, zero, and parity flags are updated
101    const UPDATE_SZP: bool;
102    /// Whether the carry flag may still be updated if no shift was performed,
103    /// based on the masked count
104    const ZERO_SHIFT_UPDATES_CARRY: bool;
105    /// Whether the overflow flag is updated based on the masked count
106    const MASKED_COUNT_UPDATES_OF: bool;
107    /// Actual operation
108    fn op(left: u64, right: u64, count: u32, flags: RFlags, operand_bit_size: u32) -> u64;
109    /// Modulates the count
110    fn mod_count(masked_count: u32, operand_bit_size: u32) -> u32;
111    /// calculates the carry flag
112    fn carry_flag(left: u64, right: u64, result: u64, count: u32, operand_bit_size: u32) -> bool;
113    /// calculates the overflow flag
114    fn overflow_flag(left: u64, result: u64, carry_flag: bool, operand_bit_size: u32) -> bool;
115}
116
117pub(super) struct SxlOp {}
118impl ShiftingOp for SxlOp {
119    const UPDATE_SZP: bool = true;
120    const ZERO_SHIFT_UPDATES_CARRY: bool = false;
121    const MASKED_COUNT_UPDATES_OF: bool = false;
122    fn op(left: u64, _right: u64, count: u32, _flags: RFlags, _operand_bit_size: u32) -> u64 {
123        left << count
124    }
125
126    fn mod_count(masked_count: u32, _operand_bit_size: u32) -> u32 {
127        masked_count
128    }
129
130    fn carry_flag(left: u64, _right: u64, _result: u64, count: u32, operand_bit_size: u32) -> bool {
131        ((left << (count - 1)) & msb_mask(operand_bit_size)) != 0
132    }
133
134    fn overflow_flag(_left: u64, result: u64, carry_flag: bool, operand_bit_size: u32) -> bool {
135        ((msb_mask(operand_bit_size) & result) != 0) ^ carry_flag
136    }
137}
138
139struct SarOp {}
140impl ShiftingOp for SarOp {
141    const UPDATE_SZP: bool = true;
142    const ZERO_SHIFT_UPDATES_CARRY: bool = false;
143    const MASKED_COUNT_UPDATES_OF: bool = false;
144    fn op(left: u64, _right: u64, count: u32, _flags: RFlags, _operand_bit_size: u32) -> u64 {
145        ((left as i64) >> count) as u64
146    }
147
148    fn mod_count(masked_count: u32, _operand_bit_size: u32) -> u32 {
149        masked_count
150    }
151
152    fn carry_flag(
153        left: u64,
154        _right: u64,
155        _result: u64,
156        count: u32,
157        _operand_bit_size: u32,
158    ) -> bool {
159        (left >> (count - 1) & LSB_MASK) != 0
160    }
161
162    fn overflow_flag(_left: u64, _result: u64, _carry_flag: bool, _operand_bit_size: u32) -> bool {
163        false
164    }
165}
166
167pub(super) struct ShrOp {}
168impl ShiftingOp for ShrOp {
169    const UPDATE_SZP: bool = true;
170    const ZERO_SHIFT_UPDATES_CARRY: bool = false;
171    const MASKED_COUNT_UPDATES_OF: bool = false;
172    fn op(left: u64, _right: u64, count: u32, _flags: RFlags, _operand_bit_size: u32) -> u64 {
173        left >> count
174    }
175
176    fn mod_count(masked_count: u32, _operand_bit_size: u32) -> u32 {
177        masked_count
178    }
179
180    fn carry_flag(
181        left: u64,
182        _right: u64,
183        _result: u64,
184        count: u32,
185        _operand_bit_size: u32,
186    ) -> bool {
187        (left >> (count - 1) & LSB_MASK) != 0
188    }
189
190    fn overflow_flag(left: u64, _result: u64, _carry_flag: bool, operand_bit_size: u32) -> bool {
191        (msb_mask(operand_bit_size) & left) != 0
192    }
193}
194
195struct ShldOp {}
196impl ShiftingOp for ShldOp {
197    const UPDATE_SZP: bool = true;
198    const ZERO_SHIFT_UPDATES_CARRY: bool = false;
199    const MASKED_COUNT_UPDATES_OF: bool = false;
200    fn op(left: u64, right: u64, count: u32, _flags: RFlags, operand_bit_size: u32) -> u64 {
201        // When operating on 16 bit operands it is possible for count to be greater than operand_bit_size.
202        // The results in this case are undefined, but real hardware appears to treat this as an oversized rotate.
203        if operand_bit_size == 16 && count > 16 {
204            let combined: u32 = ((left as u32) << 16) | (right as u32);
205            (combined.rotate_left(count - 16) as u16).into()
206        } else {
207            (left << count) | (right >> (operand_bit_size - count))
208        }
209    }
210
211    fn mod_count(masked_count: u32, _operand_bit_size: u32) -> u32 {
212        masked_count
213    }
214
215    fn carry_flag(left: u64, right: u64, _result: u64, count: u32, operand_bit_size: u32) -> bool {
216        // When operating on 16 bit operands it is possible for count to be greater than operand_bit_size.
217        // The results in this case are undefined, but real hardware appears to treat this as an oversized rotate.
218        if operand_bit_size == 16 && count > 16 {
219            ((right >> (operand_bit_size - (count - 16))) & LSB_MASK) != 0
220        } else {
221            ((left >> (operand_bit_size - count)) & LSB_MASK) != 0
222        }
223    }
224
225    fn overflow_flag(left: u64, result: u64, _carry_flag: bool, operand_bit_size: u32) -> bool {
226        (msb_mask(operand_bit_size) & (left ^ result)) != 0
227    }
228}
229
230struct ShrdOp {}
231impl ShiftingOp for ShrdOp {
232    const UPDATE_SZP: bool = true;
233    const ZERO_SHIFT_UPDATES_CARRY: bool = false;
234    const MASKED_COUNT_UPDATES_OF: bool = false;
235    fn op(left: u64, right: u64, count: u32, _flags: RFlags, operand_bit_size: u32) -> u64 {
236        // When operating on 16 bit operands it is possible for count to be greater than operand_bit_size.
237        // The results in this case are undefined, but real hardware appears to treat this as an oversized rotate.
238        if operand_bit_size == 16 && count > 16 {
239            let combined: u32 = ((left as u32) << 16) | (right as u32);
240            (combined.rotate_right(count - 16) as u16).into()
241        } else {
242            (left >> count) | (right << (operand_bit_size - count))
243        }
244    }
245
246    fn mod_count(masked_count: u32, _operand_bit_size: u32) -> u32 {
247        masked_count
248    }
249
250    fn carry_flag(left: u64, right: u64, _result: u64, count: u32, operand_bit_size: u32) -> bool {
251        // When operating on 16 bit operands it is possible for count to be greater than operand_bit_size.
252        // The results in this case are undefined, but real hardware appears to treat this as an oversized rotate.
253        if operand_bit_size == 16 && count > 16 {
254            ((right >> (count - 17)) & LSB_MASK) != 0
255        } else {
256            ((left >> (count - 1)) & LSB_MASK) != 0
257        }
258    }
259
260    fn overflow_flag(_left: u64, result: u64, carry_flag: bool, operand_bit_size: u32) -> bool {
261        ((msb_mask(operand_bit_size) & result) != 0) ^ carry_flag
262    }
263}
264
265pub(super) struct RolOp {}
266impl ShiftingOp for RolOp {
267    const UPDATE_SZP: bool = false;
268    const ZERO_SHIFT_UPDATES_CARRY: bool = true;
269    const MASKED_COUNT_UPDATES_OF: bool = true;
270    fn op(left: u64, _right: u64, count: u32, _flags: RFlags, operand_bit_size: u32) -> u64 {
271        let result = (left << count) | (left >> (operand_bit_size - count));
272        sign_extend(result, operand_bit_size)
273    }
274
275    fn carry_flag(
276        _left: u64,
277        _right: u64,
278        result: u64,
279        _count: u32,
280        _operand_bit_size: u32,
281    ) -> bool {
282        (result & LSB_MASK) != 0
283    }
284
285    fn mod_count(masked_count: u32, operand_bit_size: u32) -> u32 {
286        rox_mod_count(masked_count, operand_bit_size)
287    }
288
289    fn overflow_flag(_left: u64, result: u64, carry_flag: bool, operand_bit_size: u32) -> bool {
290        rotate_left_overflow(result, carry_flag, operand_bit_size)
291    }
292}
293
294pub(super) struct RorOp {}
295impl ShiftingOp for RorOp {
296    const UPDATE_SZP: bool = false;
297    const ZERO_SHIFT_UPDATES_CARRY: bool = true;
298    const MASKED_COUNT_UPDATES_OF: bool = true;
299    fn op(left: u64, _right: u64, count: u32, _flags: RFlags, operand_bit_size: u32) -> u64 {
300        let result = (left >> count) | (left << (operand_bit_size - count));
301        sign_extend(result, operand_bit_size)
302    }
303
304    fn carry_flag(
305        _left: u64,
306        _right: u64,
307        result: u64,
308        _count: u32,
309        operand_bit_size: u32,
310    ) -> bool {
311        (result & msb_mask(operand_bit_size)) != 0
312    }
313
314    fn mod_count(masked_count: u32, operand_bit_size: u32) -> u32 {
315        rox_mod_count(masked_count, operand_bit_size)
316    }
317
318    fn overflow_flag(_left: u64, result: u64, carry_flag: bool, operand_bit_size: u32) -> bool {
319        rotate_right_overflow(result, carry_flag, operand_bit_size)
320    }
321}
322
323pub(super) struct RclOp {}
324impl ShiftingOp for RclOp {
325    const UPDATE_SZP: bool = false;
326    const ZERO_SHIFT_UPDATES_CARRY: bool = false;
327    const MASKED_COUNT_UPDATES_OF: bool = true;
328    fn op(left: u64, _right: u64, count: u32, flags: RFlags, operand_bit_size: u32) -> u64 {
329        let result = (left << count)
330            | ((flags.carry() as u64) << (count - 1))
331            | ((left as u128) >> ((operand_bit_size + 1) - count)) as u64; // add 1 for participation of cf
332        sign_extend(result, operand_bit_size)
333    }
334
335    fn mod_count(masked_count: u32, operand_bit_size: u32) -> u32 {
336        rcx_mod_count(masked_count, operand_bit_size)
337    }
338
339    fn carry_flag(left: u64, _right: u64, _result: u64, count: u32, operand_bit_size: u32) -> bool {
340        ((left >> (operand_bit_size - count)) & LSB_MASK) != 0
341    }
342
343    fn overflow_flag(_left: u64, result: u64, carry_flag: bool, operand_bit_size: u32) -> bool {
344        rotate_left_overflow(result, carry_flag, operand_bit_size)
345    }
346}
347
348pub(super) struct RcrOp {}
349impl ShiftingOp for RcrOp {
350    const UPDATE_SZP: bool = false;
351    const ZERO_SHIFT_UPDATES_CARRY: bool = false;
352    const MASKED_COUNT_UPDATES_OF: bool = true;
353    fn op(left: u64, _right: u64, count: u32, flags: RFlags, operand_bit_size: u32) -> u64 {
354        let result = (left >> count)
355            | ((flags.carry() as u64) << (operand_bit_size - count))
356            | ((left as u128) << ((operand_bit_size + 1) - count)) as u64; // add 1 for participation of cf
357        sign_extend(result, operand_bit_size)
358    }
359
360    fn mod_count(masked_count: u32, operand_bit_size: u32) -> u32 {
361        rcx_mod_count(masked_count, operand_bit_size)
362    }
363
364    fn carry_flag(
365        left: u64,
366        _right: u64,
367        _result: u64,
368        count: u32,
369        _operand_bit_size: u32,
370    ) -> bool {
371        ((left >> (count - 1)) & LSB_MASK) != 0
372    }
373
374    fn overflow_flag(_left: u64, result: u64, carry_flag: bool, operand_bit_size: u32) -> bool {
375        rotate_right_overflow(result, carry_flag, operand_bit_size)
376    }
377}
378
379/// Returns the mask for getting the most significant bit
380fn msb_mask(operand_bit_size: u32) -> u64 {
381    match operand_bit_size {
382        8 => 0x80,
383        16 => 0x8000,
384        32 => 0x80000000,
385        64 => 0x8000000000000000,
386        _ => unreachable!(),
387    }
388}
389
390fn rcx_mod_count(masked_count: u32, operand_bit_size: u32) -> u32 {
391    if operand_bit_size == 8 {
392        masked_count % 9
393    } else if operand_bit_size == 16 {
394        masked_count % 17
395    } else {
396        masked_count
397    }
398}
399
400fn rox_mod_count(masked_count: u32, operand_bit_size: u32) -> u32 {
401    masked_count % operand_bit_size
402}
403
404/// Truncates and sign-extends the result to the correct operand size
405fn sign_extend(value: u64, operand_bit_size: u32) -> u64 {
406    let sign_shift = 64 - operand_bit_size;
407    (((value as i64) << sign_shift) >> sign_shift) as u64
408}
409
410/// Adjusts the count for shift instructions
411fn shift_count(right: u64, operand_bit_size: u32) -> u32 {
412    (if operand_bit_size == 64 {
413        right & 0x3f
414    } else {
415        right & 0x1f
416    }) as u32
417}
418
419/// Calculates the overflow flag for a right rotation
420fn rotate_right_overflow(result: u64, _carry_flag: bool, operand_bit_size: u32) -> bool {
421    let mask = msb_mask(operand_bit_size);
422    let msb = (result & mask) != 0;
423    let second_msb = (result & (mask >> 1)) != 0;
424    msb ^ second_msb
425}
426
427/// Calculates the overflow flag for a left rotation
428fn rotate_left_overflow(result: u64, carry_flag: bool, operand_bit_size: u32) -> bool {
429    ((msb_mask(operand_bit_size) & result) != 0) ^ carry_flag
430}