https://github.com/akkartik/mu/blob/master/subx/013direct_addressing.cc
  1 //: operating directly on a register
  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"  // code segment
 12       // op     ModR/M  SIB   displacement  immediate
 13       "  01     d8                                    \n" // add EBX to EAX
 14       // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
 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: {  // add r32 to r/m32
 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 // Implement tables 2-2 and 2-3 in the Intel manual, Volume 2.
 35 // We return a pointer so that instructions can write to multiple bytes in
 36 // 'Mem' at once.
 37 // beware: will eventually have side-effects
 38 int32_t* effective_address(uint8_t modrm) {
 39   const uint8_t mod = (modrm>>6);
 40   // ignore middle 3 'reg opcode' bits
 41   const uint8_t rm = modrm & 0x7;
 42   if (mod == 3) {
 43     // mod 3 is just register direct addressing
 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 // beware: will eventually have side-effects
 53 uint32_t effective_address_number(uint8_t modrm) {
 54   const uint8_t mod = (modrm>>6);
 55   // ignore middle 3 'reg opcode' bits
 56   const uint8_t rm = modrm & 0x7;
 57   uint32_t addr = 0;
 58   switch (mod) {
 59   case 3:
 60     // mod 3 is just register direct addressing
 61     raise << "unexpected direct addressing mode\n" << end();
 62     return 0;
 63   // End Mod Special-cases(addr)
 64   default:
 65     cerr << "unrecognized mod bits: " << NUM(mod) << '\n';
 66     exit(1);
 67   }
 68   //: other mods are indirect, and they'll set addr appropriately
 69   // Found effective_address(addr)
 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 //:: subtract
 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"  // code segment
 98       // op     ModR/M  SIB   displacement  immediate
 99       "  29     d8                                    \n"  // subtract EBX from EAX
100       // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
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: {  // subtract r32 from r/m32
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 //:: multiply
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"  // code segment
130       // op     ModR/M  SIB   displacement  immediate
131       "  f7     e1                                    \n"  // multiply EAX by ECX
132       // ModR/M in binary: 11 (direct mode) 100 (subop mul) 001 (src ECX)
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;  // middle 3 'reg opcode' bits
148   switch (subop) {
149   case 4: {  // mul unsigned EAX by r/m32
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   // End Op f7 Subops
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"  // code segment
177       // op     ModR/M  SIB   displacement  immediate
178       "  0f af  d8                                    \n"  // subtract EBX into EAX
179       // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
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: {  // multiply r32 into r/m32
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 //:: negate
199 
200 :(code)
201 void test_negate_r32() {
202   Reg[EBX].i = 1;
203   run(
204       "== 0x1\n"  // code segment
205       // op     ModR/M  SIB   displacement  immediate
206       "  f7 db                                        \n"  // negate EBX
207       // ModR/M in binary: 11 (direct mode) 011 (subop negate) 011 (dest EBX)
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: {  // negate r/m32
219   trace(Callstack_depth+1, "run") << "subop: negate" << end();
220   // one case that can overflow
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 // negate can overflow in exactly one situation
238 void test_negate_can_overflow() {
239   Reg[EBX].i = 0x80000000;  // INT_MIN
240   run(
241       "== 0x1\n"  // code segment
242       // op     ModR/M  SIB   displacement  immediate
243       "  f7 db                                        \n"  // negate EBX
244       // ModR/M in binary: 11 (direct mode) 011 (subop negate) 011 (dest EBX)
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 //:: shift left
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"  // code segment
265       // op     ModR/M  SIB   displacement  immediate
266       "  d3     e3                                    \n"  // shift EBX left by CL bits
267       // ModR/M in binary: 11 (direct mode) 100 (subop shift left) 011 (dest EBX)
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;  // middle 3 'reg opcode' bits
283   switch (subop) {
284   case 4: {  // shift left r/m32 by CL
285     trace(Callstack_depth+1, "run") << "subop: shift left by CL bits" << end();
286     uint8_t count = Reg[ECX].u & 0x1f;
287     // OF is only defined if count is 1
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   // End Op d3 Subops
300   default:
301     cerr << "unrecognized subop for opcode d3: " << NUM(subop) << '\n';
302     exit(1);
303   }
304   break;
305 }
306 
307 //:: shift right arithmetic
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"  // code segment
315       // op     ModR/M  SIB   displacement  immediate
316       "  d3     fb                                    \n"  // shift EBX right by CL bits, while preserving sign
317       // ModR/M in binary: 11 (direct mode) 111 (subop shift right arithmetic) 011 (dest EBX)
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: {  // shift right r/m32 by CL, preserving sign
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   // OF is only defined if count is 1
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"  // code segment
346       // op     ModR/M  SIB   displacement  immediate
347       "  d3     fb                                    \n"  // shift EBX right by CL bits, while preserving sign
348       // ModR/M in binary: 11 (direct mode) 111 (subop shift right arithmetic) 011 (dest EBX)
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       // result: 13
355       "run: storing 0x0000000d\n"
356   );
357 }
358 
359 void test_shift_right_arithmetic_negative_r32_with_cl() {
360   Reg[EBX].i = 0xfffffffd;  // -3
361   Reg[ECX].i = 1;
362   run(
363       "== 0x1\n"  // code segment
364       // op     ModR/M  SIB   displacement  immediate
365       "  d3     fb                                    \n"  // shift EBX right by CL bits, while preserving sign
366       // ModR/M in binary: 11 (direct mode) 111 (subop shift right arithmetic) 011 (dest EBX)
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       // result: -2
373       "run: storing 0xfffffffe\n"
374   );
375 }
376 
377 //:: shift right logical
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"  // code segment
385       // op     ModR/M  SIB   displacement  immediate
386       "  d3     eb                                    \n"  // shift EBX right by CL bits, while padding zeroes
387       // ModR/M in binary: 11 (direct mode) 101 (subop shift right logical) 011 (dest EBX)
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       // result: 13
394       "run: storing 0x0000000d\n"
395   );
396 }
397 
398 :(before "End Op d3 Subops")
399 case 5: {  // shift right r/m32 by CL, preserving sign
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   // OF is only defined if count is 1
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   // result is always positive by definition
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"  // code segment
423       // op     ModR/M  SIB   displacement  immediate
424       "  d3     eb                                    \n"  // shift EBX right by CL bits, while padding zeroes
425       // ModR/M in binary: 11 (direct mode) 101 (subop shift right logical) 011 (dest EBX)
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       // result: 13
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"  // code segment
441       // op     ModR/M  SIB   displacement  immediate
442       "  d3     eb                                    \n"  // shift EBX right by CL bits, while padding zeroes
443       // ModR/M in binary: 11 (direct mode) 101 (subop shift right logical) 011 (dest EBX)
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 //:: and
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"  // code segment
464       // op     ModR/M  SIB   displacement  immediate
465       "  21     d8                                    \n"  // and EBX with destination EAX
466       // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
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: {  // and r32 with r/m32
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 //:: or
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"  // code segment
496       // op     ModR/M  SIB   displacement  immediate
497       "  09     d8                                    \n"  // or EBX with destination EAX
498       // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
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: {  // or r32 with r/m32
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 //:: xor
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"  // code segment
528       // op     ModR/M  SIB   displacement  immediate
529       "  31     d8                                    \n"  // xor EBX with destination EAX
530       // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
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: {  // xor r32 with r/m32
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 //:: not
550 
551 :(code)
552 void test_not_r32() {
553   Reg[EBX].i = 0x0f0f00ff;
554   run(
555       "== 0x1\n"  // code segment
556       // op     ModR/M  SIB   displacement  immediate
557       "  f7     d3                                    \n"  // not EBX
558       // ModR/M in binary: 11 (direct mode) 010 (subop not) 011 (dest EBX)
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: {  // not r/m32
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 //:: compare (cmp)
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"  // code segment
590       // op     ModR/M  SIB   displacement  immediate
591       "  39     d8                                    \n"  // compare EBX with EAX
592       // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
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: {  // set SF if r/m32 < r32
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"  // code segment
623       // op     ModR/M  SIB   displacement  immediate
624       "  39     d8                                    \n"  // compare EBX with EAX
625       // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
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"  // code segment
639       // op     ModR/M  SIB   displacement  immediate
640       "  39     d8                                    \n"  // compare EBX with EAX
641       // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
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 //:: copy (mov)
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"  // code segment
660       // op     ModR/M  SIB   displacement  immediate
661       "  89     d8                                    \n"  // copy EBX to EAX
662       // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
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: {  // copy r32 to r/m32
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 //:: xchg
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"  // code segment
693       // op     ModR/M  SIB   displacement  immediate
694       "  87     d8                                    \n"  // exchange EBX with EAX
695       // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
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: {  // exchange r32 with r/m32
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 //:: increment
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"  // code segment
736       // op     ModR/M  SIB   displacement  immediate
737       "  41                                           \n"  // increment ECX
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: {  // increment r32
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"  // code segment
769       // op     ModR/M  SIB   displacement  immediate
770       "  ff     c0                                    \n"  // increment EAX
771       // ModR/M in binary: 11 (direct mode) 000 (subop inc) 000 (EAX)
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;  // middle 3 'reg opcode' bits
784   switch (subop) {
785     case 0: {  // increment r/m32
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     // End Op ff Subops
797   }
798   break;
799 }
800 
801 //:: decrement
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"  // code segment
818       // op     ModR/M  SIB   displacement  immediate
819       "  49                                           \n"  // decrement ECX
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: {  // decrement r32
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"  // code segment
848       // op     ModR/M  SIB   displacement  immediate
849       "  ff     c8                                    \n"  // decrement EAX
850       // ModR/M in binary: 11 (direct mode) 001 (subop inc) 000 (EAX)
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: {  // decrement r/m32
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 //:: push
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"  // code segment
886       // op     ModR/M  SIB   displacement  immediate
887       "  53                                           \n"  // push EBX to stack
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: {  // push r32 to stack
905   uint8_t reg = op & 0x7;
906   trace(Callstack_depth+1, "run") << "push " << rname(reg) << end();
907 //?   cerr << "push: " << NUM(reg) << ": " << Reg[reg].u << " => " << Reg[ESP].u << '\n';
908   push(Reg[reg].u);
909   break;
910 }
911 
912 //:: pop
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));  // manually allocate memory
928   write_mem_i32(0x02000000, 0x0000000a);  // ..before this write
929   run(
930       "== 0x1\n"  // code segment
931       // op     ModR/M  SIB   displacement  immediate
932       "  5b                                           \n"  // pop stack to EBX
933       "== 0x2000\n"  // data segment
934       "0a 00 00 00\n"  // 0x0000000a
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: {  // pop stack into r32
952   const uint8_t reg = op & 0x7;
953   trace(Callstack_depth+1, "run") << "pop into " << rname(reg) << end();
954 //?   cerr << "pop from " << Reg[ESP].u << '\n';
955   Reg[reg].u = pop();
956 //?   cerr << "=> " << NUM(reg) << ": " << Reg[reg].u << '\n';
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 }