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 :(code)
7 void test_add_imm32_to_r32() {
8 Reg[EBX].i = 1;
9 run(
10 "== 0x1\n"
11
12 " 81 c3 0a 0b 0c 0d\n"
13
14 );
15 CHECK_TRACE_CONTENTS(
16 "run: combine imm32 with r/m32\n"
17 "run: r/m32 is EBX\n"
18 "run: imm32 is 0x0d0c0b0a\n"
19 "run: subop add\n"
20 "run: storing 0x0d0c0b0b\n"
21 );
22 }
23
24 :(before "End Single-Byte Opcodes")
25 case 0x81: {
26 trace(Callstack_depth+1, "run") << "combine imm32 with r/m32" << end();
27 const uint8_t modrm = next();
28 int32_t* arg1 = effective_address(modrm);
29 const int32_t arg2 = next32();
30 trace(Callstack_depth+1, "run") << "imm32 is 0x" << HEXWORD << arg2 << end();
31 const uint8_t subop = (modrm>>3)&0x7;
32 switch (subop) {
33 case 0:
34 trace(Callstack_depth+1, "run") << "subop add" << end();
35 BINARY_ARITHMETIC_OP(+, *arg1, arg2);
36 break;
37
38 default:
39 cerr << "unrecognized subop for opcode 81: " << NUM(subop) << '\n';
40 exit(1);
41 }
42 break;
43 }
44
45
46
47 :(code)
48 void test_add_imm32_to_mem_at_r32() {
49 Reg[EBX].i = 0x2000;
50 run(
51 "== 0x1\n"
52
53 " 81 03 0a 0b 0c 0d \n"
54
55 "== 0x2000\n"
56 "01 00 00 00\n"
57 );
58 CHECK_TRACE_CONTENTS(
59 "run: combine imm32 with r/m32\n"
60 "run: effective address is 0x00002000 (EBX)\n"
61 "run: imm32 is 0x0d0c0b0a\n"
62 "run: subop add\n"
63 "run: storing 0x0d0c0b0b\n"
64 );
65 }
66
67
68
69 :(before "End Initialize Op Names")
70 put_new(Name, "2d", "subtract imm32 from EAX (sub)");
71
72 :(code)
73 void test_subtract_imm32_from_eax() {
74 Reg[EAX].i = 0x0d0c0baa;
75 run(
76 "== 0x1\n"
77
78 " 2d 0a 0b 0c 0d \n"
79 );
80 CHECK_TRACE_CONTENTS(
81 "run: subtract imm32 0x0d0c0b0a from EAX\n"
82 "run: storing 0x000000a0\n"
83 );
84 }
85
86 :(before "End Single-Byte Opcodes")
87 case 0x2d: {
88 const int32_t arg2 = next32();
89 trace(Callstack_depth+1, "run") << "subtract imm32 0x" << HEXWORD << arg2 << " from EAX" << end();
90 BINARY_ARITHMETIC_OP(-, Reg[EAX].i, arg2);
91 break;
92 }
93
94
95
96 :(code)
97 void test_subtract_imm32_from_mem_at_r32() {
98 Reg[EBX].i = 0x2000;
99 run(
100 "== 0x1\n"
101
102 " 81 2b 01 00 00 00 \n"
103
104 "== 0x2000\n"
105 "0a 00 00 00\n"
106 );
107 CHECK_TRACE_CONTENTS(
108 "run: combine imm32 with r/m32\n"
109 "run: effective address is 0x00002000 (EBX)\n"
110 "run: imm32 is 0x00000001\n"
111 "run: subop subtract\n"
112 "run: storing 0x00000009\n"
113 );
114 }
115
116 :(before "End Op 81 Subops")
117 case 5: {
118 trace(Callstack_depth+1, "run") << "subop subtract" << end();
119 BINARY_ARITHMETIC_OP(-, *arg1, arg2);
120 break;
121 }
122
123
124
125 :(code)
126 void test_subtract_imm32_from_r32() {
127 Reg[EBX].i = 10;
128 run(
129 "== 0x1\n"
130
131 " 81 eb 01 00 00 00 \n"
132
133 );
134 CHECK_TRACE_CONTENTS(
135 "run: combine imm32 with r/m32\n"
136 "run: r/m32 is EBX\n"
137 "run: imm32 is 0x00000001\n"
138 "run: subop subtract\n"
139 "run: storing 0x00000009\n"
140 );
141 }
142
143
144
145 :(before "End Initialize Op Names")
146 put_new(Name, "c1", "shift rm32 by imm8 bits depending on subop (sal/sar/shl/shr)");
147
148 :(code)
149 void test_shift_left_r32_with_imm8() {
150 Reg[EBX].i = 13;
151 run(
152 "== 0x1\n"
153
154 " c1 e3 01 \n"
155
156 );
157 CHECK_TRACE_CONTENTS(
158 "run: operate on r/m32\n"
159 "run: r/m32 is EBX\n"
160 "run: subop: shift left by CL bits\n"
161 "run: storing 0x0000001a\n"
162 );
163 }
164
165 :(before "End Single-Byte Opcodes")
166 case 0xc1: {
167 const uint8_t modrm = next();
168 trace(Callstack_depth+1, "run") << "operate on r/m32" << end();
169 int32_t* arg1 = effective_address(modrm);
170 const uint8_t subop = (modrm>>3)&0x7;
171 switch (subop) {
172 case 4: {
173 trace(Callstack_depth+1, "run") << "subop: shift left by CL bits" << end();
174 uint8_t count = next() & 0x1f;
175
176 if (count == 1) {
177 bool msb = (*arg1 & 0x80000000) >> 1;
178 bool pnsb = (*arg1 & 0x40000000);
179 OF = (msb != pnsb);
180 }
181 *arg1 = (*arg1 << count);
182 ZF = (*arg1 == 0);
183 SF = (*arg1 < 0);
184 trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *arg1 << end();
185 break;
186 }
187
188 default:
189 cerr << "unrecognized subop for opcode c1: " << NUM(subop) << '\n';
190 exit(1);
191 }
192 break;
193 }
194
195
196
197 :(code)
198 void test_shift_right_arithmetic_r32_with_imm8() {
199 Reg[EBX].i = 26;
200 run(
201 "== 0x1\n"
202
203 " c1 fb 01 \n"
204
205 );
206 CHECK_TRACE_CONTENTS(
207 "run: operate on r/m32\n"
208 "run: r/m32 is EBX\n"
209 "run: subop: shift right by CL bits, while preserving sign\n"
210 "run: storing 0x0000000d\n"
211 );
212 }
213
214 :(before "End Op c1 Subops")
215 case 7: {
216 trace(Callstack_depth+1, "run") << "subop: shift right by CL bits, while preserving sign" << end();
217 uint8_t count = next() & 0x1f;
218 *arg1 = (*arg1 >> count);
219 ZF = (*arg1 == 0);
220 SF = (*arg1 < 0);
221
222 if (count == 1) OF = false;
223 trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *arg1 << end();
224 break;
225 }
226
227 :(code)
228 void test_shift_right_arithmetic_odd_r32_with_imm8() {
229 Reg[EBX].i = 27;
230 run(
231 "== 0x1\n"
232
233 " c1 fb 01 \n"
234
235 );
236 CHECK_TRACE_CONTENTS(
237 "run: operate on r/m32\n"
238 "run: r/m32 is EBX\n"
239 "run: subop: shift right by CL bits, while preserving sign\n"
240
241 "run: storing 0x0000000d\n"
242 );
243 }
244
245 :(code)
246 void test_shift_right_arithmetic_negative_r32_with_imm8() {
247 Reg[EBX].i = 0xfffffffd;
248 run(
249 "== 0x1\n"
250
251 " c1 fb 01 \n"
252
253 );
254 CHECK_TRACE_CONTENTS(
255 "run: operate on r/m32\n"
256 "run: r/m32 is EBX\n"
257 "run: subop: shift right by CL bits, while preserving sign\n"
258
259 "run: storing 0xfffffffe\n"
260 );
261 }
262
263
264
265 :(code)
266 void test_shift_right_logical_r32_with_imm8() {
267 Reg[EBX].i = 26;
268 run(
269 "== 0x1\n"
270
271 " c1 eb 01 \n"
272
273 );
274 CHECK_TRACE_CONTENTS(
275 "run: operate on r/m32\n"
276 "run: r/m32 is EBX\n"
277 "run: subop: shift right by CL bits, while padding zeroes\n"
278 "run: storing 0x0000000d\n"
279 );
280 }
281
282 :(before "End Op c1 Subops")
283 case 5: {
284 trace(Callstack_depth+1, "run") << "subop: shift right by CL bits, while padding zeroes" << end();
285 uint8_t count = next() & 0x1f;
286
287 if (count == 1) {
288 bool msb = (*arg1 & 0x80000000) >> 1;
289 bool pnsb = (*arg1 & 0x40000000);
290 OF = (msb != pnsb);
291 }
292 uint32_t* uarg1 = reinterpret_cast<uint32_t*>(arg1);
293 *uarg1 = (*uarg1 >> count);
294 ZF = (*uarg1 == 0);
295
296 SF = false;
297 trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *arg1 << end();
298 break;
299 }
300
301 :(code)
302 void test_shift_right_logical_odd_r32_with_imm8() {
303 Reg[EBX].i = 27;
304 run(
305 "== 0x1\n"
306
307 " c1 eb 01 \n"
308 );
309 CHECK_TRACE_CONTENTS(
310 "run: operate on r/m32\n"
311 "run: r/m32 is EBX\n"
312 "run: subop: shift right by CL bits, while padding zeroes\n"
313
314 "run: storing 0x0000000d\n"
315 );
316 }
317
318 :(code)
319 void test_shift_right_logical_negative_r32_with_imm8() {
320 Reg[EBX].i = 0xfffffffd;
321 run(
322 "== 0x1\n"
323
324 " c1 eb 01 \n"
325
326 );
327 CHECK_TRACE_CONTENTS(
328 "run: operate on r/m32\n"
329 "run: r/m32 is EBX\n"
330 "run: subop: shift right by CL bits, while padding zeroes\n"
331 "run: storing 0x7ffffffe\n"
332 );
333 }
334
335
336
337 :(before "End Initialize Op Names")
338 put_new(Name, "25", "EAX = bitwise AND of imm32 with EAX (and)");
339
340 :(code)
341 void test_and_imm32_with_eax() {
342 Reg[EAX].i = 0xff;
343 run(
344 "== 0x1\n"
345
346 " 25 0a 0b 0c 0d \n"
347 );
348 CHECK_TRACE_CONTENTS(
349 "run: and imm32 0x0d0c0b0a with EAX\n"
350 "run: storing 0x0000000a\n"
351 );
352 }
353
354 :(before "End Single-Byte Opcodes")
355 case 0x25: {
356 const int32_t arg2 = next32();
357 trace(Callstack_depth+1, "run") << "and imm32 0x" << HEXWORD << arg2 << " with EAX" << end();
358 BINARY_BITWISE_OP(&, Reg[EAX].i, arg2);
359 break;
360 }
361
362
363
364 :(code)
365 void test_and_imm32_with_mem_at_r32() {
366 Reg[EBX].i = 0x2000;
367 run(
368 "== 0x1\n"
369
370 " 81 23 0a 0b 0c 0d \n"
371
372 "== 0x2000\n"
373 "ff 00 00 00\n"
374 );
375 CHECK_TRACE_CONTENTS(
376 "run: combine imm32 with r/m32\n"
377 "run: effective address is 0x00002000 (EBX)\n"
378 "run: imm32 is 0x0d0c0b0a\n"
379 "run: subop and\n"
380 "run: storing 0x0000000a\n"
381 );
382 }
383
384 :(before "End Op 81 Subops")
385 case 4: {
386 trace(Callstack_depth+1, "run") << "subop and" << end();
387 BINARY_BITWISE_OP(&, *arg1, arg2);
388 break;
389 }
390
391
392
393 :(code)
394 void test_and_imm32_with_r32() {
395 Reg[EBX].i = 0xff;
396 run(
397 "== 0x1\n"
398
399 " 81 e3 0a 0b 0c 0d \n"
400
401 );
402 CHECK_TRACE_CONTENTS(
403 "run: combine imm32 with r/m32\n"
404 "run: r/m32 is EBX\n"
405 "run: imm32 is 0x0d0c0b0a\n"
406 "run: subop and\n"
407 "run: storing 0x0000000a\n"
408 );
409 }
410
411
412
413 :(before "End Initialize Op Names")
414 put_new(Name, "0d", "EAX = bitwise OR of imm32 with EAX (or)");
415
416 :(code)
417 void test_or_imm32_with_eax() {
418 Reg[EAX].i = 0xd0c0b0a0;
419 run(
420 "== 0x1\n"
421
422 " 0d 0a 0b 0c 0d \n"
423 );
424 CHECK_TRACE_CONTENTS(
425 "run: or imm32 0x0d0c0b0a with EAX\n"
426 "run: storing 0xddccbbaa\n"
427 );
428 }
429
430 :(before "End Single-Byte Opcodes")
431 case 0x0d: {
432 const int32_t arg2 = next32();
433 trace(Callstack_depth+1, "run") << "or imm32 0x" << HEXWORD << arg2 << " with EAX" << end();
434 BINARY_BITWISE_OP(|, Reg[EAX].i, arg2);
435 break;
436 }
437
438
439
440 :(code)
441 void test_or_imm32_with_mem_at_r32() {
442 Reg[EBX].i = 0x2000;
443 run(
444 "== 0x1\n"
445
446 " 81 0b 0a 0b 0c 0d \n"
447
448 "== 0x2000\n"
449 "a0 b0 c0 d0\n"
450 );
451 CHECK_TRACE_CONTENTS(
452 "run: combine imm32 with r/m32\n"
453 "run: effective address is 0x00002000 (EBX)\n"
454 "run: imm32 is 0x0d0c0b0a\n"
455 "run: subop or\n"
456 "run: storing 0xddccbbaa\n"
457 );
458 }
459
460 :(before "End Op 81 Subops")
461 case 1: {
462 trace(Callstack_depth+1, "run") << "subop or" << end();
463 BINARY_BITWISE_OP(|, *arg1, arg2);
464 break;
465 }
466
467 :(code)
468 void test_or_imm32_with_r32() {
469 Reg[EBX].i = 0xd0c0b0a0;
470 run(
471 "== 0x1\n"
472
473 " 81 cb 0a 0b 0c 0d \n"
474
475 );
476 CHECK_TRACE_CONTENTS(
477 "run: combine imm32 with r/m32\n"
478 "run: r/m32 is EBX\n"
479 "run: imm32 is 0x0d0c0b0a\n"
480 "run: subop or\n"
481 "run: storing 0xddccbbaa\n"
482 );
483 }
484
485
486
487 :(before "End Initialize Op Names")
488 put_new(Name, "35", "EAX = bitwise XOR of imm32 with EAX (xor)");
489
490 :(code)
491 void test_xor_imm32_with_eax() {
492 Reg[EAX].i = 0xddccb0a0;
493 run(
494 "== 0x1\n"
495
496 " 35 0a 0b 0c 0d \n"
497 );
498 CHECK_TRACE_CONTENTS(
499 "run: xor imm32 0x0d0c0b0a with EAX\n"
500 "run: storing 0xd0c0bbaa\n"
501 );
502 }
503
504 :(before "End Single-Byte Opcodes")
505 case 0x35: {
506 const int32_t arg2 = next32();
507 trace(Callstack_depth+1, "run") << "xor imm32 0x" << HEXWORD << arg2 << " with EAX" << end();
508 BINARY_BITWISE_OP(^, Reg[EAX].i, arg2);
509 break;
510 }
511
512
513
514 :(code)
515 void test_xor_imm32_with_mem_at_r32() {
516 Reg[EBX].i = 0x2000;
517 run(
518 "== 0x1\n"
519
520 " 81 33 0a 0b 0c 0d \n"
521
522 "== 0x2000\n"
523 "a0 b0 c0 d0\n"
524 );
525 CHECK_TRACE_CONTENTS(
526 "run: combine imm32 with r/m32\n"
527 "run: effective address is 0x00002000 (EBX)\n"
528 "run: imm32 is 0x0d0c0b0a\n"
529 "run: subop xor\n"
530 "run: storing 0xddccbbaa\n"
531 );
532 }
533
534 :(before "End Op 81 Subops")
535 case 6: {
536 trace(Callstack_depth+1, "run") << "subop xor" << end();
537 BINARY_BITWISE_OP(^, *arg1, arg2);
538 break;
539 }
540
541 :(code)
542 void test_xor_imm32_with_r32() {
543 Reg[EBX].i = 0xd0c0b0a0;
544 run(
545 "== 0x1\n"
546
547 " 81 f3 0a 0b 0c 0d \n"
548
549 );
550 CHECK_TRACE_CONTENTS(
551 "run: combine imm32 with r/m32\n"
552 "run: r/m32 is EBX\n"
553 "run: imm32 is 0x0d0c0b0a\n"
554 "run: subop xor\n"
555 "run: storing 0xddccbbaa\n"
556 );
557 }
558
559
560
561 :(before "End Initialize Op Names")
562 put_new(Name, "3d", "compare: set SF if EAX < imm32 (cmp)");
563
564 :(code)
565 void test_compare_imm32_with_eax_greater() {
566 Reg[EAX].i = 0x0d0c0b0a;
567 run(
568 "== 0x1\n"
569
570 " 3d 07 0b 0c 0d \n"
571 );
572 CHECK_TRACE_CONTENTS(
573 "run: compare EAX and imm32 0x0d0c0b07\n"
574 "run: SF=0; ZF=0; OF=0\n"
575 );
576 }
577
578 :(before "End Single-Byte Opcodes")
579 case 0x3d: {
580 const int32_t arg1 = Reg[EAX].i;
581 const int32_t arg2 = next32();
582 trace(Callstack_depth+1, "run") << "compare EAX and imm32 0x" << HEXWORD << arg2 << end();
583 const int32_t tmp1 = arg1 - arg2;
584 SF = (tmp1 < 0);
585 ZF = (tmp1 == 0);
586 const int64_t tmp2 = arg1 - arg2;
587 OF = (tmp1 != tmp2);
588 trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; OF=" << OF << end();
589 break;
590 }
591
592 :(code)
593 void test_compare_imm32_with_eax_lesser() {
594 Reg[EAX].i = 0x0d0c0b07;
595 run(
596 "== 0x1\n"
597
598 " 3d 0a 0b 0c 0d \n"
599 );
600 CHECK_TRACE_CONTENTS(
601 "run: compare EAX and imm32 0x0d0c0b0a\n"
602 "run: SF=1; ZF=0; OF=0\n"
603 );
604 }
605
606 :(code)
607 void test_compare_imm32_with_eax_equal() {
608 Reg[EAX].i = 0x0d0c0b0a;
609 run(
610 "== 0x1\n"
611
612 " 3d 0a 0b 0c 0d \n"
613 );
614 CHECK_TRACE_CONTENTS(
615 "run: compare EAX and imm32 0x0d0c0b0a\n"
616 "run: SF=0; ZF=1; OF=0\n"
617 );
618 }
619
620
621
622 :(code)
623 void test_compare_imm32_with_r32_greater() {
624 Reg[EBX].i = 0x0d0c0b0a;
625 run(
626 "== 0x1\n"
627
628 " 81 fb 07 0b 0c 0d \n"
629
630 );
631 CHECK_TRACE_CONTENTS(
632 "run: combine imm32 with r/m32\n"
633 "run: r/m32 is EBX\n"
634 "run: imm32 is 0x0d0c0b07\n"
635 "run: SF=0; ZF=0; OF=0\n"
636 );
637 }
638
639 :(before "End Op 81 Subops")
640 case 7: {
641 trace(Callstack_depth+1, "run") << "subop compare" << end();
642 const int32_t tmp1 = *arg1 - arg2;
643 SF = (tmp1 < 0);
644 ZF = (tmp1 == 0);
645 const int64_t tmp2 = *arg1 - arg2;
646 OF = (tmp1 != tmp2);
647 trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; OF=" << OF << end();
648 break;
649 }
650
651 :(code)
652 void test_compare_imm32_with_r32_lesser() {
653 Reg[EBX].i = 0x0d0c0b07;
654 run(
655 "== 0x1\n"
656
657 " 81 fb 0a 0b 0c 0d \n"
658
659 );
660 CHECK_TRACE_CONTENTS(
661 "run: combine imm32 with r/m32\n"
662 "run: r/m32 is EBX\n"
663 "run: imm32 is 0x0d0c0b0a\n"
664 "run: SF=1; ZF=0; OF=0\n"
665 );
666 }
667
668 :(code)
669 void test_compare_imm32_with_r32_equal() {
670 Reg[EBX].i = 0x0d0c0b0a;
671 run(
672 "== 0x1\n"
673
674 " 81 fb 0a 0b 0c 0d \n"
675
676 );
677 CHECK_TRACE_CONTENTS(
678 "run: combine imm32 with r/m32\n"
679 "run: r/m32 is EBX\n"
680 "run: imm32 is 0x0d0c0b0a\n"
681 "run: SF=0; ZF=1; OF=0\n"
682 );
683 }
684
685 :(code)
686 void test_compare_imm32_with_mem_at_r32_greater() {
687 Reg[EBX].i = 0x2000;
688 run(
689 "== 0x1\n"
690
691 " 81 3b 07 0b 0c 0d \n"
692
693 "== 0x2000\n"
694 "0a 0b 0c 0d\n"
695 );
696 CHECK_TRACE_CONTENTS(
697 "run: combine imm32 with r/m32\n"
698 "run: effective address is 0x00002000 (EBX)\n"
699 "run: imm32 is 0x0d0c0b07\n"
700 "run: SF=0; ZF=0; OF=0\n"
701 );
702 }
703
704 :(code)
705 void test_compare_imm32_with_mem_at_r32_lesser() {
706 Reg[EBX].i = 0x2000;
707 run(
708 "== 0x1\n"
709
710 " 81 3b 0a 0b 0c 0d \n"
711
712 "== 0x2000\n"
713 "07 0b 0c 0d\n"
714 );
715 CHECK_TRACE_CONTENTS(
716 "run: combine imm32 with r/m32\n"
717 "run: effective address is 0x00002000 (EBX)\n"
718 "run: imm32 is 0x0d0c0b0a\n"
719 "run: SF=1; ZF=0; OF=0\n"
720 );
721 }
722
723 :(code)
724 void test_compare_imm32_with_mem_at_r32_equal() {
725 Reg[EBX].i = 0x0d0c0b0a;
726 Reg[EBX].i = 0x2000;
727 run(
728 "== 0x1\n"
729
730 " 81 3b 0a 0b 0c 0d \n"
731
732 "== 0x2000\n"
733 "0a 0b 0c 0d\n"
734 );
735 CHECK_TRACE_CONTENTS(
736 "run: combine imm32 with r/m32\n"
737 "run: effective address is 0x00002000 (EBX)\n"
738 "run: imm32 is 0x0d0c0b0a\n"
739 "run: SF=0; ZF=1; OF=0\n"
740 );
741 }
742
743
744
745 :(before "End Initialize Op Names")
746 put_new(Name, "b8", "copy imm32 to EAX (mov)");
747 put_new(Name, "b9", "copy imm32 to ECX (mov)");
748 put_new(Name, "ba", "copy imm32 to EDX (mov)");
749 put_new(Name, "bb", "copy imm32 to EBX (mov)");
750 put_new(Name, "bc", "copy imm32 to ESP (mov)");
751 put_new(Name, "bd", "copy imm32 to EBP (mov)");
752 put_new(Name, "be", "copy imm32 to ESI (mov)");
753 put_new(Name, "bf", "copy imm32 to EDI (mov)");
754
755 :(code)
756 void test_copy_imm32_to_r32() {
757 run(
758 "== 0x1\n"
759
760 " bb 0a 0b 0c 0d \n"
761 );
762 CHECK_TRACE_CONTENTS(
763 "run: copy imm32 0x0d0c0b0a to EBX\n"
764 );
765 }
766
767 :(before "End Single-Byte Opcodes")
768 case 0xb8:
769 case 0xb9:
770 case 0xba:
771 case 0xbb:
772 case 0xbc:
773 case 0xbd:
774 case 0xbe:
775 case 0xbf: {
776 const uint8_t rdest = op & 0x7;
777 const int32_t src = next32();
778 trace(Callstack_depth+1, "run") << "copy imm32 0x" << HEXWORD << src << " to " << rname(rdest) << end();
779 Reg[rdest].i = src;
780 break;
781 }
782
783
784
785 :(before "End Initialize Op Names")
786 put_new(Name, "c7", "copy imm32 to rm32 (mov)");
787
788 :(code)
789 void test_copy_imm32_to_mem_at_r32() {
790 Reg[EBX].i = 0x60;
791 run(
792 "== 0x1\n"
793
794 " c7 03 0a 0b 0c 0d \n"
795
796 );
797 CHECK_TRACE_CONTENTS(
798 "run: copy imm32 to r/m32\n"
799 "run: effective address is 0x00000060 (EBX)\n"
800 "run: imm32 is 0x0d0c0b0a\n"
801 );
802 }
803
804 :(before "End Single-Byte Opcodes")
805 case 0xc7: {
806 const uint8_t modrm = next();
807 trace(Callstack_depth+1, "run") << "copy imm32 to r/m32" << end();
808 const uint8_t subop = (modrm>>3)&0x7;
809 if (subop != 0) {
810 cerr << "unrecognized subop for opcode c7: " << NUM(subop) << " (only 0/copy currently implemented)\n";
811 exit(1);
812 }
813 int32_t* dest = effective_address(modrm);
814 const int32_t src = next32();
815 trace(Callstack_depth+1, "run") << "imm32 is 0x" << HEXWORD << src << end();
816 *dest = src;
817 break;
818 }
819
820
821
822 :(before "End Initialize Op Names")
823 put_new(Name, "68", "push imm32 to stack (push)");
824
825 :(code)
826 void test_push_imm32() {
827 Reg[ESP].u = 0x14;
828 run(
829 "== 0x1\n"
830
831 " 68 af 00 00 00 \n"
832 );
833 CHECK_TRACE_CONTENTS(
834 "run: push imm32 0x000000af\n"
835 "run: ESP is now 0x00000010\n"
836 "run: contents at ESP: 0x000000af\n"
837 );
838 }
839
840 :(before "End Single-Byte Opcodes")
841 case 0x68: {
842 const uint32_t val = static_cast<uint32_t>(next32());
843 trace(Callstack_depth+1, "run") << "push imm32 0x" << HEXWORD << val << end();
844
845 push(val);
846 trace(Callstack_depth+1, "run") << "ESP is now 0x" << HEXWORD << Reg[ESP].u << end();
847 trace(Callstack_depth+1, "run") << "contents at ESP: 0x" << HEXWORD << read_mem_u32(Reg[ESP].u) << end();
848 break;
849 }