1
2
3
4 :(scenario add_r32_to_mem_at_r32)
5 % Reg[EBX].i = 0x10;
6 % Reg[EAX].i = 0x60;
7 == 0x1
8
9 01 18
10
11 == 0x60
12 01 00 00 00
13 +run: add EBX to r/m32
14 +run: effective address is 0x60 (EAX)
15 +run: storing 0x00000011
16
17 :(before "End Mod Special-cases(addr)")
18 case 0:
19 switch (rm) {
20 default:
21 trace(90, "run") << "effective address is 0x" << std::hex << Reg[rm].u << " (" << rname(rm) << ")" << end();
22 addr = Reg[rm].u;
23 break;
24
25 }
26 break;
27
28
29
30 :(before "End Initialize Op Names(name)")
31 put(name, "03", "add rm32 to r32");
32
33 :(scenario add_mem_at_r32_to_r32)
34 % Reg[EAX].i = 0x60;
35 % Reg[EBX].i = 0x10;
36 == 0x1
37
38 03 18
39
40 == 0x60
41 01 00 00 00
42 +run: add r/m32 to EBX
43 +run: effective address is 0x60 (EAX)
44 +run: storing 0x00000011
45
46 :(before "End Single-Byte Opcodes")
47 case 0x03: {
48 uint8_t modrm = next();
49 uint8_t arg1 = (modrm>>3)&0x7;
50 trace(90, "run") << "add r/m32 to " << rname(arg1) << end();
51 const int32_t* arg2 = effective_address(modrm);
52 BINARY_ARITHMETIC_OP(+, Reg[arg1].i, *arg2);
53 break;
54 }
55
56
57
58 :(scenario subtract_r32_from_mem_at_r32)
59 % Reg[EAX].i = 0x60;
60 % Reg[EBX].i = 1;
61 == 0x1
62
63 29 18
64
65 == 0x60
66 0a 00 00 00
67 +run: subtract EBX from r/m32
68 +run: effective address is 0x60 (EAX)
69 +run: storing 0x00000009
70
71
72
73 :(before "End Initialize Op Names(name)")
74 put(name, "2b", "subtract rm32 from r32");
75
76 :(scenario subtract_mem_at_r32_from_r32)
77 % Reg[EAX].i = 0x60;
78 % Reg[EBX].i = 10;
79 == 0x1
80
81 2b 18
82
83 == 0x60
84 01 00 00 00
85 +run: subtract r/m32 from EBX
86 +run: effective address is 0x60 (EAX)
87 +run: storing 0x00000009
88
89 :(before "End Single-Byte Opcodes")
90 case 0x2b: {
91 uint8_t modrm = next();
92 uint8_t arg1 = (modrm>>3)&0x7;
93 trace(90, "run") << "subtract r/m32 from " << rname(arg1) << end();
94 const int32_t* arg2 = effective_address(modrm);
95 BINARY_ARITHMETIC_OP(-, Reg[arg1].i, *arg2);
96 break;
97 }
98
99
100
101 :(scenario and_r32_with_mem_at_r32)
102 % Reg[EAX].i = 0x60;
103 % Reg[EBX].i = 0xff;
104 == 0x1
105
106 21 18
107
108 == 0x60
109 0d 0c 0b 0a
110 +run: and EBX with r/m32
111 +run: effective address is 0x60 (EAX)
112 +run: storing 0x0000000d
113
114
115
116 :(before "End Initialize Op Names(name)")
117 put(name, "23", "r32 = bitwise AND of r32 with rm32");
118
119 :(scenario and_mem_at_r32_with_r32)
120 % Reg[EAX].i = 0x60;
121 % Reg[EBX].i = 0x0a0b0c0d;
122 == 0x1
123
124 23 18
125
126 == 0x60
127 ff 00 00 00
128 +run: and r/m32 with EBX
129 +run: effective address is 0x60 (EAX)
130 +run: storing 0x0000000d
131
132 :(before "End Single-Byte Opcodes")
133 case 0x23: {
134 uint8_t modrm = next();
135 uint8_t arg1 = (modrm>>3)&0x7;
136 trace(90, "run") << "and r/m32 with " << rname(arg1) << end();
137 const int32_t* arg2 = effective_address(modrm);
138 BINARY_BITWISE_OP(&, Reg[arg1].u, *arg2);
139 break;
140 }
141
142
143
144 :(scenario or_r32_with_mem_at_r32)
145 % Reg[EAX].i = 0x60;
146 % Reg[EBX].i = 0xa0b0c0d0;
147 == 0x1
148
149 09 18
150
151 == 0x60
152 0d 0c 0b 0a
153 +run: or EBX with r/m32
154 +run: effective address is 0x60 (EAX)
155 +run: storing 0xaabbccdd
156
157
158
159 :(before "End Initialize Op Names(name)")
160 put(name, "0b", "r32 = bitwise OR of r32 with rm32");
161
162 :(scenario or_mem_at_r32_with_r32)
163 % Reg[EAX].i = 0x60;
164 % Reg[EBX].i = 0xa0b0c0d0;
165 == 0x1
166
167 0b 18
168
169 == 0x60
170 0d 0c 0b 0a
171 +run: or r/m32 with EBX
172 +run: effective address is 0x60 (EAX)
173 +run: storing 0xaabbccdd
174
175 :(before "End Single-Byte Opcodes")
176 case 0x0b: {
177 uint8_t modrm = next();
178 uint8_t arg1 = (modrm>>3)&0x7;
179 trace(90, "run") << "or r/m32 with " << rname(arg1) << end();
180 const int32_t* arg2 = effective_address(modrm);
181 BINARY_BITWISE_OP(|, Reg[arg1].u, *arg2);
182 break;
183 }
184
185
186
187 :(scenario xor_r32_with_mem_at_r32)
188 % Reg[EAX].i = 0x60;
189 % Reg[EBX].i = 0xa0b0c0d0;
190 == 0x1
191
192 31 18
193
194 == 0x60
195 0d 0c bb aa
196 +run: xor EBX with r/m32
197 +run: effective address is 0x60 (EAX)
198 +run: storing 0x0a0bccdd
199
200
201
202 :(before "End Initialize Op Names(name)")
203 put(name, "33", "r32 = bitwise XOR of r32 with rm32");
204
205 :(scenario xor_mem_at_r32_with_r32)
206 % Reg[EAX].i = 0x60;
207 % Reg[EBX].i = 0xa0b0c0d0;
208 == 0x1
209
210 33 18
211
212 == 0x60
213 0d 0c 0b 0a
214 +run: xor r/m32 with EBX
215 +run: effective address is 0x60 (EAX)
216 +run: storing 0xaabbccdd
217
218 :(before "End Single-Byte Opcodes")
219 case 0x33: {
220 uint8_t modrm = next();
221 uint8_t arg1 = (modrm>>3)&0x7;
222 trace(90, "run") << "xor r/m32 with " << rname(arg1) << end();
223 const int32_t* arg2 = effective_address(modrm);
224 BINARY_BITWISE_OP(|, Reg[arg1].u, *arg2);
225 break;
226 }
227
228
229
230 :(scenario not_of_mem_at_r32)
231 % Reg[EBX].i = 0x60;
232 == 0x1
233
234 f7 13
235
236 == 0x60
237 ff 00 0f 0f
238 +run: operate on r/m32
239 +run: effective address is 0x60 (EBX)
240 +run: subop: not
241 +run: storing 0xf0f0ff00
242
243
244
245 :(scenario compare_mem_at_r32_with_r32_greater)
246 % Reg[EAX].i = 0x60;
247 % Reg[EBX].i = 0x0a0b0c07;
248 == 0x1
249
250 39 18
251
252 == 0x60
253 0d 0c 0b 0a
254 +run: compare EBX with r/m32
255 +run: effective address is 0x60 (EAX)
256 +run: SF=0; ZF=0; OF=0
257
258 :(scenario compare_mem_at_r32_with_r32_lesser)
259 % Reg[EAX].i = 0x60;
260 % Reg[EBX].i = 0x0a0b0c0d;
261 == 0x1
262
263 39 18
264
265 == 0x60
266 07 0c 0b 0a
267 +run: compare EBX with r/m32
268 +run: effective address is 0x60 (EAX)
269 +run: SF=1; ZF=0; OF=0
270
271 :(scenario compare_mem_at_r32_with_r32_equal)
272 % Reg[EAX].i = 0x60;
273 % Reg[EBX].i = 0x0a0b0c0d;
274 == 0x1
275
276 39 18
277
278 == 0x60
279 0d 0c 0b 0a
280 +run: compare EBX with r/m32
281 +run: effective address is 0x60 (EAX)
282 +run: SF=0; ZF=1; OF=0
283
284
285
286 :(before "End Initialize Op Names(name)")
287 put(name, "3b", "compare: set SF if r32 < rm32");
288
289 :(scenario compare_r32_with_mem_at_r32_greater)
290 % Reg[EAX].i = 0x60;
291 % Reg[EBX].i = 0x0a0b0c0d;
292 == 0x1
293
294 3b 18
295
296 == 0x60
297 07 0c 0b 0a
298 +run: compare r/m32 with EBX
299 +run: effective address is 0x60 (EAX)
300 +run: SF=0; ZF=0; OF=0
301
302 :(before "End Single-Byte Opcodes")
303 case 0x3b: {
304 uint8_t modrm = next();
305 uint8_t reg1 = (modrm>>3)&0x7;
306 trace(90, "run") << "compare r/m32 with " << rname(reg1) << end();
307 int32_t arg1 = Reg[reg1].i;
308 int32_t* arg2 = effective_address(modrm);
309 int32_t tmp1 = arg1 - *arg2;
310 SF = (tmp1 < 0);
311 ZF = (tmp1 == 0);
312 int64_t tmp2 = arg1 - *arg2;
313 OF = (tmp1 != tmp2);
314 trace(90, "run") << "SF=" << SF << "; ZF=" << ZF << "; OF=" << OF << end();
315 break;
316 }
317
318 :(scenario compare_r32_with_mem_at_r32_lesser)
319 % Reg[EAX].i = 0x60;
320 % Reg[EBX].i = 0x0a0b0c07;
321 == 0x1
322
323 3b 18
324
325 == 0x60
326 0d 0c 0b 0a
327 +run: compare r/m32 with EBX
328 +run: effective address is 0x60 (EAX)
329 +run: SF=1; ZF=0; OF=0
330
331 :(scenario compare_r32_with_mem_at_r32_equal)
332 % Reg[EAX].i = 0x60;
333 % Reg[EBX].i = 0x0a0b0c0d;
334 == 0x1
335
336 3b 18
337
338 == 0x60
339 0d 0c 0b 0a
340 +run: compare r/m32 with EBX
341 +run: effective address is 0x60 (EAX)
342 +run: SF=0; ZF=1; OF=0
343
344
345
346 :(scenario copy_r32_to_mem_at_r32)
347 % Reg[EBX].i = 0xaf;
348 % Reg[EAX].i = 0x60;
349 == 0x1
350
351 89 18
352
353 +run: copy EBX to r/m32
354 +run: effective address is 0x60 (EAX)
355 +run: storing 0x000000af
356
357
358
359 :(before "End Initialize Op Names(name)")
360 put(name, "8b", "copy rm32 to r32");
361
362 :(scenario copy_mem_at_r32_to_r32)
363 % Reg[EAX].i = 0x60;
364 == 0x1
365
366 8b 18
367
368 == 0x60
369 af 00 00 00
370 +run: copy r/m32 to EBX
371 +run: effective address is 0x60 (EAX)
372 +run: storing 0x000000af
373
374 :(before "End Single-Byte Opcodes")
375 case 0x8b: {
376 uint8_t modrm = next();
377 uint8_t reg1 = (modrm>>3)&0x7;
378 trace(90, "run") << "copy r/m32 to " << rname(reg1) << end();
379 int32_t* arg2 = effective_address(modrm);
380 Reg[reg1].i = *arg2;
381 trace(90, "run") << "storing 0x" << HEXWORD << *arg2 << end();
382 break;
383 }
384
385
386
387 :(before "End Initialize Op Names(name)")
388 put(name, "88", "copy r8 (lowermost byte of r32) to r8/m8-at-r32");
389
390 :(scenario copy_r8_to_mem_at_r32)
391 % Reg[EBX].i = 0x224488ab;
392 % Reg[EAX].i = 0x60;
393 == 0x1
394
395 88 18
396
397 == 0x60
398 f0 cc bb aa
399 +run: copy lowermost byte of EBX to r8/m8-at-r32
400 +run: effective address is 0x60 (EAX)
401 +run: storing 0xab
402 % CHECK_EQ(0xaabbccab, read_mem_u32(0x60));
403
404 :(before "End Single-Byte Opcodes")
405 case 0x88: {
406 uint8_t modrm = next();
407 uint8_t reg2 = (modrm>>3)&0x7;
408 trace(90, "run") << "copy lowermost byte of " << rname(reg2) << " to r8/m8-at-r32" << end();
409
410 uint8_t* arg1 = reinterpret_cast<uint8_t*>(effective_address(modrm));
411 *arg1 = Reg[reg2].u;
412 trace(90, "run") << "storing 0x" << HEXBYTE << NUM(*arg1) << end();
413 break;
414 }
415
416
417
418 :(before "End Initialize Op Names(name)")
419 put(name, "8a", "copy r8/m8-at-r32 to r8 (lowermost byte of r32)");
420
421 :(scenario copy_mem_at_r32_to_r8)
422 % Reg[EBX].i = 0xaabbcc0f; // one nibble each of lowest byte set to all 0s and all 1s, to maximize value of this test
423 % Reg[EAX].i = 0x60;
424 == 0x1
425
426 8a 18
427
428 == 0x60
429 ab ff ff ff
430 +run: copy r8/m8-at-r32 to lowermost byte of EBX
431 +run: effective address is 0x60 (EAX)
432 +run: storing 0xab
433
434 +run: EBX now contains 0xaabbccab
435
436 :(before "End Single-Byte Opcodes")
437 case 0x8a: {
438 uint8_t modrm = next();
439 uint8_t reg1 = (modrm>>3)&0x7;
440 trace(90, "run") << "copy r8/m8-at-r32 to lowermost byte of " << rname(reg1) << end();
441
442 uint8_t* arg2 = reinterpret_cast<uint8_t*>(effective_address(modrm));
443 trace(90, "run") << "storing 0x" << HEXBYTE << NUM(*arg2) << end();
444 *reinterpret_cast<uint8_t*>(&Reg[reg1].u) = *arg2;
445 trace(90, "run") << rname(reg1) << " now contains 0x" << HEXWORD << Reg[reg1].u << end();
446 break;
447 }
448
449
450
451 :(scenario jump_mem_at_r32)
452 % Reg[EAX].i = 0x60;
453 == 0x1
454
455 ff 20
456
457 05 00 00 00 01
458 05 00 00 00 02
459 == 0x60
460 08 00 00 00
461 +run: inst: 0x00000001
462 +run: jump to r/m32
463 +run: effective address is 0x60 (EAX)
464 +run: jumping to 0x00000008
465 +run: inst: 0x00000008
466 -run: inst: 0x00000003
467
468 :(before "End Op ff Subops")
469 case 4: {
470 trace(90, "run") << "jump to r/m32" << end();
471 int32_t* arg2 = effective_address(modrm);
472 EIP = *arg2;
473 trace(90, "run") << "jumping to 0x" << HEXWORD << EIP << end();
474 break;
475 }
476
477
478
479 :(scenario push_mem_at_r32)
480 % Reg[EAX].i = 0x60;
481 % Reg[ESP].u = 0x14;
482 == 0x1
483
484 ff 30
485
486 == 0x60
487 af 00 00 00
488 +run: push r/m32
489 +run: effective address is 0x60 (EAX)
490 +run: decrementing ESP to 0x00000010
491 +run: pushing value 0x000000af
492
493 :(before "End Op ff Subops")
494 case 6: {
495 trace(90, "run") << "push r/m32" << end();
496 const int32_t* val = effective_address(modrm);
497 push(*val);
498 break;
499 }
500
501
502
503 :(before "End Initialize Op Names(name)")
504 put(name, "8f", "pop top of stack to rm32");
505
506 :(scenario pop_mem_at_r32)
507 % Reg[EAX].i = 0x60;
508 % Reg[ESP].u = 0x10;
509 == 0x1
510
511 8f 00
512
513 == 0x10
514 30 00 00 00
515 +run: pop into r/m32
516 +run: effective address is 0x60 (EAX)
517 +run: popping value 0x00000030
518 +run: incrementing ESP to 0x00000014
519
520 :(before "End Single-Byte Opcodes")
521 case 0x8f: {
522 uint8_t modrm = next();
523 uint8_t subop = (modrm>>3)&0x7;
524 switch (subop) {
525 case 0: {
526 trace(90, "run") << "pop into r/m32" << end();
527 int32_t* dest = effective_address(modrm);
528 *dest = pop();
529 break;
530 }
531 }
532 break;
533 }
534
535
536
537 :(scenario add_r32_to_mem_at_displacement)
538 % Reg[EBX].i = 0x10; // source
539 == 0x1
540
541 01 1d 60 00 00 00
542
543 == 0x60
544 01 00 00 00
545 +run: add EBX to r/m32
546 +run: effective address is 0x60 (disp32)
547 +run: storing 0x00000011
548
549 :(before "End Mod 0 Special-cases(addr)")
550 case 5:
551 addr = next32();
552 trace(90, "run") << "effective address is 0x" << std::hex << addr << " (disp32)" << end();
553 break;
554
555
556
557 :(scenario add_r32_to_mem_at_r32_plus_disp8)
558 % Reg[EBX].i = 0x10; // source
559 % Reg[EAX].i = 0x5e; // dest
560 == 0x1
561
562 01 58 02
563
564 == 0x60
565 01 00 00 00
566 +run: add EBX to r/m32
567 +run: effective address is initially 0x5e (EAX)
568 +run: effective address is 0x60 (after adding disp8)
569 +run: storing 0x00000011
570
571 :(before "End Mod Special-cases(addr)")
572 case 1:
573 switch (rm) {
574 default:
575 addr = Reg[rm].u;
576 trace(90, "run") << "effective address is initially 0x" << std::hex << addr << " (" << rname(rm) << ")" << end();
577 break;
578
579 }
580 if (addr > 0) {
581 addr += static_cast<int8_t>(next());
582 trace(90, "run") << "effective address is 0x" << std::hex << addr << " (after adding disp8)" << end();
583 }
584 break;
585
586 :(scenario add_r32_to_mem_at_r32_plus_negative_disp8)
587 % Reg[EBX].i = 0x10; // source
588 % Reg[EAX].i = 0x61; // dest
589 == 0x1
590
591 01 58 ff
592
593 == 0x60
594 01 00 00 00
595 +run: add EBX to r/m32
596 +run: effective address is initially 0x61 (EAX)
597 +run: effective address is 0x60 (after adding disp8)
598 +run: storing 0x00000011
599
600
601
602 :(scenario add_r32_to_mem_at_r32_plus_disp32)
603 % Reg[EBX].i = 0x10; // source
604 % Reg[EAX].i = 0x5e; // dest
605 == 0x1
606
607 01 98 02 00 00 00
608
609 == 0x60
610 01 00 00 00
611 +run: add EBX to r/m32
612 +run: effective address is initially 0x5e (EAX)
613 +run: effective address is 0x60 (after adding disp32)
614 +run: storing 0x00000011
615
616 :(before "End Mod Special-cases(addr)")
617 case 2:
618 switch (rm) {
619 default:
620 addr = Reg[rm].u;
621 trace(90, "run") << "effective address is initially 0x" << std::hex << addr << " (" << rname(rm) << ")" << end();
622 break;
623
624 }
625 if (addr > 0) {
626 addr += next32();
627 trace(90, "run") << "effective address is 0x" << std::hex << addr << " (after adding disp32)" << end();
628 }
629 break;
630
631 :(scenario add_r32_to_mem_at_r32_plus_negative_disp32)
632 % Reg[EBX].i = 0x10; // source
633 % Reg[EAX].i = 0x61; // dest
634 == 0x1
635
636 01 98 ff ff ff ff
637
638 == 0x60
639 01 00 00 00
640 +run: add EBX to r/m32
641 +run: effective address is initially 0x61 (EAX)
642 +run: effective address is 0x60 (after adding disp32)
643 +run: storing 0x00000011