1
2
3 :(scenario add_r32_to_mem_at_r32)
4 % Reg[3].i = 0x10;
5 % Reg[0].i = 0x60;
6 % SET_WORD_IN_MEM(0x60, 1);
7
8 01 18
9
10 +run: add EBX to r/m32
11 +run: effective address is 0x60 (EAX)
12 +run: storing 0x00000011
13
14 :(before "End Mod Special-cases(addr)")
15 case 0:
16 switch (rm) {
17 default:
18 trace(2, "run") << "effective address is 0x" << std::hex << Reg[rm].u << " (" << rname(rm) << ")" << end();
19 addr = Reg[rm].u;
20 break;
21
22 }
23 break;
24
25
26
27 :(scenario add_mem_at_r32_to_r32)
28 % Reg[0].i = 0x60;
29 % Reg[3].i = 0x10;
30 % SET_WORD_IN_MEM(0x60, 1);
31
32 03 18
33
34 +run: add r/m32 to EBX
35 +run: effective address is 0x60 (EAX)
36 +run: storing 0x00000011
37
38 :(before "End Single-Byte Opcodes")
39 case 0x03: {
40 uint8_t modrm = next();
41 uint8_t arg1 = (modrm>>3)&0x7;
42 trace(2, "run") << "add r/m32 to " << rname(arg1) << end();
43 const int32_t* arg2 = effective_address(modrm);
44 BINARY_ARITHMETIC_OP(+, Reg[arg1].i, *arg2);
45 break;
46 }
47
48
49
50 :(scenario subtract_r32_from_mem_at_r32)
51 % Reg[0].i = 0x60;
52 % SET_WORD_IN_MEM(0x60, 10);
53 % Reg[3].i = 1;
54
55 29 18
56
57 +run: subtract EBX from r/m32
58 +run: effective address is 0x60 (EAX)
59 +run: storing 0x00000009
60
61
62
63 :(scenario subtract_mem_at_r32_from_r32)
64 % Reg[0].i = 0x60;
65 % SET_WORD_IN_MEM(0x60, 1);
66 % Reg[3].i = 10;
67
68 2b 18
69
70 +run: subtract r/m32 from EBX
71 +run: effective address is 0x60 (EAX)
72 +run: storing 0x00000009
73
74 :(before "End Single-Byte Opcodes")
75 case 0x2b: {
76 uint8_t modrm = next();
77 uint8_t arg1 = (modrm>>3)&0x7;
78 trace(2, "run") << "subtract r/m32 from " << rname(arg1) << end();
79 const int32_t* arg2 = effective_address(modrm);
80 BINARY_ARITHMETIC_OP(-, Reg[arg1].i, *arg2);
81 break;
82 }
83
84
85
86 :(scenario and_r32_with_mem_at_r32)
87 % Reg[0].i = 0x60;
88 % SET_WORD_IN_MEM(0x60, 0x0a0b0c0d);
89 % Reg[3].i = 0xff;
90
91 21 18
92
93 +run: and EBX with r/m32
94 +run: effective address is 0x60 (EAX)
95 +run: storing 0x0000000d
96
97
98
99 :(scenario and_mem_at_r32_with_r32)
100 % Reg[0].i = 0x60;
101 % SET_WORD_IN_MEM(0x60, 0x000000ff);
102 % Reg[3].i = 0x0a0b0c0d;
103
104 23 18
105
106 +run: and r/m32 with EBX
107 +run: effective address is 0x60 (EAX)
108 +run: storing 0x0000000d
109
110 :(before "End Single-Byte Opcodes")
111 case 0x23: {
112 uint8_t modrm = next();
113 uint8_t arg1 = (modrm>>3)&0x7;
114 trace(2, "run") << "and r/m32 with " << rname(arg1) << end();
115 const int32_t* arg2 = effective_address(modrm);
116 BINARY_BITWISE_OP(&, Reg[arg1].u, *arg2);
117 break;
118 }
119
120
121
122 :(scenario or_r32_with_mem_at_r32)
123 % Reg[0].i = 0x60;
124 % SET_WORD_IN_MEM(0x60, 0x0a0b0c0d);
125 % Reg[3].i = 0xa0b0c0d0;
126
127 09 18
128
129 +run: or EBX with r/m32
130 +run: effective address is 0x60 (EAX)
131 +run: storing 0xaabbccdd
132
133
134
135 :(scenario or_mem_at_r32_with_r32)
136 % Reg[0].i = 0x60;
137 % SET_WORD_IN_MEM(0x60, 0x0a0b0c0d);
138 % Reg[3].i = 0xa0b0c0d0;
139
140 0b 18
141
142 +run: or r/m32 with EBX
143 +run: effective address is 0x60 (EAX)
144 +run: storing 0xaabbccdd
145
146 :(before "End Single-Byte Opcodes")
147 case 0x0b: {
148 uint8_t modrm = next();
149 uint8_t arg1 = (modrm>>3)&0x7;
150 trace(2, "run") << "or r/m32 with " << rname(arg1) << end();
151 const int32_t* arg2 = effective_address(modrm);
152 BINARY_BITWISE_OP(|, Reg[arg1].u, *arg2);
153 break;
154 }
155
156
157
158 :(scenario xor_r32_with_mem_at_r32)
159 % Reg[0].i = 0x60;
160 % SET_WORD_IN_MEM(0x60, 0xaabb0c0d);
161 % Reg[3].i = 0xa0b0c0d0;
162
163 31 18
164
165 +run: xor EBX with r/m32
166 +run: effective address is 0x60 (EAX)
167 +run: storing 0x0a0bccdd
168
169
170
171 :(scenario xor_mem_at_r32_with_r32)
172 % Reg[0].i = 0x60;
173 % SET_WORD_IN_MEM(0x60, 0x0a0b0c0d);
174 % Reg[3].i = 0xa0b0c0d0;
175
176 33 18
177
178 +run: xor r/m32 with EBX
179 +run: effective address is 0x60 (EAX)
180 +run: storing 0xaabbccdd
181
182 :(before "End Single-Byte Opcodes")
183 case 0x33: {
184 uint8_t modrm = next();
185 uint8_t arg1 = (modrm>>3)&0x7;
186 trace(2, "run") << "xor r/m32 with " << rname(arg1) << end();
187 const int32_t* arg2 = effective_address(modrm);
188 BINARY_BITWISE_OP(|, Reg[arg1].u, *arg2);
189 break;
190 }
191
192
193
194 :(scenario not_r32_with_mem_at_r32)
195 % Reg[3].i = 0x60;
196
197 % SET_WORD_IN_MEM(0x60, 0x0f0f00ff);
198
199 f7 03
200
201 +run: 'not' of r/m32
202 +run: effective address is 0x60 (EBX)
203 +run: storing 0xf0f0ff00
204
205
206
207 :(scenario compare_mem_at_r32_with_r32_greater)
208 % Reg[0].i = 0x60;
209 % SET_WORD_IN_MEM(0x60, 0x0a0b0c0d);
210 % Reg[3].i = 0x0a0b0c07;
211
212 39 18
213
214 +run: compare EBX with r/m32
215 +run: effective address is 0x60 (EAX)
216 +run: SF=0; ZF=0; OF=0
217
218 :(scenario compare_mem_at_r32_with_r32_lesser)
219 % Reg[0].i = 0x60;
220 % SET_WORD_IN_MEM(0x60, 0x0a0b0c07);
221 % Reg[3].i = 0x0a0b0c0d;
222
223 39 18
224
225 +run: compare EBX with r/m32
226 +run: effective address is 0x60 (EAX)
227 +run: SF=1; ZF=0; OF=0
228
229 :(scenario compare_mem_at_r32_with_r32_equal)
230 % Reg[0].i = 0x60;
231 % SET_WORD_IN_MEM(0x60, 0x0a0b0c0d);
232 % Reg[3].i = 0x0a0b0c0d;
233
234 39 18
235
236 +run: compare EBX with r/m32
237 +run: effective address is 0x60 (EAX)
238 +run: SF=0; ZF=1; OF=0
239
240
241
242 :(scenario compare_r32_with_mem_at_r32_greater)
243 % Reg[0].i = 0x60;
244 % SET_WORD_IN_MEM(0x60, 0x0a0b0c07);
245 % Reg[3].i = 0x0a0b0c0d;
246
247 3b 18
248
249 +run: compare r/m32 with EBX
250 +run: effective address is 0x60 (EAX)
251 +run: SF=0; ZF=0; OF=0
252
253 :(before "End Single-Byte Opcodes")
254 case 0x3b: {
255 uint8_t modrm = next();
256 uint8_t reg1 = (modrm>>3)&0x7;
257 trace(2, "run") << "compare r/m32 with " << rname(reg1) << end();
258 int32_t arg1 = Reg[reg1].i;
259 int32_t* arg2 = effective_address(modrm);
260 int32_t tmp1 = arg1 - *arg2;
261 SF = (tmp1 < 0);
262 ZF = (tmp1 == 0);
263 int64_t tmp2 = arg1 - *arg2;
264 OF = (tmp1 != tmp2);
265 trace(2, "run") << "SF=" << SF << "; ZF=" << ZF << "; OF=" << OF << end();
266 break;
267 }
268
269 :(scenario compare_r32_with_mem_at_r32_lesser)
270 % Reg[0].i = 0x60;
271 % SET_WORD_IN_MEM(0x60, 0x0a0b0c0d);
272 % Reg[3].i = 0x0a0b0c07;
273
274 3b 18
275
276 +run: compare r/m32 with EBX
277 +run: effective address is 0x60 (EAX)
278 +run: SF=1; ZF=0; OF=0
279
280 :(scenario compare_r32_with_mem_at_r32_equal)
281 % Reg[0].i = 0x60;
282 % SET_WORD_IN_MEM(0x60, 0x0a0b0c0d);
283 % Reg[3].i = 0x0a0b0c0d;
284
285 3b 18
286
287 +run: compare r/m32 with EBX
288 +run: effective address is 0x60 (EAX)
289 +run: SF=0; ZF=1; OF=0
290
291
292
293 :(scenario copy_r32_to_mem_at_r32)
294 % Reg[3].i = 0xaf;
295 % Reg[0].i = 0x60;
296
297 89 18
298
299 +run: copy EBX to r/m32
300 +run: effective address is 0x60 (EAX)
301 +run: storing 0x000000af
302
303
304
305 :(scenario copy_mem_at_r32_to_r32)
306 % Reg[0].i = 0x60;
307 % SET_WORD_IN_MEM(0x60, 0x000000af);
308
309 8b 18
310
311 +run: copy r/m32 to EBX
312 +run: effective address is 0x60 (EAX)
313 +run: storing 0x000000af
314
315 :(before "End Single-Byte Opcodes")
316 case 0x8b: {
317 uint8_t modrm = next();
318 uint8_t reg1 = (modrm>>3)&0x7;
319 trace(2, "run") << "copy r/m32 to " << rname(reg1) << end();
320 int32_t* arg2 = effective_address(modrm);
321 Reg[reg1].i = *arg2;
322 trace(2, "run") << "storing 0x" << HEXWORD << *arg2 << end();
323 break;
324 }
325
326
327
328 :(scenario jump_mem_at_r32)
329 % Reg[0].i = 0x60;
330 % SET_WORD_IN_MEM(0x60, 8);
331
332 ff 20
333
334 05 00 00 00 01
335 05 00 00 00 02
336 +run: inst: 0x00000001
337 +run: jump to r/m32
338 +run: effective address is 0x60 (EAX)
339 +run: jumping to 0x00000008
340 +run: inst: 0x00000008
341 -run: inst: 0x00000003
342
343 :(before "End Single-Byte Opcodes")
344 case 0xff: {
345 uint8_t modrm = next();
346 uint8_t subop = (modrm>>3)&0x7;
347 switch (subop) {
348 case 4: {
349 trace(2, "run") << "jump to r/m32" << end();
350 int32_t* arg2 = effective_address(modrm);
351 EIP = *arg2;
352 trace(2, "run") << "jumping to 0x" << HEXWORD << EIP << end();
353 break;
354 }
355
356 }
357 break;
358 }
359
360
361
362 :(scenario push_mem_at_r32)
363 % Reg[0].i = 0x60;
364 % SET_WORD_IN_MEM(0x60, 0x000000af);
365 % Reg[ESP].u = 0x14;
366
367 ff 30
368
369 +run: push r/m32
370 +run: effective address is 0x60 (EAX)
371 +run: decrementing ESP to 0x00000010
372 +run: pushing value 0x000000af
373
374 :(before "End Op ff Subops")
375 case 6: {
376 trace(2, "run") << "push r/m32" << end();
377 const int32_t* val = effective_address(modrm);
378 push(*val);
379 break;
380 }
381
382
383
384 :(scenario pop_mem_at_r32)
385 % Reg[0].i = 0x60;
386 % Reg[ESP].u = 0x10;
387 % SET_WORD_IN_MEM(0x10, 0x00000030);
388
389 8f 00
390
391 +run: pop into r/m32
392 +run: effective address is 0x60 (EAX)
393 +run: popping value 0x00000030
394 +run: incrementing ESP to 0x00000014
395
396 :(before "End Single-Byte Opcodes")
397 case 0x8f: {
398 uint8_t modrm = next();
399 uint8_t subop = (modrm>>3)&0x7;
400 switch (subop) {
401 case 0: {
402 trace(2, "run") << "pop into r/m32" << end();
403 int32_t* dest = effective_address(modrm);
404 *dest = pop();
405 break;
406 }
407 }
408 break;
409 }
410
411
412
413 :(scenario add_r32_to_mem_at_displacement)
414 % Reg[3].i = 0x10; // source
415 % SET_WORD_IN_MEM(0x60, 1);
416
417 01 1d 60 00 00 00
418
419 +run: add EBX to r/m32
420 +run: effective address is 0x60 (disp32)
421 +run: storing 0x00000011
422
423 :(before "End Mod 0 Special-cases(addr)")
424 case 5:
425 addr = imm32();
426 trace(2, "run") << "effective address is 0x" << std::hex << addr << " (disp32)" << end();
427 break;
428
429
430
431 :(scenario add_r32_to_mem_at_r32_plus_disp8)
432 % Reg[3].i = 0x10; // source
433 % Reg[0].i = 0x5e; // dest
434 % SET_WORD_IN_MEM(0x60, 1);
435
436 01 58 02
437
438 +run: add EBX to r/m32
439 +run: effective address is initially 0x5e (EAX)
440 +run: effective address is 0x60 (after adding disp8)
441 +run: storing 0x00000011
442
443 :(before "End Mod Special-cases(addr)")
444 case 1:
445 switch (rm) {
446 default:
447 addr = Reg[rm].u;
448 trace(2, "run") << "effective address is initially 0x" << std::hex << addr << " (" << rname(rm) << ")" << end();
449 break;
450
451 }
452 if (addr > 0) {
453 addr += static_cast<int8_t>(next());
454 trace(2, "run") << "effective address is 0x" << std::hex << addr << " (after adding disp8)" << end();
455 }
456 break;
457
458 :(scenario add_r32_to_mem_at_r32_plus_negative_disp8)
459 % Reg[3].i = 0x10; // source
460 % Reg[0].i = 0x61; // dest
461 % SET_WORD_IN_MEM(0x60, 1);
462
463 01 58 ff
464
465 +run: add EBX to r/m32
466 +run: effective address is initially 0x61 (EAX)
467 +run: effective address is 0x60 (after adding disp8)
468 +run: storing 0x00000011
469
470
471
472 :(scenario add_r32_to_mem_at_r32_plus_disp32)
473 % Reg[3].i = 0x10; // source
474 % Reg[0].i = 0x5e; // dest
475 % SET_WORD_IN_MEM(0x60, 1);
476
477 01 98 02 00 00 00
478
479 +run: add EBX to r/m32
480 +run: effective address is initially 0x5e (EAX)
481 +run: effective address is 0x60 (after adding disp32)
482 +run: storing 0x00000011
483
484 :(before "End Mod Special-cases(addr)")
485 case 2:
486 switch (rm) {
487 default:
488 addr = Reg[rm].u;
489 trace(2, "run") << "effective address is initially 0x" << std::hex << addr << " (" << rname(rm) << ")" << end();
490 break;
491
492 }
493 if (addr > 0) {
494 addr += imm32();
495 trace(2, "run") << "effective address is 0x" << std::hex << addr << " (after adding disp32)" << end();
496 }
497 break;
498
499 :(scenario add_r32_to_mem_at_r32_plus_negative_disp32)
500 % Reg[3].i = 0x10; // source
501 % Reg[0].i = 0x61; // dest
502 % SET_WORD_IN_MEM(0x60, 1);
503
504 01 98 ff ff ff ff
505
506 +run: add EBX to r/m32
507 +run: effective address is initially 0x61 (EAX)
508 +run: effective address is 0x60 (after adding disp32)
509 +run: storing 0x00000011