https://github.com/akkartik/mu/blob/master/subx/015immediate_addressing.cc
1
2
3 :(before "End Initialize Op Names")
4 put_new(Name, "81", "combine rm32 with imm32 based on subop (add/sub/and/or/xor/cmp)");
5
6 :(scenario add_imm32_to_r32)
7 % Reg[EBX].i = 1;
8 == 0x1
9
10 81 c3 0a 0b 0c 0d
11
12 +run: combine imm32 with r/m32
13 +run: r/m32 is EBX
14 +run: imm32 is 0x0d0c0b0a
15 +run: subop add
16 +run: storing 0x0d0c0b0b
17
18 :(before "End Single-Byte Opcodes")
19 case 0x81: {
20 trace(90, "run") << "combine imm32 with r/m32" << end();
21 const uint8_t modrm = next();
22 int32_t* arg1 = effective_address(modrm);
23 const int32_t arg2 = next32();
24 trace(90, "run") << "imm32 is 0x" << HEXWORD << arg2 << end();
25 const uint8_t subop = (modrm>>3)&0x7;
26 switch (subop) {
27 case 0:
28 trace(90, "run") << "subop add" << end();
29 BINARY_ARITHMETIC_OP(+, *arg1, arg2);
30 break;
31
32 default:
33 cerr << "unrecognized subop for opcode 81: " << NUM(subop) << '\n';
34 exit(1);
35 }
36 break;
37 }
38
39
40
41 :(scenario add_imm32_to_mem_at_r32)
42 % Reg[EBX].i = 0x2000;
43 == 0x01
44
45 81 03 0a 0b 0c 0d
46
47 == 0x2000
48 01 00 00 00
49 +run: combine imm32 with r/m32
50 +run: effective address is 0x00002000 (EBX)
51 +run: imm32 is 0x0d0c0b0a
52 +run: subop add
53 +run: storing 0x0d0c0b0b
54
55
56
57 :(before "End Initialize Op Names")
58 put_new(Name, "2d", "subtract imm32 from EAX (sub)");
59
60 :(scenario subtract_imm32_from_eax)
61 % Reg[EAX].i = 0x0d0c0baa;
62 == 0x1
63
64 2d 0a 0b 0c 0d
65 +run: subtract imm32 0x0d0c0b0a from EAX
66 +run: storing 0x000000a0
67
68 :(before "End Single-Byte Opcodes")
69 case 0x2d: {
70 const int32_t arg2 = next32();
71 trace(90, "run") << "subtract imm32 0x" << HEXWORD << arg2 << " from EAX" << end();
72 BINARY_ARITHMETIC_OP(-, Reg[EAX].i, arg2);
73 break;
74 }
75
76
77
78 :(scenario subtract_imm32_from_mem_at_r32)
79 % Reg[EBX].i = 0x2000;
80 == 0x01
81
82 81 2b 01 00 00 00
83
84 == 0x2000
85 0a 00 00 00
86 +run: combine imm32 with r/m32
87 +run: effective address is 0x00002000 (EBX)
88 +run: imm32 is 0x00000001
89 +run: subop subtract
90 +run: storing 0x00000009
91
92 :(before "End Op 81 Subops")
93 case 5: {
94 trace(90, "run") << "subop subtract" << end();
95 BINARY_ARITHMETIC_OP(-, *arg1, arg2);
96 break;
97 }
98
99
100
101 :(scenario subtract_imm32_from_r32)
102 % Reg[EBX].i = 10;
103 == 0x1
104
105 81 eb 01 00 00 00
106
107 +run: combine imm32 with r/m32
108 +run: r/m32 is EBX
109 +run: imm32 is 0x00000001
110 +run: subop subtract
111 +run: storing 0x00000009
112
113
114
115 :(before "End Initialize Op Names")
116 put_new(Name, "c1", "shift rm32 by imm8 bits depending on subop (sal/sar/shl/shr)");
117
118 :(scenario shift_left_r32_with_imm8)
119 % Reg[EBX].i = 13;
120 == 0x1
121
122 c1 e3 01
123
124 +run: operate on r/m32
125 +run: r/m32 is EBX
126 +run: subop: shift left by CL bits
127 +run: storing 0x0000001a
128
129 :(before "End Single-Byte Opcodes")
130 case 0xc1: {
131 const uint8_t modrm = next();
132 trace(90, "run") << "operate on r/m32" << end();
133 int32_t* arg1 = effective_address(modrm);
134 const uint8_t subop = (modrm>>3)&0x7;
135 switch (subop) {
136 case 4: {
137 trace(90, "run") << "subop: shift left by CL bits" << end();
138 uint8_t count = next() & 0x1f;
139
140 if (count == 1) {
141 bool msb = (*arg1 & 0x80000000) >> 1;
142 bool pnsb = (*arg1 & 0x40000000);
143 OF = (msb != pnsb);
144 }
145 *arg1 = (*arg1 << count);
146 ZF = (*arg1 == 0);
147 SF = (*arg1 < 0);
148 trace(90, "run") << "storing 0x" << HEXWORD << *arg1 << end();
149 break;
150 }
151
152 default:
153 cerr << "unrecognized subop for opcode c1: " << NUM(subop) << '\n';
154 exit(1);
155 }
156 break;
157 }
158
159
160
161 :(scenario shift_right_arithmetic_r32_with_imm8)
162 % Reg[EBX].i = 26;
163 == 0x1
164
165 c1 fb 01
166
167 +run: operate on r/m32
168 +run: r/m32 is EBX
169 +run: subop: shift right by CL bits, while preserving sign
170 +run: storing 0x0000000d
171
172 :(before "End Op c1 Subops")
173 case 7: {
174 trace(90, "run") << "subop: shift right by CL bits, while preserving sign" << end();
175 uint8_t count = next() & 0x1f;
176 *arg1 = (*arg1 >> count);
177 ZF = (*arg1 == 0);
178 SF = (*arg1 < 0);
179
180 if (count == 1) OF = false;
181 trace(90, "run") << "storing 0x" << HEXWORD << *arg1 << end();
182 break;
183 }
184
185 :(scenario shift_right_arithmetic_odd_r32_with_imm8)
186 % Reg[EBX].i = 27;
187 == 0x1
188
189 c1 fb 01
190
191 +run: operate on r/m32
192 +run: r/m32 is EBX
193 +run: subop: shift right by CL bits, while preserving sign
194
195 +run: storing 0x0000000d
196
197 :(scenario shift_right_arithmetic_negative_r32_with_imm8)
198 % Reg[EBX].i = 0xfffffffd; // -3
199 == 0x1
200
201 c1 fb 01
202
203 +run: operate on r/m32
204 +run: r/m32 is EBX
205 +run: subop: shift right by CL bits, while preserving sign
206
207 +run: storing 0xfffffffe
208
209
210
211 :(scenario shift_right_logical_r32_with_imm8)
212 % Reg[EBX].i = 26;
213 == 0x1
214
215 c1 eb 01
216
217 +run: operate on r/m32
218 +run: r/m32 is EBX
219 +run: subop: shift right by CL bits, while padding zeroes
220 +run: storing 0x0000000d
221
222 :(before "End Op c1 Subops")
223 case 5: {
224 trace(90, "run") << "subop: shift right by CL bits, while padding zeroes" << end();
225 uint8_t count = next() & 0x1f;
226
227 if (count == 1) {
228 bool msb = (*arg1 & 0x80000000) >> 1;
229 bool pnsb = (*arg1 & 0x40000000);
230 OF = (msb != pnsb);
231 }
232 uint32_t* uarg1 = reinterpret_cast<uint32_t*>(arg1);
233 *uarg1 = (*uarg1 >> count);
234 ZF = (*uarg1 == 0);
235
236 SF = false;
237 trace(90, "run") << "storing 0x" << HEXWORD << *arg1 << end();
238 break;
239 }
240
241 :(scenario shift_right_logical_odd_r32_with_imm8)
242 % Reg[EBX].i = 27;
243 == 0x1
244
245 c1 eb 01
246
247 +run: operate on r/m32
248 +run: r/m32 is EBX
249 +run: subop: shift right by CL bits, while padding zeroes
250
251 +run: storing 0x0000000d
252
253 :(scenario shift_right_logical_negative_r32_with_imm8)
254 % Reg[EBX].i = 0xfffffffd;
255 == 0x1
256
257 c1 eb 01
258
259 +run: operate on r/m32
260 +run: r/m32 is EBX
261 +run: subop: shift right by CL bits, while padding zeroes
262 +run: storing 0x7ffffffe
263
264
265
266 :(before "End Initialize Op Names")
267 put_new(Name, "25", "EAX = bitwise AND of imm32 with EAX (and)");
268
269 :(scenario and_imm32_with_eax)
270 % Reg[EAX].i = 0xff;
271 == 0x1
272
273 25 0a 0b 0c 0d
274 +run: and imm32 0x0d0c0b0a with EAX
275 +run: storing 0x0000000a
276
277 :(before "End Single-Byte Opcodes")
278 case 0x25: {
279 const int32_t arg2 = next32();
280 trace(90, "run") << "and imm32 0x" << HEXWORD << arg2 << " with EAX" << end();
281 BINARY_BITWISE_OP(&, Reg[EAX].i, arg2);
282 break;
283 }
284
285
286
287 :(scenario and_imm32_with_mem_at_r32)
288 % Reg[EBX].i = 0x2000;
289 == 0x01
290
291 81 23 0a 0b 0c 0d
292
293 == 0x2000
294 ff 00 00 00
295 +run: combine imm32 with r/m32
296 +run: effective address is 0x00002000 (EBX)
297 +run: imm32 is 0x0d0c0b0a
298 +run: subop and
299 +run: storing 0x0000000a
300
301 :(before "End Op 81 Subops")
302 case 4: {
303 trace(90, "run") << "subop and" << end();
304 BINARY_BITWISE_OP(&, *arg1, arg2);
305 break;
306 }
307
308
309
310 :(scenario and_imm32_with_r32)
311 % Reg[EBX].i = 0xff;
312 == 0x1
313
314 81 e3 0a 0b 0c 0d
315
316 +run: combine imm32 with r/m32
317 +run: r/m32 is EBX
318 +run: imm32 is 0x0d0c0b0a
319 +run: subop and
320 +run: storing 0x0000000a
321
322
323
324 :(before "End Initialize Op Names")
325 put_new(Name, "0d", "EAX = bitwise OR of imm32 with EAX (or)");
326
327 :(scenario or_imm32_with_eax)
328 % Reg[EAX].i = 0xd0c0b0a0;
329 == 0x1
330
331 0d 0a 0b 0c 0d
332 +run: or imm32 0x0d0c0b0a with EAX
333 +run: storing 0xddccbbaa
334
335 :(before "End Single-Byte Opcodes")
336 case 0x0d: {
337 const int32_t arg2 = next32();
338 trace(90, "run") << "or imm32 0x" << HEXWORD << arg2 << " with EAX" << end();
339 BINARY_BITWISE_OP(|, Reg[EAX].i, arg2);
340 break;
341 }
342
343
344
345 :(scenario or_imm32_with_mem_at_r32)
346 % Reg[EBX].i = 0x2000;
347 == 0x01
348
349 81 0b 0a 0b 0c 0d
350
351 == 0x2000
352 a0 b0 c0 d0
353 +run: combine imm32 with r/m32
354 +run: effective address is 0x00002000 (EBX)
355 +run: imm32 is 0x0d0c0b0a
356 +run: subop or
357 +run: storing 0xddccbbaa
358
359 :(before "End Op 81 Subops")
360 case 1: {
361 trace(90, "run") << "subop or" << end();
362 BINARY_BITWISE_OP(|, *arg1, arg2);
363 break;
364 }
365
366 :(scenario or_imm32_with_r32)
367 % Reg[EBX].i = 0xd0c0b0a0;
368 == 0x1
369
370 81 cb 0a 0b 0c 0d
371
372 +run: combine imm32 with r/m32
373 +run: r/m32 is EBX
374 +run: imm32 is 0x0d0c0b0a
375 +run: subop or
376 +run: storing 0xddccbbaa
377
378
379
380 :(before "End Initialize Op Names")
381 put_new(Name, "35", "EAX = bitwise XOR of imm32 with EAX (xor)");
382
383 :(scenario xor_imm32_with_eax)
384 % Reg[EAX].i = 0xddccb0a0;
385 == 0x1
386
387 35 0a 0b 0c 0d
388 +run: xor imm32 0x0d0c0b0a with EAX
389 +run: storing 0xd0c0bbaa
390
391 :(before "End Single-Byte Opcodes")
392 case 0x35: {
393 const int32_t arg2 = next32();
394 trace(90, "run") << "xor imm32 0x" << HEXWORD << arg2 << " with EAX" << end();
395 BINARY_BITWISE_OP(^, Reg[EAX].i, arg2);
396 break;
397 }
398
399
400
401 :(scenario xor_imm32_with_mem_at_r32)
402 % Reg[EBX].i = 0x2000;
403 == 0x01
404
405 81 33 0a 0b 0c 0d
406
407 == 0x2000
408 a0 b0 c0 d0
409 +run: combine imm32 with r/m32
410 +run: effective address is 0x00002000 (EBX)
411 +run: imm32 is 0x0d0c0b0a
412 +run: subop xor
413 +run: storing 0xddccbbaa
414
415 :(before "End Op 81 Subops")
416 case 6: {
417 trace(90, "run") << "subop xor" << end();
418 BINARY_BITWISE_OP(^, *arg1, arg2);
419 break;
420 }
421
422 :(scenario xor_imm32_with_r32)
423 % Reg[EBX].i = 0xd0c0b0a0;
424 == 0x1
425
426 81 f3 0a 0b 0c 0d
427
428 +run: combine imm32 with r/m32
429 +run: r/m32 is EBX
430 +run: imm32 is 0x0d0c0b0a
431 +run: subop xor
432 +run: storing 0xddccbbaa
433
434
435
436 :(before "End Initialize Op Names")
437 put_new(Name, "3d", "compare: set SF if EAX < imm32 (cmp)");
438
439 :(scenario compare_imm32_with_eax_greater)
440 % Reg[EAX].i = 0x0d0c0b0a;
441 == 0x1
442
443 3d 07 0b 0c 0d
444 +run: compare EAX and imm32 0x0d0c0b07
445 +run: SF=0; ZF=0; OF=0
446
447 :(before "End Single-Byte Opcodes")
448 case 0x3d: {
449 const int32_t arg1 = Reg[EAX].i;
450 const int32_t arg2 = next32();
451 trace(90, "run") << "compare EAX and imm32 0x" << HEXWORD << arg2 << end();
452 const int32_t tmp1 = arg1 - arg2;
453 SF = (tmp1 < 0);
454 ZF = (tmp1 == 0);
455 const int64_t tmp2 = arg1 - arg2;
456 OF = (tmp1 != tmp2);
457 trace(90, "run") << "SF=" << SF << "; ZF=" << ZF << "; OF=" << OF << end();
458 break;
459 }
460
461 :(scenario compare_imm32_with_eax_lesser)
462 % Reg[EAX].i = 0x0d0c0b07;
463 == 0x1
464
465 3d 0a 0b 0c 0d
466 +run: compare EAX and imm32 0x0d0c0b0a
467 +run: SF=1; ZF=0; OF=0
468
469 :(scenario compare_imm32_with_eax_equal)
470 % Reg[EAX].i = 0x0d0c0b0a;
471 == 0x1
472
473 3d 0a 0b 0c 0d
474 +run: compare EAX and imm32 0x0d0c0b0a
475 +run: SF=0; ZF=1; OF=0
476
477
478
479 :(scenario compare_imm32_with_r32_greater)
480 % Reg[EBX].i = 0x0d0c0b0a;
481 == 0x1
482
483 81 fb 07 0b 0c 0d
484
485 +run: combine imm32 with r/m32
486 +run: r/m32 is EBX
487 +run: imm32 is 0x0d0c0b07
488 +run: SF=0; ZF=0; OF=0
489
490 :(before "End Op 81 Subops")
491 case 7: {
492 trace(90, "run") << "subop compare" << end();
493 const int32_t tmp1 = *arg1 - arg2;
494 SF = (tmp1 < 0);
495 ZF = (tmp1 == 0);
496 const int64_t tmp2 = *arg1 - arg2;
497 OF = (tmp1 != tmp2);
498 trace(90, "run") << "SF=" << SF << "; ZF=" << ZF << "; OF=" << OF << end();
499 break;
500 }
501
502 :(scenario compare_imm32_with_r32_lesser)
503 % Reg[EBX].i = 0x0d0c0b07;
504 == 0x1
505
506 81 fb 0a 0b 0c 0d
507
508 +run: combine imm32 with r/m32
509 +run: r/m32 is EBX
510 +run: imm32 is 0x0d0c0b0a
511 +run: SF=1; ZF=0; OF=0
512
513 :(scenario compare_imm32_with_r32_equal)
514 % Reg[EBX].i = 0x0d0c0b0a;
515 == 0x1
516
517 81 fb 0a 0b 0c 0d
518
519 +run: combine imm32 with r/m32
520 +run: r/m32 is EBX
521 +run: imm32 is 0x0d0c0b0a
522 +run: SF=0; ZF=1; OF=0
523
524 :(scenario compare_imm32_with_mem_at_r32_greater)
525 % Reg[EBX].i = 0x2000;
526 == 0x01
527
528 81 3b 07 0b 0c 0d
529
530 == 0x2000
531 0a 0b 0c 0d
532 +run: combine imm32 with r/m32
533 +run: effective address is 0x00002000 (EBX)
534 +run: imm32 is 0x0d0c0b07
535 +run: SF=0; ZF=0; OF=0
536
537 :(scenario compare_imm32_with_mem_at_r32_lesser)
538 % Reg[EBX].i = 0x2000;
539 == 0x01
540
541 81 3b 0a 0b 0c 0d
542
543 == 0x2000
544 07 0b 0c 0d
545 +run: combine imm32 with r/m32
546 +run: effective address is 0x00002000 (EBX)
547 +run: imm32 is 0x0d0c0b0a
548 +run: SF=1; ZF=0; OF=0
549
550 :(scenario compare_imm32_with_mem_at_r32_equal)
551 % Reg[EBX].i = 0x0d0c0b0a;
552 % Reg[EBX].i = 0x2000;
553 == 0x01
554
555 81 3b 0a 0b 0c 0d
556
557 == 0x2000
558 0a 0b 0c 0d
559 +run: combine imm32 with r/m32
560 +run: effective address is 0x00002000 (EBX)
561 +run: imm32 is 0x0d0c0b0a
562 +run: SF=0; ZF=1; OF=0
563
564
565
566 :(before "End Initialize Op Names")
567 put_new(Name, "b8", "copy imm32 to EAX (mov)");
568 put_new(Name, "b9", "copy imm32 to ECX (mov)");
569 put_new(Name, "ba", "copy imm32 to EDX (mov)");
570 put_new(Name, "bb", "copy imm32 to EBX (mov)");
571 put_new(Name, "bc", "copy imm32 to ESP (mov)");
572 put_new(Name, "bd", "copy imm32 to EBP (mov)");
573 put_new(Name, "be", "copy imm32 to ESI (mov)");
574 put_new(Name, "bf", "copy imm32 to EDI (mov)");
575
576 :(scenario copy_imm32_to_r32)
577 == 0x1
578
579 bb 0a 0b 0c 0d
580 +run: copy imm32 0x0d0c0b0a to EBX
581
582 :(before "End Single-Byte Opcodes")
583 case 0xb8:
584 case 0xb9:
585 case 0xba:
586 case 0xbb:
587 case 0xbc:
588 case 0xbd:
589 case 0xbe:
590 case 0xbf: {
591 const uint8_t rdest = op & 0x7;
592 const int32_t src = next32();
593 trace(90, "run") << "copy imm32 0x" << HEXWORD << src << " to " << rname(rdest) << end();
594 Reg[rdest].i = src;
595 break;
596 }
597
598
599
600 :(before "End Initialize Op Names")
601 put_new(Name, "c7", "copy imm32 to rm32 (mov)");
602
603 :(scenario copy_imm32_to_mem_at_r32)
604 % Reg[EBX].i = 0x60;
605 == 0x1
606
607 c7 03 0a 0b 0c 0d
608
609 +run: copy imm32 to r/m32
610 +run: effective address is 0x00000060 (EBX)
611 +run: imm32 is 0x0d0c0b0a
612
613 :(before "End Single-Byte Opcodes")
614 case 0xc7: {
615 const uint8_t modrm = next();
616 trace(90, "run") << "copy imm32 to r/m32" << end();
617 const uint8_t subop = (modrm>>3)&0x7;
618 if (subop != 0) {
619 cerr << "unrecognized subop for opcode c7: " << NUM(subop) << " (only 0/copy currently implemented)\n";
620 exit(1);
621 }
622 int32_t* dest = effective_address(modrm);
623 const int32_t src = next32();
624 trace(90, "run") << "imm32 is 0x" << HEXWORD << src << end();
625 *dest = src;
626 break;
627 }
628
629
630
631 :(before "End Initialize Op Names")
632 put_new(Name, "68", "push imm32 to stack (push)");
633
634 :(scenario push_imm32)
635 % Reg[ESP].u = 0x14;
636 == 0x1
637
638 68 af 00 00 00
639 +run: push imm32 0x000000af
640 +run: ESP is now 0x00000010
641 +run: contents at ESP: 0x000000af
642
643 :(before "End Single-Byte Opcodes")
644 case 0x68: {
645 const uint32_t val = static_cast<uint32_t>(next32());
646 trace(90, "run") << "push imm32 0x" << HEXWORD << val << end();
647
648 push(val);
649 trace(90, "run") << "ESP is now 0x" << HEXWORD << Reg[ESP].u << end();
650 trace(90, "run") << "contents at ESP: 0x" << HEXWORD << read_mem_u32(Reg[ESP].u) << end();
651 break;
652 }