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_r32_with_mem_at_r32)
231 % Reg[EBX].i = 0x60;
232 == 0x1
233
234 f7 03
235
236 == 0x60
237 ff 00 0f 0f
238 +run: 'not' of r/m32
239 +run: effective address is 0x60 (EBX)
240 +run: storing 0xf0f0ff00
241
242
243
244 :(scenario compare_mem_at_r32_with_r32_greater)
245 % Reg[EAX].i = 0x60;
246 % Reg[EBX].i = 0x0a0b0c07;
247 == 0x1
248
249 39 18
250
251 == 0x60
252 0d 0c 0b 0a
253 +run: compare EBX with r/m32
254 +run: effective address is 0x60 (EAX)
255 +run: SF=0; ZF=0; OF=0
256
257 :(scenario compare_mem_at_r32_with_r32_lesser)
258 % Reg[EAX].i = 0x60;
259 % Reg[EBX].i = 0x0a0b0c0d;
260 == 0x1
261
262 39 18
263
264 == 0x60
265 07 0c 0b 0a
266 +run: compare EBX with r/m32
267 +run: effective address is 0x60 (EAX)
268 +run: SF=1; ZF=0; OF=0
269
270 :(scenario compare_mem_at_r32_with_r32_equal)
271 % Reg[EAX].i = 0x60;
272 % Reg[EBX].i = 0x0a0b0c0d;
273 == 0x1
274
275 39 18
276
277 == 0x60
278 0d 0c 0b 0a
279 +run: compare EBX with r/m32
280 +run: effective address is 0x60 (EAX)
281 +run: SF=0; ZF=1; OF=0
282
283
284
285 :(before "End Initialize Op Names(name)")
286 put(name, "3b", "set SF if rm32 > r32");
287
288 :(scenario compare_r32_with_mem_at_r32_greater)
289 % Reg[EAX].i = 0x60;
290 % Reg[EBX].i = 0x0a0b0c0d;
291 == 0x1
292
293 3b 18
294
295 == 0x60
296 07 0c 0b 0a
297 +run: compare r/m32 with EBX
298 +run: effective address is 0x60 (EAX)
299 +run: SF=0; ZF=0; OF=0
300
301 :(before "End Single-Byte Opcodes")
302 case 0x3b: {
303 uint8_t modrm = next();
304 uint8_t reg1 = (modrm>>3)&0x7;
305 trace(90, "run") << "compare r/m32 with " << rname(reg1) << end();
306 int32_t arg1 = Reg[reg1].i;
307 int32_t* arg2 = effective_address(modrm);
308 int32_t tmp1 = arg1 - *arg2;
309 SF = (tmp1 < 0);
310 ZF = (tmp1 == 0);
311 int64_t tmp2 = arg1 - *arg2;
312 OF = (tmp1 != tmp2);
313 trace(90, "run") << "SF=" << SF << "; ZF=" << ZF << "; OF=" << OF << end();
314 break;
315 }
316
317 :(scenario compare_r32_with_mem_at_r32_lesser)
318 % Reg[EAX].i = 0x60;
319 % Reg[EBX].i = 0x0a0b0c07;
320 == 0x1
321
322 3b 18
323
324 == 0x60
325 0d 0c 0b 0a
326 +run: compare r/m32 with EBX
327 +run: effective address is 0x60 (EAX)
328 +run: SF=1; ZF=0; OF=0
329
330 :(scenario compare_r32_with_mem_at_r32_equal)
331 % Reg[EAX].i = 0x60;
332 % Reg[EBX].i = 0x0a0b0c0d;
333 == 0x1
334
335 3b 18
336
337 == 0x60
338 0d 0c 0b 0a
339 +run: compare r/m32 with EBX
340 +run: effective address is 0x60 (EAX)
341 +run: SF=0; ZF=1; OF=0
342
343
344
345 :(scenario copy_r32_to_mem_at_r32)
346 % Reg[EBX].i = 0xaf;
347 % Reg[EAX].i = 0x60;
348 == 0x1
349
350 89 18
351
352 +run: copy EBX to r/m32
353 +run: effective address is 0x60 (EAX)
354 +run: storing 0x000000af
355
356
357
358 :(before "End Initialize Op Names(name)")
359 put(name, "8b", "copy rm32 to r32");
360
361 :(scenario copy_mem_at_r32_to_r32)
362 % Reg[EAX].i = 0x60;
363 == 0x1
364
365 8b 18
366
367 == 0x60
368 af 00 00 00
369 +run: copy r/m32 to EBX
370 +run: effective address is 0x60 (EAX)
371 +run: storing 0x000000af
372
373 :(before "End Single-Byte Opcodes")
374 case 0x8b: {
375 uint8_t modrm = next();
376 uint8_t reg1 = (modrm>>3)&0x7;
377 trace(90, "run") << "copy r/m32 to " << rname(reg1) << end();
378 int32_t* arg2 = effective_address(modrm);
379 Reg[reg1].i = *arg2;
380 trace(90, "run") << "storing 0x" << HEXWORD << *arg2 << end();
381 break;
382 }
383
384
385
386 :(before "End Initialize Op Names(name)")
387 put(name, "ff", "jump/push/call rm32 based on subop");
388
389 :(scenario jump_mem_at_r32)
390 % Reg[EAX].i = 0x60;
391 == 0x1
392
393 ff 20
394
395 05 00 00 00 01
396 05 00 00 00 02
397 == 0x60
398 08 00 00 00
399 +run: inst: 0x00000001
400 +run: jump to r/m32
401 +run: effective address is 0x60 (EAX)
402 +run: jumping to 0x00000008
403 +run: inst: 0x00000008
404 -run: inst: 0x00000003
405
406 :(before "End Single-Byte Opcodes")
407 case 0xff: {
408 uint8_t modrm = next();
409 uint8_t subop = (modrm>>3)&0x7;
410 switch (subop) {
411 case 4: {
412 trace(90, "run") << "jump to r/m32" << end();
413 int32_t* arg2 = effective_address(modrm);
414 EIP = *arg2;
415 trace(90, "run") << "jumping to 0x" << HEXWORD << EIP << end();
416 break;
417 }
418
419 }
420 break;
421 }
422
423
424
425 :(scenario push_mem_at_r32)
426 % Reg[EAX].i = 0x60;
427 % Reg[ESP].u = 0x14;
428 == 0x1
429
430 ff 30
431
432 == 0x60
433 af 00 00 00
434 +run: push r/m32
435 +run: effective address is 0x60 (EAX)
436 +run: decrementing ESP to 0x00000010
437 +run: pushing value 0x000000af
438
439 :(before "End Op ff Subops")
440 case 6: {
441 trace(90, "run") << "push r/m32" << end();
442 const int32_t* val = effective_address(modrm);
443 push(*val);
444 break;
445 }
446
447
448
449 :(before "End Initialize Op Names(name)")
450 put(name, "8f", "pop top of stack to rm32");
451
452 :(scenario pop_mem_at_r32)
453 % Reg[EAX].i = 0x60;
454 % Reg[ESP].u = 0x10;
455 == 0x1
456
457 8f 00
458
459 == 0x10
460 30 00 00 00
461 +run: pop into r/m32
462 +run: effective address is 0x60 (EAX)
463 +run: popping value 0x00000030
464 +run: incrementing ESP to 0x00000014
465
466 :(before "End Single-Byte Opcodes")
467 case 0x8f: {
468 uint8_t modrm = next();
469 uint8_t subop = (modrm>>3)&0x7;
470 switch (subop) {
471 case 0: {
472 trace(90, "run") << "pop into r/m32" << end();
473 int32_t* dest = effective_address(modrm);
474 *dest = pop();
475 break;
476 }
477 }
478 break;
479 }
480
481
482
483 :(scenario add_r32_to_mem_at_displacement)
484 % Reg[EBX].i = 0x10; // source
485 == 0x1
486
487 01 1d 60 00 00 00
488
489 == 0x60
490 01 00 00 00
491 +run: add EBX to r/m32
492 +run: effective address is 0x60 (disp32)
493 +run: storing 0x00000011
494
495 :(before "End Mod 0 Special-cases(addr)")
496 case 5:
497 addr = imm32();
498 trace(90, "run") << "effective address is 0x" << std::hex << addr << " (disp32)" << end();
499 break;
500
501
502
503 :(scenario add_r32_to_mem_at_r32_plus_disp8)
504 % Reg[EBX].i = 0x10; // source
505 % Reg[EAX].i = 0x5e; // dest
506 == 0x1
507
508 01 58 02
509
510 == 0x60
511 01 00 00 00
512 +run: add EBX to r/m32
513 +run: effective address is initially 0x5e (EAX)
514 +run: effective address is 0x60 (after adding disp8)
515 +run: storing 0x00000011
516
517 :(before "End Mod Special-cases(addr)")
518 case 1:
519 switch (rm) {
520 default:
521 addr = Reg[rm].u;
522 trace(90, "run") << "effective address is initially 0x" << std::hex << addr << " (" << rname(rm) << ")" << end();
523 break;
524
525 }
526 if (addr > 0) {
527 addr += static_cast<int8_t>(next());
528 trace(90, "run") << "effective address is 0x" << std::hex << addr << " (after adding disp8)" << end();
529 }
530 break;
531
532 :(scenario add_r32_to_mem_at_r32_plus_negative_disp8)
533 % Reg[EBX].i = 0x10; // source
534 % Reg[EAX].i = 0x61; // dest
535 == 0x1
536
537 01 58 ff
538
539 == 0x60
540 01 00 00 00
541 +run: add EBX to r/m32
542 +run: effective address is initially 0x61 (EAX)
543 +run: effective address is 0x60 (after adding disp8)
544 +run: storing 0x00000011
545
546
547
548 :(scenario add_r32_to_mem_at_r32_plus_disp32)
549 % Reg[EBX].i = 0x10; // source
550 % Reg[EAX].i = 0x5e; // dest
551 == 0x1
552
553 01 98 02 00 00 00
554
555 == 0x60
556 01 00 00 00
557 +run: add EBX to r/m32
558 +run: effective address is initially 0x5e (EAX)
559 +run: effective address is 0x60 (after adding disp32)
560 +run: storing 0x00000011
561
562 :(before "End Mod Special-cases(addr)")
563 case 2:
564 switch (rm) {
565 default:
566 addr = Reg[rm].u;
567 trace(90, "run") << "effective address is initially 0x" << std::hex << addr << " (" << rname(rm) << ")" << end();
568 break;
569
570 }
571 if (addr > 0) {
572 addr += imm32();
573 trace(90, "run") << "effective address is 0x" << std::hex << addr << " (after adding disp32)" << end();
574 }
575 break;
576
577 :(scenario add_r32_to_mem_at_r32_plus_negative_disp32)
578 % Reg[EBX].i = 0x10; // source
579 % Reg[EAX].i = 0x61; // dest
580 == 0x1
581
582 01 98 ff ff ff ff
583
584 == 0x60
585 01 00 00 00
586 +run: add EBX to r/m32
587 +run: effective address is initially 0x61 (EAX)
588 +run: effective address is 0x60 (after adding disp32)
589 +run: storing 0x00000011