https://github.com/akkartik/mu/blob/main/014indirect_addressing.cc
1
2
3
4 void test_add_r32_to_mem_at_r32() {
5 Reg[EBX].i = 0x10;
6 Reg[EAX].i = 0x2000;
7 run(
8 "== code 0x1\n"
9
10 " 01 18 \n"
11
12 "== data 0x2000\n"
13 "01 00 00 00\n"
14 );
15 CHECK_TRACE_CONTENTS(
16 "run: add EBX to r/m32\n"
17 "run: effective address is 0x00002000 (EAX)\n"
18 "run: storing 0x00000011\n"
19 );
20 }
21
22 :(before "End Mod Special-cases(addr)")
23 case 0:
24 switch (rm) {
25 default:
26 trace(Callstack_depth+1, "run") << "effective address is 0x" << HEXWORD << Reg[rm].u << " (" << rname(rm) << ")" << end();
27 addr = Reg[rm].u;
28 break;
29
30 }
31 break;
32
33
34
35 :(before "End Initialize Op Names")
36 put_new(Name, "03", "add rm32 to r32 (add)");
37
38 :(code)
39 void test_add_mem_at_r32_to_r32() {
40 Reg[EAX].i = 0x2000;
41 Reg[EBX].i = 0x10;
42 run(
43 "== code 0x1\n"
44
45 " 03 18 \n"
46
47 "== data 0x2000\n"
48 "01 00 00 00\n"
49 );
50 CHECK_TRACE_CONTENTS(
51 "run: add r/m32 to EBX\n"
52 "run: effective address is 0x00002000 (EAX)\n"
53 "run: storing 0x00000011\n"
54 );
55 }
56
57 :(before "End Single-Byte Opcodes")
58 case 0x03: {
59 const uint8_t modrm = next();
60 const uint8_t arg1 = (modrm>>3)&0x7;
61 trace(Callstack_depth+1, "run") << "add r/m32 to " << rname(arg1) << end();
62 const int32_t* signed_arg2 = effective_address(modrm);
63 int32_t signed_result = Reg[arg1].i + *signed_arg2;
64 SF = (signed_result < 0);
65 ZF = (signed_result == 0);
66 int64_t signed_full_result = static_cast<int64_t>(Reg[arg1].i) + *signed_arg2;
67 OF = (signed_result != signed_full_result);
68
69 uint32_t unsigned_arg2 = static_cast<uint32_t>(*signed_arg2);
70 uint32_t unsigned_result = Reg[arg1].u + unsigned_arg2;
71 uint64_t unsigned_full_result = static_cast<uint64_t>(Reg[arg1].u) + unsigned_arg2;
72 CF = (unsigned_result != unsigned_full_result);
73 trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
74 Reg[arg1].i = signed_result;
75 trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[arg1].i << end();
76 break;
77 }
78
79 :(code)
80 void test_add_mem_at_r32_to_r32_signed_overflow() {
81 Reg[EAX].i = 0x2000;
82 Reg[EBX].i = 0x7fffffff;
83 run(
84 "== code 0x1\n"
85
86 " 03 18 \n"
87
88 "== data 0x2000\n"
89 "01 00 00 00\n"
90 );
91 CHECK_TRACE_CONTENTS(
92 "run: add r/m32 to EBX\n"
93 "run: effective address is 0x00002000 (EAX)\n"
94 "run: effective address contains 0x00000001\n"
95 "run: SF=1; ZF=0; CF=0; OF=1\n"
96 "run: storing 0x80000000\n"
97 );
98 }
99
100 void test_add_mem_at_r32_to_r32_unsigned_overflow() {
101 Reg[EAX].u = 0x2000;
102 Reg[EBX].u = 0xffffffff;
103 run(
104 "== code 0x1\n"
105
106 " 03 18 \n"
107
108 "== data 0x2000\n"
109 "01 00 00 00\n"
110 );
111 CHECK_TRACE_CONTENTS(
112 "run: add r/m32 to EBX\n"
113 "run: effective address is 0x00002000 (EAX)\n"
114 "run: effective address contains 0x00000001\n"
115 "run: SF=0; ZF=1; CF=1; OF=0\n"
116 "run: storing 0x00000000\n"
117 );
118 }
119
120 void test_add_mem_at_r32_to_r32_unsigned_and_signed_overflow() {
121 Reg[EAX].u = 0x2000;
122 Reg[EBX].u = 0x80000000;
123 run(
124 "== code 0x1\n"
125
126 " 03 18 \n"
127
128 "== data 0x2000\n"
129 "00 00 00 80\n"
130 );
131 CHECK_TRACE_CONTENTS(
132 "run: add r/m32 to EBX\n"
133 "run: effective address is 0x00002000 (EAX)\n"
134 "run: effective address contains 0x80000000\n"
135 "run: SF=0; ZF=1; CF=1; OF=1\n"
136 "run: storing 0x00000000\n"
137 );
138 }
139
140
141
142 :(code)
143 void test_subtract_r32_from_mem_at_r32() {
144 Reg[EAX].i = 0x2000;
145 Reg[EBX].i = 1;
146 run(
147 "== code 0x1\n"
148
149 " 29 18 \n"
150
151 "== data 0x2000\n"
152 "0a 00 00 00\n"
153 );
154 CHECK_TRACE_CONTENTS(
155 "run: subtract EBX from r/m32\n"
156 "run: effective address is 0x00002000 (EAX)\n"
157 "run: storing 0x00000009\n"
158 );
159 }
160
161
162
163 :(before "End Initialize Op Names")
164 put_new(Name, "2b", "subtract rm32 from r32 (sub)");
165
166 :(code)
167 void test_subtract_mem_at_r32_from_r32() {
168 Reg[EAX].i = 0x2000;
169 Reg[EBX].i = 10;
170 run(
171 "== code 0x1\n"
172
173 " 2b 18 \n"
174
175 "== data 0x2000\n"
176 "01 00 00 00\n"
177 );
178 CHECK_TRACE_CONTENTS(
179 "run: subtract r/m32 from EBX\n"
180 "run: effective address is 0x00002000 (EAX)\n"
181 "run: storing 0x00000009\n"
182 );
183 }
184
185 :(before "End Single-Byte Opcodes")
186 case 0x2b: {
187 const uint8_t modrm = next();
188 const uint8_t arg1 = (modrm>>3)&0x7;
189 trace(Callstack_depth+1, "run") << "subtract r/m32 from " << rname(arg1) << end();
190 const int32_t* signed_arg2 = effective_address(modrm);
191 const int32_t signed_result = Reg[arg1].i - *signed_arg2;
192 SF = (signed_result < 0);
193 ZF = (signed_result == 0);
194 int64_t signed_full_result = static_cast<int64_t>(Reg[arg1].i) - *signed_arg2;
195 OF = (signed_result != signed_full_result);
196
197 uint32_t unsigned_arg2 = static_cast<uint32_t>(*signed_arg2);
198 uint32_t unsigned_result = Reg[arg1].u - unsigned_arg2;
199 uint64_t unsigned_full_result = static_cast<uint64_t>(Reg[arg1].u) - unsigned_arg2;
200 CF = (unsigned_result != unsigned_full_result);
201 trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
202 Reg[arg1].i = signed_result;
203 trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[arg1].i << end();
204 break;
205 }
206
207 :(code)
208 void test_subtract_mem_at_r32_from_r32_signed_overflow() {
209 Reg[EAX].i = 0x2000;
210 Reg[EBX].i = 0x80000000;
211 run(
212 "== code 0x1\n"
213
214 " 2b 18 \n"
215
216 "== data 0x2000\n"
217 "ff ff ff 7f\n"
218 );
219 CHECK_TRACE_CONTENTS(
220 "run: subtract r/m32 from EBX\n"
221 "run: effective address is 0x00002000 (EAX)\n"
222 "run: effective address contains 0x7fffffff\n"
223 "run: SF=0; ZF=0; CF=0; OF=1\n"
224 "run: storing 0x00000001\n"
225 );
226 }
227
228 void test_subtract_mem_at_r32_from_r32_unsigned_overflow() {
229 Reg[EAX].i = 0x2000;
230 Reg[EBX].i = 0;
231 run(
232 "== code 0x1\n"
233
234 " 2b 18 \n"
235
236 "== data 0x2000\n"
237 "01 00 00 00\n"
238 );
239 CHECK_TRACE_CONTENTS(
240 "run: subtract r/m32 from EBX\n"
241 "run: effective address is 0x00002000 (EAX)\n"
242 "run: effective address contains 0x00000001\n"
243 "run: SF=1; ZF=0; CF=1; OF=0\n"
244 "run: storing 0xffffffff\n"
245 );
246 }
247
248 void test_subtract_mem_at_r32_from_r32_signed_and_unsigned_overflow() {
249 Reg[EAX].i = 0x2000;
250 Reg[EBX].i = 0;
251 run(
252 "== code 0x1\n"
253
254 " 2b 18 \n"
255
256 "== data 0x2000\n"
257 "00 00 00 80\n"
258 );
259 CHECK_TRACE_CONTENTS(
260 "run: subtract r/m32 from EBX\n"
261 "run: effective address is 0x00002000 (EAX)\n"
262 "run: effective address contains 0x80000000\n"
263 "run: SF=1; ZF=0; CF=1; OF=1\n"
264 "run: storing 0x80000000\n"
265 );
266 }
267
268
269 :(code)
270 void test_and_r32_with_mem_at_r32() {
271 Reg[EAX].i = 0x2000;
272 Reg[EBX].i = 0xff;
273 run(
274 "== code 0x1\n"
275
276 " 21 18 \n"
277
278 "== data 0x2000\n"
279 "0d 0c 0b 0a\n"
280 );
281 CHECK_TRACE_CONTENTS(
282 "run: and EBX with r/m32\n"
283 "run: effective address is 0x00002000 (EAX)\n"
284 "run: storing 0x0000000d\n"
285 );
286 }
287
288
289
290 :(before "End Initialize Op Names")
291 put_new(Name, "23", "r32 = bitwise AND of r32 with rm32 (and)");
292
293 :(code)
294 void test_and_mem_at_r32_with_r32() {
295 Reg[EAX].i = 0x2000;
296 Reg[EBX].i = 0x0a0b0c0d;
297 run(
298 "== code 0x1\n"
299
300 " 23 18 \n"
301
302 "== data 0x2000\n"
303 "ff 00 00 00\n"
304 );
305 CHECK_TRACE_CONTENTS(
306 "run: and r/m32 with EBX\n"
307 "run: effective address is 0x00002000 (EAX)\n"
308 "run: storing 0x0000000d\n"
309 );
310 }
311
312 :(before "End Single-Byte Opcodes")
313 case 0x23: {
314 const uint8_t modrm = next();
315 const uint8_t arg1 = (modrm>>3)&0x7;
316 trace(Callstack_depth+1, "run") << "and r/m32 with " << rname(arg1) << end();
317
318
319 const int32_t* signed_arg2 = effective_address(modrm);
320 Reg[arg1].i &= *signed_arg2;
321 trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[arg1].i << end();
322 SF = (Reg[arg1].i >> 31);
323 ZF = (Reg[arg1].i == 0);
324 CF = false;
325 OF = false;
326 trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
327 break;
328 }
329
330
331
332 :(code)
333 void test_or_r32_with_mem_at_r32() {
334 Reg[EAX].i = 0x2000;
335 Reg[EBX].i = 0xa0b0c0d0;
336 run(
337 "== code 0x1\n"
338
339 " 09 18 #\n"
340
341 "== data 0x2000\n"
342 "0d 0c 0b 0a\n"
343 );
344 CHECK_TRACE_CONTENTS(
345 "run: or EBX with r/m32\n"
346 "run: effective address is 0x00002000 (EAX)\n"
347 "run: storing 0xaabbccdd\n"
348 );
349 }
350
351
352
353 :(before "End Initialize Op Names")
354 put_new(Name, "0b", "r32 = bitwise OR of r32 with rm32 (or)");
355
356 :(code)
357 void test_or_mem_at_r32_with_r32() {
358 Reg[EAX].i = 0x2000;
359 Reg[EBX].i = 0xa0b0c0d0;
360 run(
361 "== code 0x1\n"
362
363 " 0b 18 \n"
364
365 "== data 0x2000\n"
366 "0d 0c 0b 0a\n"
367 );
368 CHECK_TRACE_CONTENTS(
369 "run: or r/m32 with EBX\n"
370 "run: effective address is 0x00002000 (EAX)\n"
371 "run: storing 0xaabbccdd\n"
372 );
373 }
374
375 :(before "End Single-Byte Opcodes")
376 case 0x0b: {
377 const uint8_t modrm = next();
378 const uint8_t arg1 = (modrm>>3)&0x7;
379 trace(Callstack_depth+1, "run") << "or r/m32 with " << rname(arg1) << end();
380
381
382 const int32_t* signed_arg2 = effective_address(modrm);
383 Reg[arg1].i |= *signed_arg2;
384 trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[arg1].i << end();
385 SF = (Reg[arg1].i >> 31);
386 ZF = (Reg[arg1].i == 0);
387 CF = false;
388 OF = false;
389 trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
390 break;
391 }
392
393
394
395 :(code)
396 void test_xor_r32_with_mem_at_r32() {
397 Reg[EAX].i = 0x2000;
398 Reg[EBX].i = 0xa0b0c0d0;
399 run(
400 "== code 0x1\n"
401
402 " 31 18 \n"
403 "== data 0x2000\n"
404 "0d 0c bb aa\n"
405 );
406 CHECK_TRACE_CONTENTS(
407 "run: xor EBX with r/m32\n"
408 "run: effective address is 0x00002000 (EAX)\n"
409 "run: storing 0x0a0bccdd\n"
410 );
411 }
412
413
414
415 :(before "End Initialize Op Names")
416 put_new(Name, "33", "r32 = bitwise XOR of r32 with rm32 (xor)");
417
418 :(code)
419 void test_xor_mem_at_r32_with_r32() {
420 Reg[EAX].i = 0x2000;
421 Reg[EBX].i = 0xa0b0c0d0;
422 run(
423 "== code 0x1\n"
424
425 " 33 18 \n"
426
427 "== data 0x2000\n"
428 "0d 0c 0b 0a\n"
429 );
430 CHECK_TRACE_CONTENTS(
431 "run: xor r/m32 with EBX\n"
432 "run: effective address is 0x00002000 (EAX)\n"
433 "run: storing 0xaabbccdd\n"
434 );
435 }
436
437 :(before "End Single-Byte Opcodes")
438 case 0x33: {
439 const uint8_t modrm = next();
440 const uint8_t arg1 = (modrm>>3)&0x7;
441 trace(Callstack_depth+1, "run") << "xor r/m32 with " << rname(arg1) << end();
442
443
444 const int32_t* signed_arg2 = effective_address(modrm);
445 Reg[arg1].i |= *signed_arg2;
446 trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[arg1].i << end();
447 SF = (Reg[arg1].i >> 31);
448 ZF = (Reg[arg1].i == 0);
449 CF = false;
450 OF = false;
451 trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
452 break;
453 }
454
455
456
457 :(code)
458 void test_not_of_mem_at_r32() {
459 Reg[EBX].i = 0x2000;
460 run(
461 "== code 0x1\n"
462
463 " f7 13 \n"
464
465 "== data 0x2000\n"
466 "ff 00 0f 0f\n"
467 );
468 CHECK_TRACE_CONTENTS(
469 "run: operate on r/m32\n"
470 "run: effective address is 0x00002000 (EBX)\n"
471 "run: subop: not\n"
472 "run: storing 0xf0f0ff00\n"
473 );
474 }
475
476
477
478 :(code)
479 void test_compare_mem_at_r32_with_r32_greater() {
480 Reg[EAX].i = 0x2000;
481 Reg[EBX].i = 0x0a0b0c07;
482 run(
483 "== code 0x1\n"
484
485 " 39 18 \n"
486
487 "== data 0x2000\n"
488 "0d 0c 0b 0a\n"
489 );
490 CHECK_TRACE_CONTENTS(
491 "run: compare r/m32 with EBX\n"
492 "run: effective address is 0x00002000 (EAX)\n"
493 "run: SF=0; ZF=0; CF=0; OF=0\n"
494 );
495 }
496
497 :(code)
498 void test_compare_mem_at_r32_with_r32_lesser() {
499 Reg[EAX].i = 0x2000;
500 Reg[EBX].i = 0x0a0b0c0d;
501 run(
502 "== code 0x1\n"
503
504 " 39 18 \n"
505
506 "== data 0x2000\n"
507 "07 0c 0b 0a\n"
508 );
509 CHECK_TRACE_CONTENTS(
510 "run: compare r/m32 with EBX\n"
511 "run: effective address is 0x00002000 (EAX)\n"
512 "run: SF=1; ZF=0; CF=1; OF=0\n"
513 );
514 }
515
516 :(code)
517 void test_compare_mem_at_r32_with_r32_equal() {
518 Reg[EAX].i = 0x2000;
519 Reg[EBX].i = 0x0a0b0c0d;
520 run(
521 "== code 0x1\n"
522
523 " 39 18 \n"
524
525 "== data 0x2000\n"
526 "0d 0c 0b 0a\n"
527 );
528 CHECK_TRACE_CONTENTS(
529 "run: compare r/m32 with EBX\n"
530 "run: effective address is 0x00002000 (EAX)\n"
531 "run: SF=0; ZF=1; CF=0; OF=0\n"
532 );
533 }
534
535
536
537 :(before "End Initialize Op Names")
538 put_new(Name, "3b", "compare: set SF if r32 < rm32 (cmp)");
539
540 :(code)
541 void test_compare_r32_with_mem_at_rm32_greater() {
542 Reg[EAX].i = 0x2000;
543 Reg[EBX].i = 0x0a0b0c0d;
544 run(
545 "== code 0x1\n"
546
547 " 3b 18 \n"
548
549 "== data 0x2000\n"
550 "07 0c 0b 0a\n"
551 );
552 CHECK_TRACE_CONTENTS(
553 "run: compare EBX with r/m32\n"
554 "run: effective address is 0x00002000 (EAX)\n"
555 "run: SF=0; ZF=0; CF=0; OF=0\n"
556 );
557 }
558
559 :(before "End Single-Byte Opcodes")
560 case 0x3b: {
561 const uint8_t modrm = next();
562 const uint8_t reg1 = (modrm>>3)&0x7;
563 trace(Callstack_depth+1, "run") << "compare " << rname(reg1) << " with r/m32" << end();
564 const int32_t* signed_arg2 = effective_address(modrm);
565 const int32_t signed_difference = Reg[reg1].i - *signed_arg2;
566 SF = (signed_difference < 0);
567 ZF = (signed_difference == 0);
568 int64_t full_signed_difference = static_cast<int64_t>(Reg[reg1].i) - *signed_arg2;
569 OF = (signed_difference != full_signed_difference);
570 const uint32_t unsigned_arg2 = static_cast<uint32_t>(*signed_arg2);
571 const uint32_t unsigned_difference = Reg[reg1].u - unsigned_arg2;
572 const uint64_t full_unsigned_difference = static_cast<uint64_t>(Reg[reg1].u) - unsigned_arg2;
573 CF = (unsigned_difference != full_unsigned_difference);
574 trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
575 break;
576 }
577
578 :(code)
579 void test_compare_r32_with_mem_at_rm32_lesser_unsigned_and_signed() {
580 Reg[EAX].i = 0x2000;
581 Reg[EBX].i = 0x0a0b0c07;
582 run(
583 "== code 0x1\n"
584
585 " 3b 18 \n"
586
587 "== data 0x2000\n"
588 "0d 0c 0b 0a\n"
589 );
590 CHECK_TRACE_CONTENTS(
591 "run: compare EBX with r/m32\n"
592 "run: effective address is 0x00002000 (EAX)\n"
593 "run: effective address contains 0x0a0b0c0d\n"
594 "run: SF=1; ZF=0; CF=1; OF=0\n"
595 );
596 }
597
598 void test_compare_r32_with_mem_at_rm32_lesser_unsigned_and_signed_due_to_overflow() {
599 Reg[EAX].i = 0x2000;
600 Reg[EBX].i = 0x7fffffff;
601 run(
602 "== code 0x1\n"
603
604 " 3b 18 \n"
605
606 "== data 0x2000\n"
607 "00 00 00 80\n"
608 );
609 CHECK_TRACE_CONTENTS(
610 "run: compare EBX with r/m32\n"
611 "run: effective address is 0x00002000 (EAX)\n"
612 "run: effective address contains 0x80000000\n"
613 "run: SF=1; ZF=0; CF=1; OF=1\n"
614 );
615 }
616
617 void test_compare_r32_with_mem_at_rm32_lesser_signed() {
618 Reg[EAX].i = 0x2000;
619 Reg[EBX].i = 0xffffffff;
620 run(
621 "== code 0x1\n"
622
623 " 3b 18 \n"
624
625 "== data 0x2000\n"
626 "01 00 00 00\n"
627 );
628 CHECK_TRACE_CONTENTS(
629 "run: compare EBX with r/m32\n"
630 "run: effective address is 0x00002000 (EAX)\n"
631 "run: effective address contains 0x00000001\n"
632 "run: SF=1; ZF=0; CF=0; OF=0\n"
633 );
634 }
635
636 void test_compare_r32_with_mem_at_rm32_lesser_unsigned() {
637 Reg[EAX].i = 0x2000;
638 Reg[EBX].i = 0x00000001;
639 run(
640 "== code 0x1\n"
641
642 " 3b 18 \n"
643
644 "== data 0x2000\n"
645 "ff ff ff ff\n"
646 );
647 CHECK_TRACE_CONTENTS(
648 "run: compare EBX with r/m32\n"
649 "run: effective address is 0x00002000 (EAX)\n"
650 "run: effective address contains 0xffffffff\n"
651 "run: SF=0; ZF=0; CF=1; OF=0\n"
652 );
653 }
654
655 void test_compare_r32_with_mem_at_rm32_equal() {
656 Reg[EAX].i = 0x2000;
657 Reg[EBX].i = 0x0a0b0c0d;
658 run(
659 "== code 0x1\n"
660
661 " 3b 18 \n"
662
663 "== data 0x2000\n"
664 "0d 0c 0b 0a\n"
665 );
666 CHECK_TRACE_CONTENTS(
667 "run: compare EBX with r/m32\n"
668 "run: effective address is 0x00002000 (EAX)\n"
669 "run: SF=0; ZF=1; CF=0; OF=0\n"
670 );
671 }
672
673
674
675 void test_copy_r32_to_mem_at_r32() {
676 Reg[EBX].i = 0xaf;
677 Reg[EAX].i = 0x60;
678 run(
679 "== code 0x1\n"
680
681 " 89 18 \n"
682
683 );
684 CHECK_TRACE_CONTENTS(
685 "run: copy EBX to r/m32\n"
686 "run: effective address is 0x00000060 (EAX)\n"
687 "run: storing 0x000000af\n"
688 );
689 }
690
691
692
693 :(before "End Initialize Op Names")
694 put_new(Name, "8b", "copy rm32 to r32 (mov)");
695
696 :(code)
697 void test_copy_mem_at_r32_to_r32() {
698 Reg[EAX].i = 0x2000;
699 run(
700 "== code 0x1\n"
701
702 " 8b 18 \n"
703 "== data 0x2000\n"
704 "af 00 00 00\n"
705 );
706 CHECK_TRACE_CONTENTS(
707 "run: copy r/m32 to EBX\n"
708 "run: effective address is 0x00002000 (EAX)\n"
709 "run: storing 0x000000af\n"
710 );
711 }
712
713 :(before "End Single-Byte Opcodes")
714 case 0x8b: {
715 const uint8_t modrm = next();
716 const uint8_t rdest = (modrm>>3)&0x7;
717 trace(Callstack_depth+1, "run") << "copy r/m32 to " << rname(rdest) << end();
718 const int32_t* src = effective_address(modrm);
719 Reg[rdest].i = *src;
720 trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *src << end();
721 break;
722 }
723
724
725
726 :(code)
727 void test_jump_mem_at_r32() {
728 Reg[EAX].i = 0x2000;
729 run(
730 "== code 0x1\n"
731
732 " ff 20 \n"
733
734 " b8 00 00 00 01\n"
735 " b8 00 00 00 02\n"
736 "== data 0x2000\n"
737 "08 00 00 00\n"
738 );
739 CHECK_TRACE_CONTENTS(
740 "run: 0x00000001 opcode: ff\n"
741 "run: jump to r/m32\n"
742 "run: effective address is 0x00002000 (EAX)\n"
743 "run: jumping to 0x00000008\n"
744 "run: 0x00000008 opcode: b8\n"
745 );
746 CHECK_TRACE_DOESNT_CONTAIN("run: 0x00000003 opcode: b8");
747 }
748
749 :(before "End Op ff Subops")
750 case 4: {
751 trace(Callstack_depth+1, "run") << "jump to r/m32" << end();
752 const int32_t* arg2 = effective_address(modrm);
753 EIP = *arg2;
754 trace(Callstack_depth+1, "run") << "jumping to 0x" << HEXWORD << EIP << end();
755 break;
756 }
757
758
759
760 :(code)
761 void test_push_mem_at_r32() {
762 Reg[EAX].i = 0x2000;
763 Mem.push_back(vma(0xbd000000));
764 Reg[ESP].u = 0xbd000014;
765 run(
766 "== code 0x1\n"
767
768 " ff 30 \n"
769 "== data 0x2000\n"
770 "af 00 00 00\n"
771 );
772 CHECK_TRACE_CONTENTS(
773 "run: push r/m32\n"
774 "run: effective address is 0x00002000 (EAX)\n"
775 "run: decrementing ESP to 0xbd000010\n"
776 "run: pushing value 0x000000af\n"
777 );
778 }
779
780 :(before "End Op ff Subops")
781 case 6: {
782 trace(Callstack_depth+1, "run") << "push r/m32" << end();
783 const int32_t* val = effective_address(modrm);
784 push(*val);
785 break;
786 }
787
788
789
790 :(before "End Initialize Op Names")
791 put_new(Name, "8f", "pop top of stack to rm32 (pop)");
792
793 :(code)
794 void test_pop_mem_at_r32() {
795 Reg[EAX].i = 0x60;
796 Mem.push_back(vma(0xbd000000));
797 Reg[ESP].u = 0xbd000000;
798 write_mem_i32(0xbd000000, 0x00000030);
799 run(
800 "== code 0x1\n"
801
802 " 8f 00 \n"
803
804 );
805 CHECK_TRACE_CONTENTS(
806 "run: pop into r/m32\n"
807 "run: effective address is 0x00000060 (EAX)\n"
808 "run: popping value 0x00000030\n"
809 "run: incrementing ESP to 0xbd000004\n"
810 );
811 }
812
813 :(before "End Single-Byte Opcodes")
814 case 0x8f: {
815 const uint8_t modrm = next();
816 const uint8_t subop = (modrm>>3)&0x7;
817 switch (subop) {
818 case 0: {
819 trace(Callstack_depth+1, "run") << "pop into r/m32" << end();
820 int32_t* dest = effective_address(modrm);
821 *dest = pop();
822 break;
823 }
824 }
825 break;
826 }
827
828
829
830 :(code)
831 void test_add_r32_to_mem_at_displacement() {
832 Reg[EBX].i = 0x10;
833 run(
834 "== code 0x1\n"
835
836 " 01 1d 00 20 00 00 \n"
837
838 "== data 0x2000\n"
839 "01 00 00 00\n"
840 );
841 CHECK_TRACE_CONTENTS(
842 "run: add EBX to r/m32\n"
843 "run: effective address is 0x00002000 (disp32)\n"
844 "run: storing 0x00000011\n"
845 );
846 }
847
848 :(before "End Mod 0 Special-cases(addr)")
849 case 5:
850 addr = next32();
851 trace(Callstack_depth+1, "run") << "effective address is 0x" << HEXWORD << addr << " (disp32)" << end();
852 break;
853
854
855
856 :(code)
857 void test_add_r32_to_mem_at_r32_plus_disp8() {
858 Reg[EBX].i = 0x10;
859 Reg[EAX].i = 0x1ffe;
860 run(
861 "== code 0x1\n"
862
863 " 01 58 02 \n"
864
865 "== data 0x2000\n"
866 "01 00 00 00\n"
867 );
868 CHECK_TRACE_CONTENTS(
869 "run: add EBX to r/m32\n"
870 "run: effective address is initially 0x00001ffe (EAX)\n"
871 "run: effective address is 0x00002000 (after adding disp8)\n"
872 "run: storing 0x00000011\n"
873 );
874 }
875
876 :(before "End Mod Special-cases(addr)")
877 case 1: {
878 switch (rm) {
879 default:
880 addr = Reg[rm].u;
881 trace(Callstack_depth+1, "run") << "effective address is initially 0x" << HEXWORD << addr << " (" << rname(rm) << ")" << end();
882 break;
883
884 }
885 int8_t displacement = static_cast<int8_t>(next());
886 if (addr > 0) {
887 addr += displacement;
888 trace(Callstack_depth+1, "run") << "effective address is 0x" << HEXWORD << addr << " (after adding disp8)" << end();
889 }
890 else {
891 trace(Callstack_depth+1, "run") << "null address; skipping displacement" << end();
892 }
893 break;
894 }
895
896 :(code)
897 void test_add_r32_to_mem_at_r32_plus_negative_disp8() {
898 Reg[EBX].i = 0x10;
899 Reg[EAX].i = 0x2001;
900 run(
901 "== code 0x1\n"
902
903 " 01 58 ff \n"
904
905 "== data 0x2000\n"
906 "01 00 00 00\n"
907 );
908 CHECK_TRACE_CONTENTS(
909 "run: add EBX to r/m32\n"
910 "run: effective address is initially 0x00002001 (EAX)\n"
911 "run: effective address is 0x00002000 (after adding disp8)\n"
912 "run: storing 0x00000011\n"
913 );
914 }
915
916
917
918 :(code)
919 void test_add_r32_to_mem_at_r32_plus_disp32() {
920 Reg[EBX].i = 0x10;
921 Reg[EAX].i = 0x1ffe;
922 run(
923 "== code 0x1\n"
924
925 " 01 98 02 00 00 00 \n"
926
927 "== data 0x2000\n"
928 "01 00 00 00\n"
929 );
930 CHECK_TRACE_CONTENTS(
931 "run: add EBX to r/m32\n"
932 "run: effective address is initially 0x00001ffe (EAX)\n"
933 "run: effective address is 0x00002000 (after adding disp32)\n"
934 "run: storing 0x00000011\n"
935 );
936 }
937
938 :(before "End Mod Special-cases(addr)")
939 case 2: {
940 switch (rm) {
941 default:
942 addr = Reg[rm].u;
943 trace(Callstack_depth+1, "run") << "effective address is initially 0x" << HEXWORD << addr << " (" << rname(rm) << ")" << end();
944 break;
945
946 }
947 int32_t displacement = static_cast<int32_t>(next32());
948 if (addr > 0) {
949 addr += displacement;
950 trace(Callstack_depth+1, "run") << "effective address is 0x" << HEXWORD << addr << " (after adding disp32)" << end();
951 }
952 else {
953 trace(Callstack_depth+1, "run") << "null address; skipping displacement" << end();
954 }
955 break;
956 }
957
958 :(code)
959 void test_add_r32_to_mem_at_r32_plus_negative_disp32() {
960 Reg[EBX].i = 0x10;
961 Reg[EAX].i = 0x2001;
962 run(
963 "== code 0x1\n"
964
965 " 01 98 ff ff ff ff \n"
966
967 "== data 0x2000\n"
968 "01 00 00 00\n"
969 );
970 CHECK_TRACE_CONTENTS(
971 "run: add EBX to r/m32\n"
972 "run: effective address is initially 0x00002001 (EAX)\n"
973 "run: effective address is 0x00002000 (after adding disp32)\n"
974 "run: storing 0x00000011\n"
975 );
976 }
977
978
979
980 :(before "End Initialize Op Names")
981 put_new(Name, "8d", "copy address in rm32 into r32 (lea)");
982
983 :(code)
984 void test_copy_address() {
985 Reg[EAX].u = 0x2000;
986 run(
987 "== code 0x1\n"
988
989 " 8d 18 \n"
990
991 );
992 CHECK_TRACE_CONTENTS(
993 "run: copy address into EBX\n"
994 "run: effective address is 0x00002000 (EAX)\n"
995 );
996 }
997
998 :(before "End Single-Byte Opcodes")
999 case 0x8d: {
1000 const uint8_t modrm = next();
1001 const uint8_t arg1 = (modrm>>3)&0x7;
1002 trace(Callstack_depth+1, "run") << "copy address into " << rname(arg1) << end();
1003 Reg[arg1].u = effective_address_number(modrm);
1004 break;
1005 }