https://github.com/akkartik/mu/blob/master/subx/013direct_addressing.cc
1
2
3 :(before "End Initialize Op Names")
4 put_new(Name, "01", "add r32 to rm32 (add)");
5
6 :(code)
7 void test_add_r32_to_r32() {
8 Reg[EAX].i = 0x10;
9 Reg[EBX].i = 1;
10 run(
11 "== 0x1\n"
12
13 " 01 d8 \n"
14
15 );
16 CHECK_TRACE_CONTENTS(
17 "run: add EBX to r/m32\n"
18 "run: r/m32 is EAX\n"
19 "run: storing 0x00000011\n"
20 );
21 }
22
23 :(before "End Single-Byte Opcodes")
24 case 0x01: {
25 uint8_t modrm = next();
26 uint8_t arg2 = (modrm>>3)&0x7;
27 trace(Callstack_depth+1, "run") << "add " << rname(arg2) << " to r/m32" << end();
28 int32_t* arg1 = effective_address(modrm);
29 BINARY_ARITHMETIC_OP(+, *arg1, Reg[arg2].i);
30 break;
31 }
32
33 :(code)
34
35
36
37
38 int32_t* effective_address(uint8_t modrm) {
39 const uint8_t mod = (modrm>>6);
40
41 const uint8_t rm = modrm & 0x7;
42 if (mod == 3) {
43
44 trace(Callstack_depth+1, "run") << "r/m32 is " << rname(rm) << end();
45 return &Reg[rm].i;
46 }
47 uint32_t addr = effective_address_number(modrm);
48 trace(Callstack_depth+1, "run") << "effective address contains " << read_mem_i32(addr) << end();
49 return mem_addr_i32(addr);
50 }
51
52
53 uint32_t effective_address_number(uint8_t modrm) {
54 const uint8_t mod = (modrm>>6);
55
56 const uint8_t rm = modrm & 0x7;
57 uint32_t addr = 0;
58 switch (mod) {
59 case 3:
60
61 raise << "unexpected direct addressing mode\n" << end();
62 return 0;
63
64 default:
65 cerr << "unrecognized mod bits: " << NUM(mod) << '\n';
66 exit(1);
67 }
68
69
70 return addr;
71 }
72
73 string rname(uint8_t r) {
74 switch (r) {
75 case 0: return "EAX";
76 case 1: return "ECX";
77 case 2: return "EDX";
78 case 3: return "EBX";
79 case 4: return "ESP";
80 case 5: return "EBP";
81 case 6: return "ESI";
82 case 7: return "EDI";
83 default: raise << "invalid register " << r << '\n' << end(); return "";
84 }
85 }
86
87
88
89 :(before "End Initialize Op Names")
90 put_new(Name, "29", "subtract r32 from rm32 (sub)");
91
92 :(code)
93 void test_subtract_r32_from_r32() {
94 Reg[EAX].i = 10;
95 Reg[EBX].i = 1;
96 run(
97 "== 0x1\n"
98
99 " 29 d8 \n"
100
101 );
102 CHECK_TRACE_CONTENTS(
103 "run: subtract EBX from r/m32\n"
104 "run: r/m32 is EAX\n"
105 "run: storing 0x00000009\n"
106 );
107 }
108
109 :(before "End Single-Byte Opcodes")
110 case 0x29: {
111 const uint8_t modrm = next();
112 const uint8_t arg2 = (modrm>>3)&0x7;
113 trace(Callstack_depth+1, "run") << "subtract " << rname(arg2) << " from r/m32" << end();
114 int32_t* arg1 = effective_address(modrm);
115 BINARY_ARITHMETIC_OP(-, *arg1, Reg[arg2].i);
116 break;
117 }
118
119
120
121 :(before "End Initialize Op Names")
122 put_new(Name, "f7", "negate/multiply rm32 (with EAX if necessary) depending on subop (neg/mul)");
123
124 :(code)
125 void test_multiply_eax_by_r32() {
126 Reg[EAX].i = 4;
127 Reg[ECX].i = 3;
128 run(
129 "== 0x1\n"
130
131 " f7 e1 \n"
132
133 );
134 CHECK_TRACE_CONTENTS(
135 "run: operate on r/m32\n"
136 "run: r/m32 is ECX\n"
137 "run: subop: multiply EAX by r/m32\n"
138 "run: storing 0x0000000c\n"
139 );
140 }
141
142 :(before "End Single-Byte Opcodes")
143 case 0xf7: {
144 const uint8_t modrm = next();
145 trace(Callstack_depth+1, "run") << "operate on r/m32" << end();
146 int32_t* arg1 = effective_address(modrm);
147 const uint8_t subop = (modrm>>3)&0x7;
148 switch (subop) {
149 case 4: {
150 trace(Callstack_depth+1, "run") << "subop: multiply EAX by r/m32" << end();
151 const uint64_t result = Reg[EAX].u * static_cast<uint32_t>(*arg1);
152 Reg[EAX].u = result & 0xffffffff;
153 Reg[EDX].u = result >> 32;
154 OF = (Reg[EDX].u != 0);
155 trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[EAX].u << end();
156 break;
157 }
158
159 default:
160 cerr << "unrecognized subop for opcode f7: " << NUM(subop) << '\n';
161 exit(1);
162 }
163 break;
164 }
165
166
167
168 :(before "End Initialize Op Names")
169 put_new(Name_0f, "af", "multiply rm32 into r32 (imul)");
170
171 :(code)
172 void test_multiply_r32_into_r32() {
173 Reg[EAX].i = 4;
174 Reg[EBX].i = 2;
175 run(
176 "== 0x1\n"
177
178 " 0f af d8 \n"
179
180 );
181 CHECK_TRACE_CONTENTS(
182 "run: multiply r/m32 into EBX\n"
183 "run: r/m32 is EAX\n"
184 "run: storing 0x00000008\n"
185 );
186 }
187
188 :(before "End Two-Byte Opcodes Starting With 0f")
189 case 0xaf: {
190 const uint8_t modrm = next();
191 const uint8_t arg2 = (modrm>>3)&0x7;
192 trace(Callstack_depth+1, "run") << "multiply r/m32 into " << rname(arg2) << end();
193 const int32_t* arg1 = effective_address(modrm);
194 BINARY_ARITHMETIC_OP(*, Reg[arg2].i, *arg1);
195 break;
196 }
197
198
199
200 :(code)
201 void test_negate_r32() {
202 Reg[EBX].i = 1;
203 run(
204 "== 0x1\n"
205
206 " f7 db \n"
207
208 );
209 CHECK_TRACE_CONTENTS(
210 "run: operate on r/m32\n"
211 "run: r/m32 is EBX\n"
212 "run: subop: negate\n"
213 "run: storing 0xffffffff\n"
214 );
215 }
216
217 :(before "End Op f7 Subops")
218 case 3: {
219 trace(Callstack_depth+1, "run") << "subop: negate" << end();
220
221 if (static_cast<uint32_t>(*arg1) == 0x80000000) {
222 trace(Callstack_depth+1, "run") << "overflow" << end();
223 SF = true;
224 ZF = false;
225 OF = true;
226 break;
227 }
228 *arg1 = -(*arg1);
229 trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *arg1 << end();
230 SF = (*arg1 >> 31);
231 ZF = (*arg1 == 0);
232 OF = false;
233 break;
234 }
235
236 :(code)
237
238 void test_negate_can_overflow() {
239 Reg[EBX].i = 0x80000000;
240 run(
241 "== 0x1\n"
242
243 " f7 db \n"
244
245 );
246 CHECK_TRACE_CONTENTS(
247 "run: operate on r/m32\n"
248 "run: r/m32 is EBX\n"
249 "run: subop: negate\n"
250 "run: overflow\n"
251 );
252 }
253
254
255
256 :(before "End Initialize Op Names")
257 put_new(Name, "d3", "shift rm32 by CL bits depending on subop (sal/sar/shl/shr)");
258
259 :(code)
260 void test_shift_left_r32_with_cl() {
261 Reg[EBX].i = 13;
262 Reg[ECX].i = 1;
263 run(
264 "== 0x1\n"
265
266 " d3 e3 \n"
267
268 );
269 CHECK_TRACE_CONTENTS(
270 "run: operate on r/m32\n"
271 "run: r/m32 is EBX\n"
272 "run: subop: shift left by CL bits\n"
273 "run: storing 0x0000001a\n"
274 );
275 }
276
277 :(before "End Single-Byte Opcodes")
278 case 0xd3: {
279 const uint8_t modrm = next();
280 trace(Callstack_depth+1, "run") << "operate on r/m32" << end();
281 int32_t* arg1 = effective_address(modrm);
282 const uint8_t subop = (modrm>>3)&0x7;
283 switch (subop) {
284 case 4: {
285 trace(Callstack_depth+1, "run") << "subop: shift left by CL bits" << end();
286 uint8_t count = Reg[ECX].u & 0x1f;
287
288 if (count == 1) {
289 bool msb = (*arg1 & 0x80000000) >> 1;
290 bool pnsb = (*arg1 & 0x40000000);
291 OF = (msb != pnsb);
292 }
293 *arg1 = (*arg1 << count);
294 ZF = (*arg1 == 0);
295 SF = (*arg1 < 0);
296 trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *arg1 << end();
297 break;
298 }
299
300 default:
301 cerr << "unrecognized subop for opcode d3: " << NUM(subop) << '\n';
302 exit(1);
303 }
304 break;
305 }
306
307
308
309 :(code)
310 void test_shift_right_arithmetic_r32_with_cl() {
311 Reg[EBX].i = 26;
312 Reg[ECX].i = 1;
313 run(
314 "== 0x1\n"
315
316 " d3 fb \n"
317
318 );
319 CHECK_TRACE_CONTENTS(
320 "run: operate on r/m32\n"
321 "run: r/m32 is EBX\n"
322 "run: subop: shift right by CL bits, while preserving sign\n"
323 "run: storing 0x0000000d\n"
324 );
325 }
326
327 :(before "End Op d3 Subops")
328 case 7: {
329 trace(Callstack_depth+1, "run") << "subop: shift right by CL bits, while preserving sign" << end();
330 uint8_t count = Reg[ECX].u & 0x1f;
331 *arg1 = (*arg1 >> count);
332 ZF = (*arg1 == 0);
333 SF = (*arg1 < 0);
334
335 if (count == 1) OF = false;
336 trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *arg1 << end();
337 break;
338 }
339
340 :(code)
341 void test_shift_right_arithmetic_odd_r32_with_cl() {
342 Reg[EBX].i = 27;
343 Reg[ECX].i = 1;
344 run(
345 "== 0x1\n"
346
347 " d3 fb \n"
348
349 );
350 CHECK_TRACE_CONTENTS(
351 "run: operate on r/m32\n"
352 "run: r/m32 is EBX\n"
353 "run: subop: shift right by CL bits, while preserving sign\n"
354
355 "run: storing 0x0000000d\n"
356 );
357 }
358
359 void test_shift_right_arithmetic_negative_r32_with_cl() {
360 Reg[EBX].i = 0xfffffffd;
361 Reg[ECX].i = 1;
362 run(
363 "== 0x1\n"
364
365 " d3 fb \n"
366
367 );
368 CHECK_TRACE_CONTENTS(
369 "run: operate on r/m32\n"
370 "run: r/m32 is EBX\n"
371 "run: subop: shift right by CL bits, while preserving sign\n"
372
373 "run: storing 0xfffffffe\n"
374 );
375 }
376
377
378
379 :(code)
380 void test_shift_right_logical_r32_with_cl() {
381 Reg[EBX].i = 26;
382 Reg[ECX].i = 1;
383 run(
384 "== 0x1\n"
385
386 " d3 eb \n"
387
388 );
389 CHECK_TRACE_CONTENTS(
390 "run: operate on r/m32\n"
391 "run: r/m32 is EBX\n"
392 "run: subop: shift right by CL bits, while padding zeroes\n"
393
394 "run: storing 0x0000000d\n"
395 );
396 }
397
398 :(before "End Op d3 Subops")
399 case 5: {
400 trace(Callstack_depth+1, "run") << "subop: shift right by CL bits, while padding zeroes" << end();
401 uint8_t count = Reg[ECX].u & 0x1f;
402
403 if (count == 1) {
404 bool msb = (*arg1 & 0x80000000) >> 1;
405 bool pnsb = (*arg1 & 0x40000000);
406 OF = (msb != pnsb);
407 }
408 uint32_t* uarg1 = reinterpret_cast<uint32_t*>(arg1);
409 *uarg1 = (*uarg1 >> count);
410 ZF = (*uarg1 == 0);
411
412 SF = false;
413 trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *arg1 << end();
414 break;
415 }
416
417 :(code)
418 void test_shift_right_logical_odd_r32_with_cl() {
419 Reg[EBX].i = 27;
420 Reg[ECX].i = 1;
421 run(
422 "== 0x1\n"
423
424 " d3 eb \n"
425
426 );
427 CHECK_TRACE_CONTENTS(
428 "run: operate on r/m32\n"
429 "run: r/m32 is EBX\n"
430 "run: subop: shift right by CL bits, while padding zeroes\n"
431
432 "run: storing 0x0000000d\n"
433 );
434 }
435
436 void test_shift_right_logical_negative_r32_with_cl() {
437 Reg[EBX].i = 0xfffffffd;
438 Reg[ECX].i = 1;
439 run(
440 "== 0x1\n"
441
442 " d3 eb \n"
443
444 );
445 CHECK_TRACE_CONTENTS(
446 "run: operate on r/m32\n"
447 "run: r/m32 is EBX\n"
448 "run: subop: shift right by CL bits, while padding zeroes\n"
449 "run: storing 0x7ffffffe\n"
450 );
451 }
452
453
454
455 :(before "End Initialize Op Names")
456 put_new(Name, "21", "rm32 = bitwise AND of r32 with rm32 (and)");
457
458 :(code)
459 void test_and_r32_with_r32() {
460 Reg[EAX].i = 0x0a0b0c0d;
461 Reg[EBX].i = 0x000000ff;
462 run(
463 "== 0x1\n"
464
465 " 21 d8 \n"
466
467 );
468 CHECK_TRACE_CONTENTS(
469 "run: and EBX with r/m32\n"
470 "run: r/m32 is EAX\n"
471 "run: storing 0x0000000d\n"
472 );
473 }
474
475 :(before "End Single-Byte Opcodes")
476 case 0x21: {
477 const uint8_t modrm = next();
478 const uint8_t arg2 = (modrm>>3)&0x7;
479 trace(Callstack_depth+1, "run") << "and " << rname(arg2) << " with r/m32" << end();
480 int32_t* arg1 = effective_address(modrm);
481 BINARY_BITWISE_OP(&, *arg1, Reg[arg2].u);
482 break;
483 }
484
485
486
487 :(before "End Initialize Op Names")
488 put_new(Name, "09", "rm32 = bitwise OR of r32 with rm32 (or)");
489
490 :(code)
491 void test_or_r32_with_r32() {
492 Reg[EAX].i = 0x0a0b0c0d;
493 Reg[EBX].i = 0xa0b0c0d0;
494 run(
495 "== 0x1\n"
496
497 " 09 d8 \n"
498
499 );
500 CHECK_TRACE_CONTENTS(
501 "run: or EBX with r/m32\n"
502 "run: r/m32 is EAX\n"
503 "run: storing 0xaabbccdd\n"
504 );
505 }
506
507 :(before "End Single-Byte Opcodes")
508 case 0x09: {
509 const uint8_t modrm = next();
510 const uint8_t arg2 = (modrm>>3)&0x7;
511 trace(Callstack_depth+1, "run") << "or " << rname(arg2) << " with r/m32" << end();
512 int32_t* arg1 = effective_address(modrm);
513 BINARY_BITWISE_OP(|, *arg1, Reg[arg2].u);
514 break;
515 }
516
517
518
519 :(before "End Initialize Op Names")
520 put_new(Name, "31", "rm32 = bitwise XOR of r32 with rm32 (xor)");
521
522 :(code)
523 void test_xor_r32_with_r32() {
524 Reg[EAX].i = 0x0a0b0c0d;
525 Reg[EBX].i = 0xaabbc0d0;
526 run(
527 "== 0x1\n"
528
529 " 31 d8 \n"
530
531 );
532 CHECK_TRACE_CONTENTS(
533 "run: xor EBX with r/m32\n"
534 "run: r/m32 is EAX\n"
535 "run: storing 0xa0b0ccdd\n"
536 );
537 }
538
539 :(before "End Single-Byte Opcodes")
540 case 0x31: {
541 const uint8_t modrm = next();
542 const uint8_t arg2 = (modrm>>3)&0x7;
543 trace(Callstack_depth+1, "run") << "xor " << rname(arg2) << " with r/m32" << end();
544 int32_t* arg1 = effective_address(modrm);
545 BINARY_BITWISE_OP(^, *arg1, Reg[arg2].u);
546 break;
547 }
548
549
550
551 :(code)
552 void test_not_r32() {
553 Reg[EBX].i = 0x0f0f00ff;
554 run(
555 "== 0x1\n"
556
557 " f7 d3 \n"
558
559 );
560 CHECK_TRACE_CONTENTS(
561 "run: operate on r/m32\n"
562 "run: r/m32 is EBX\n"
563 "run: subop: not\n"
564 "run: storing 0xf0f0ff00\n"
565 );
566 }
567
568 :(before "End Op f7 Subops")
569 case 2: {
570 trace(Callstack_depth+1, "run") << "subop: not" << end();
571 *arg1 = ~(*arg1);
572 trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *arg1 << end();
573 SF = (*arg1 >> 31);
574 ZF = (*arg1 == 0);
575 OF = false;
576 break;
577 }
578
579
580
581 :(before "End Initialize Op Names")
582 put_new(Name, "39", "compare: set SF if rm32 < r32 (cmp)");
583
584 :(code)
585 void test_compare_r32_with_r32_greater() {
586 Reg[EAX].i = 0x0a0b0c0d;
587 Reg[EBX].i = 0x0a0b0c07;
588 run(
589 "== 0x1\n"
590
591 " 39 d8 \n"
592
593 );
594 CHECK_TRACE_CONTENTS(
595 "run: compare EBX with r/m32\n"
596 "run: r/m32 is EAX\n"
597 "run: SF=0; ZF=0; OF=0\n"
598 );
599 }
600
601 :(before "End Single-Byte Opcodes")
602 case 0x39: {
603 const uint8_t modrm = next();
604 const uint8_t reg2 = (modrm>>3)&0x7;
605 trace(Callstack_depth+1, "run") << "compare " << rname(reg2) << " with r/m32" << end();
606 const int32_t* arg1 = effective_address(modrm);
607 const int32_t arg2 = Reg[reg2].i;
608 const int32_t tmp1 = *arg1 - arg2;
609 SF = (tmp1 < 0);
610 ZF = (tmp1 == 0);
611 const int64_t tmp2 = *arg1 - arg2;
612 OF = (tmp1 != tmp2);
613 trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; OF=" << OF << end();
614 break;
615 }
616
617 :(code)
618 void test_compare_r32_with_r32_lesser() {
619 Reg[EAX].i = 0x0a0b0c07;
620 Reg[EBX].i = 0x0a0b0c0d;
621 run(
622 "== 0x1\n"
623
624 " 39 d8 \n"
625
626 );
627 CHECK_TRACE_CONTENTS(
628 "run: compare EBX with r/m32\n"
629 "run: r/m32 is EAX\n"
630 "run: SF=1; ZF=0; OF=0\n"
631 );
632 }
633
634 void test_compare_r32_with_r32_equal() {
635 Reg[EAX].i = 0x0a0b0c0d;
636 Reg[EBX].i = 0x0a0b0c0d;
637 run(
638 "== 0x1\n"
639
640 " 39 d8 \n"
641
642 );
643 CHECK_TRACE_CONTENTS(
644 "run: compare EBX with r/m32\n"
645 "run: r/m32 is EAX\n"
646 "run: SF=0; ZF=1; OF=0\n"
647 );
648 }
649
650
651
652 :(before "End Initialize Op Names")
653 put_new(Name, "89", "copy r32 to rm32 (mov)");
654
655 :(code)
656 void test_copy_r32_to_r32() {
657 Reg[EBX].i = 0xaf;
658 run(
659 "== 0x1\n"
660
661 " 89 d8 \n"
662
663 );
664 CHECK_TRACE_CONTENTS(
665 "run: copy EBX to r/m32\n"
666 "run: r/m32 is EAX\n"
667 "run: storing 0x000000af\n"
668 );
669 }
670
671 :(before "End Single-Byte Opcodes")
672 case 0x89: {
673 const uint8_t modrm = next();
674 const uint8_t rsrc = (modrm>>3)&0x7;
675 trace(Callstack_depth+1, "run") << "copy " << rname(rsrc) << " to r/m32" << end();
676 int32_t* dest = effective_address(modrm);
677 *dest = Reg[rsrc].i;
678 trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *dest << end();
679 break;
680 }
681
682
683
684 :(before "End Initialize Op Names")
685 put_new(Name, "87", "swap the contents of r32 and rm32 (xchg)");
686
687 :(code)
688 void test_xchg_r32_with_r32() {
689 Reg[EBX].i = 0xaf;
690 Reg[EAX].i = 0x2e;
691 run(
692 "== 0x1\n"
693
694 " 87 d8 \n"
695
696 );
697 CHECK_TRACE_CONTENTS(
698 "run: exchange EBX with r/m32\n"
699 "run: r/m32 is EAX\n"
700 "run: storing 0x000000af in r/m32\n"
701 "run: storing 0x0000002e in EBX\n"
702 );
703 }
704
705 :(before "End Single-Byte Opcodes")
706 case 0x87: {
707 const uint8_t modrm = next();
708 const uint8_t reg2 = (modrm>>3)&0x7;
709 trace(Callstack_depth+1, "run") << "exchange " << rname(reg2) << " with r/m32" << end();
710 int32_t* arg1 = effective_address(modrm);
711 const int32_t tmp = *arg1;
712 *arg1 = Reg[reg2].i;
713 Reg[reg2].i = tmp;
714 trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *arg1 << " in r/m32" << end();
715 trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[reg2].i << " in " << rname(reg2) << end();
716 break;
717 }
718
719
720
721 :(before "End Initialize Op Names")
722 put_new(Name, "40", "increment EAX (inc)");
723 put_new(Name, "41", "increment ECX (inc)");
724 put_new(Name, "42", "increment EDX (inc)");
725 put_new(Name, "43", "increment EBX (inc)");
726 put_new(Name, "44", "increment ESP (inc)");
727 put_new(Name, "45", "increment EBP (inc)");
728 put_new(Name, "46", "increment ESI (inc)");
729 put_new(Name, "47", "increment EDI (inc)");
730
731 :(code)
732 void test_increment_r32() {
733 Reg[ECX].u = 0x1f;
734 run(
735 "== 0x1\n"
736
737 " 41 \n"
738 );
739 CHECK_TRACE_CONTENTS(
740 "run: increment ECX\n"
741 "run: storing value 0x00000020\n"
742 );
743 }
744
745 :(before "End Single-Byte Opcodes")
746 case 0x40:
747 case 0x41:
748 case 0x42:
749 case 0x43:
750 case 0x44:
751 case 0x45:
752 case 0x46:
753 case 0x47: {
754 const uint8_t reg = op & 0x7;
755 trace(Callstack_depth+1, "run") << "increment " << rname(reg) << end();
756 ++Reg[reg].u;
757 trace(Callstack_depth+1, "run") << "storing value 0x" << HEXWORD << Reg[reg].u << end();
758 break;
759 }
760
761 :(before "End Initialize Op Names")
762 put_new(Name, "ff", "increment/decrement/jump/push/call rm32 based on subop (inc/dec/jmp/push/call)");
763
764 :(code)
765 void test_increment_rm32() {
766 Reg[EAX].u = 0x20;
767 run(
768 "== 0x1\n"
769
770 " ff c0 \n"
771
772 );
773 CHECK_TRACE_CONTENTS(
774 "run: increment r/m32\n"
775 "run: r/m32 is EAX\n"
776 "run: storing value 0x00000021\n"
777 );
778 }
779
780 :(before "End Single-Byte Opcodes")
781 case 0xff: {
782 const uint8_t modrm = next();
783 const uint8_t subop = (modrm>>3)&0x7;
784 switch (subop) {
785 case 0: {
786 trace(Callstack_depth+1, "run") << "increment r/m32" << end();
787 int32_t* arg = effective_address(modrm);
788 ++*arg;
789 trace(Callstack_depth+1, "run") << "storing value 0x" << HEXWORD << *arg << end();
790 break;
791 }
792 default:
793 cerr << "unrecognized subop for ff: " << HEXBYTE << NUM(subop) << '\n';
794 DUMP("");
795 exit(1);
796
797 }
798 break;
799 }
800
801
802
803 :(before "End Initialize Op Names")
804 put_new(Name, "48", "decrement EAX (dec)");
805 put_new(Name, "49", "decrement ECX (dec)");
806 put_new(Name, "4a", "decrement EDX (dec)");
807 put_new(Name, "4b", "decrement EBX (dec)");
808 put_new(Name, "4c", "decrement ESP (dec)");
809 put_new(Name, "4d", "decrement EBP (dec)");
810 put_new(Name, "4e", "decrement ESI (dec)");
811 put_new(Name, "4f", "decrement EDI (dec)");
812
813 :(code)
814 void test_decrement_r32() {
815 Reg[ECX].u = 0x1f;
816 run(
817 "== 0x1\n"
818
819 " 49 \n"
820 );
821 CHECK_TRACE_CONTENTS(
822 "run: decrement ECX\n"
823 "run: storing value 0x0000001e\n"
824 );
825 }
826
827 :(before "End Single-Byte Opcodes")
828 case 0x48:
829 case 0x49:
830 case 0x4a:
831 case 0x4b:
832 case 0x4c:
833 case 0x4d:
834 case 0x4e:
835 case 0x4f: {
836 const uint8_t reg = op & 0x7;
837 trace(Callstack_depth+1, "run") << "decrement " << rname(reg) << end();
838 --Reg[reg].u;
839 trace(Callstack_depth+1, "run") << "storing value 0x" << HEXWORD << Reg[reg].u << end();
840 break;
841 }
842
843 :(code)
844 void test_decrement_rm32() {
845 Reg[EAX].u = 0x20;
846 run(
847 "== 0x1\n"
848
849 " ff c8 \n"
850
851 );
852 CHECK_TRACE_CONTENTS(
853 "run: decrement r/m32\n"
854 "run: r/m32 is EAX\n"
855 "run: storing value 0x0000001f\n"
856 );
857 }
858
859 :(before "End Op ff Subops")
860 case 1: {
861 trace(Callstack_depth+1, "run") << "decrement r/m32" << end();
862 int32_t* arg = effective_address(modrm);
863 --*arg;
864 trace(Callstack_depth+1, "run") << "storing value 0x" << HEXWORD << *arg << end();
865 break;
866 }
867
868
869
870 :(before "End Initialize Op Names")
871 put_new(Name, "50", "push EAX to stack (push)");
872 put_new(Name, "51", "push ECX to stack (push)");
873 put_new(Name, "52", "push EDX to stack (push)");
874 put_new(Name, "53", "push EBX to stack (push)");
875 put_new(Name, "54", "push ESP to stack (push)");
876 put_new(Name, "55", "push EBP to stack (push)");
877 put_new(Name, "56", "push ESI to stack (push)");
878 put_new(Name, "57", "push EDI to stack (push)");
879
880 :(code)
881 void test_push_r32() {
882 Reg[ESP].u = 0x64;
883 Reg[EBX].i = 0x0000000a;
884 run(
885 "== 0x1\n"
886
887 " 53 \n"
888 );
889 CHECK_TRACE_CONTENTS(
890 "run: push EBX\n"
891 "run: decrementing ESP to 0x00000060\n"
892 "run: pushing value 0x0000000a\n"
893 );
894 }
895
896 :(before "End Single-Byte Opcodes")
897 case 0x50:
898 case 0x51:
899 case 0x52:
900 case 0x53:
901 case 0x54:
902 case 0x55:
903 case 0x56:
904 case 0x57: {
905 uint8_t reg = op & 0x7;
906 trace(Callstack_depth+1, "run") << "push " << rname(reg) << end();
907
908 push(Reg[reg].u);
909 break;
910 }
911
912
913
914 :(before "End Initialize Op Names")
915 put_new(Name, "58", "pop top of stack to EAX (pop)");
916 put_new(Name, "59", "pop top of stack to ECX (pop)");
917 put_new(Name, "5a", "pop top of stack to EDX (pop)");
918 put_new(Name, "5b", "pop top of stack to EBX (pop)");
919 put_new(Name, "5c", "pop top of stack to ESP (pop)");
920 put_new(Name, "5d", "pop top of stack to EBP (pop)");
921 put_new(Name, "5e", "pop top of stack to ESI (pop)");
922 put_new(Name, "5f", "pop top of stack to EDI (pop)");
923
924 :(code)
925 void test_pop_r32() {
926 Reg[ESP].u = 0x02000000;
927 Mem.push_back(vma(0x02000000));
928 write_mem_i32(0x02000000, 0x0000000a);
929 run(
930 "== 0x1\n"
931
932 " 5b \n"
933 "== 0x2000\n"
934 "0a 00 00 00\n"
935 );
936 CHECK_TRACE_CONTENTS(
937 "run: pop into EBX\n"
938 "run: popping value 0x0000000a\n"
939 "run: incrementing ESP to 0x02000004\n"
940 );
941 }
942
943 :(before "End Single-Byte Opcodes")
944 case 0x58:
945 case 0x59:
946 case 0x5a:
947 case 0x5b:
948 case 0x5c:
949 case 0x5d:
950 case 0x5e:
951 case 0x5f: {
952 const uint8_t reg = op & 0x7;
953 trace(Callstack_depth+1, "run") << "pop into " << rname(reg) << end();
954
955 Reg[reg].u = pop();
956
957 break;
958 }
959 :(code)
960 uint32_t pop() {
961 const uint32_t result = read_mem_u32(Reg[ESP].u);
962 trace(Callstack_depth+1, "run") << "popping value 0x" << HEXWORD << result << end();
963 Reg[ESP].u += 4;
964 trace(Callstack_depth+1, "run") << "incrementing ESP to 0x" << HEXWORD << Reg[ESP].u << end();
965 return result;
966 }