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       "== code 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* signed_arg1 = effective_address(modrm);
  29   int32_t signed_result = *signed_arg1 + Reg[arg2].i;
  30   SF = (signed_result < 0);
  31   ZF = (signed_result == 0);
  32   int64_t signed_full_result = static_cast<int64_t>(*signed_arg1) + Reg[arg2].i;
  33   OF = (signed_result != signed_full_result);
  34   // set CF
  35   uint32_t unsigned_arg1 = static_cast<uint32_t>(*signed_arg1);
  36   uint32_t unsigned_result = unsigned_arg1 + Reg[arg2].u;
  37   uint64_t unsigned_full_result = static_cast<uint64_t>(unsigned_arg1) + Reg[arg2].u;
  38   CF = (unsigned_result != unsigned_full_result);
  39   trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
  40   *signed_arg1 = signed_result;
  41   trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *signed_arg1 << end();
  42   break;
  43 }
  44 
  45 :(code)
  46 void test_add_r32_to_r32_signed_overflow() {
  47   Reg[EAX].i = 0x7fffffff;  // largest positive signed integer
  48   Reg[EBX].i = 1;
  49   run(
  50       "== code 0x1\n"  // code segment
  51       // op     ModR/M  SIB   displacement  immediate
  52       "  01     d8                                    \n" // add EBX to EAX
  53       // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
  54   );
  55   CHECK_TRACE_CONTENTS(
  56       "run: add EBX to r/m32\n"
  57       "run: r/m32 is EAX\n"
  58       "run: SF=1; ZF=0; CF=0; OF=1\n"
  59       "run: storing 0x80000000\n"
  60   );
  61 }
  62 
  63 void test_add_r32_to_r32_unsigned_overflow() {
  64   Reg[EAX].u = 0xffffffff;  // largest unsigned number
  65   Reg[EBX].u = 1;
  66   run(
  67       "== code 0x1\n"  // code segment
  68       // op     ModR/M  SIB   displacement  immediate
  69       "  01     d8                                    \n" // add EBX to EAX
  70       // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
  71   );
  72   CHECK_TRACE_CONTENTS(
  73       "run: add EBX to r/m32\n"
  74       "run: r/m32 is EAX\n"
  75       "run: SF=0; ZF=1; CF=1; OF=0\n"
  76       "run: storing 0x00000000\n"
  77   );
  78 }
  79 
  80 void test_add_r32_to_r32_unsigned_and_signed_overflow() {
  81   Reg[EAX].u = Reg[EBX].u = 0x80000000;  // smallest negative signed integer
  82   run(
  83       "== code 0x1\n"  // code segment
  84       // op     ModR/M  SIB   displacement  immediate
  85       "  01     d8                                    \n" // add EBX to EAX
  86       // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
  87   );
  88   CHECK_TRACE_CONTENTS(
  89       "run: add EBX to r/m32\n"
  90       "run: r/m32 is EAX\n"
  91       "run: SF=0; ZF=1; CF=1; OF=1\n"
  92       "run: storing 0x00000000\n"
  93   );
  94 }
  95 
  96 :(code)
  97 // Implement tables 2-2 and 2-3 in the Intel manual, Volume 2.
  98 // We return a pointer so that instructions can write to multiple bytes in
  99 // 'Mem' at once.
 100 // beware: will eventually have side-effects
 101 int32_t* effective_address(uint8_t modrm) {
 102   const uint8_t mod = (modrm>>6);
 103   // ignore middle 3 'reg opcode' bits
 104   const uint8_t rm = modrm & 0x7;
 105   if (mod == 3) {
 106     // mod 3 is just register direct addressing
 107     trace(Callstack_depth+1, "run") << "r/m32 is " << rname(rm) << end();
 108     return &Reg[rm].i;
 109   }
 110   uint32_t addr = effective_address_number(modrm);
 111   trace(Callstack_depth+1, "run") << "effective address contains " << read_mem_i32(addr) << end();
 112   return mem_addr_i32(addr);
 113 }
 114 
 115 // beware: will eventually have side-effects
 116 uint32_t effective_address_number(uint8_t modrm) {
 117   const uint8_t mod = (modrm>>6);
 118   // ignore middle 3 'reg opcode' bits
 119   const uint8_t rm = modrm & 0x7;
 120   uint32_t addr = 0;
 121   switch (mod) {
 122   case 3:
 123     // mod 3 is just register direct addressing
 124     raise << "unexpected direct addressing mode\n" << end();
 125     return 0;
 126   // End Mod Special-cases(addr)
 127   default:
 128     cerr << "unrecognized mod bits: " << NUM(mod) << '\n';
 129     exit(1);
 130   }
 131   //: other mods are indirect, and they'll set addr appropriately
 132   // Found effective_address(addr)
 133   return addr;
 134 }
 135 
 136 string rname(uint8_t r) {
 137   switch (r) {
 138   case 0: return "EAX";
 139   case 1: return "ECX";
 140   case 2: return "EDX";
 141   case 3: return "EBX";
 142   case 4: return "ESP";
 143   case 5: return "EBP";
 144   case 6: return "ESI";
 145   case 7: return "EDI";
 146   default: raise << "invalid register " << r << '\n' << end();  return "";
 147   }
 148 }
 149 
 150 //:: subtract
 151 
 152 :(before "End Initialize Op Names")
 153 put_new(Name, "29", "subtract r32 from rm32 (sub)");
 154 
 155 :(code)
 156 void test_subtract_r32_from_r32() {
 157   Reg[EAX].i = 10;
 158   Reg[EBX].i = 1;
 159   run(
 160       "== code 0x1\n"  // code segment
 161       // op     ModR/M  SIB   displacement  immediate
 162       "  29     d8                                    \n"  // subtract EBX from EAX
 163       // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
 164   );
 165   CHECK_TRACE_CONTENTS(
 166       "run: subtract EBX from r/m32\n"
 167       "run: r/m32 is EAX\n"
 168       "run: storing 0x00000009\n"
 169   );
 170 }
 171 
 172 :(before "End Single-Byte Opcodes")
 173 case 0x29: {  // subtract r32 from r/m32
 174   const uint8_t modrm = next();
 175   const uint8_t arg2 = (modrm>>3)&0x7;
 176   trace(Callstack_depth+1, "run") << "subtract " << rname(arg2) << " from r/m32" << end();
 177   int32_t* signed_arg1 = effective_address(modrm);
 178   int32_t signed_result = *signed_arg1 - Reg[arg2].i;
 179   SF = (signed_result < 0);
 180   ZF = (signed_result == 0);
 181   int64_t signed_full_result = static_cast<int64_t>(*signed_arg1) - Reg[arg2].i;
 182   OF = (signed_result != signed_full_result);
 183   // set CF
 184   uint32_t unsigned_arg1 = static_cast<uint32_t>(*signed_arg1);
 185   uint32_t unsigned_result = unsigned_arg1 - Reg[arg2].u;
 186   uint64_t unsigned_full_result = static_cast<uint64_t>(unsigned_arg1) - Reg[arg2].u;
 187   CF = (unsigned_result != unsigned_full_result);
 188   trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
 189   *signed_arg1 = signed_result;
 190   trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *signed_arg1 << end();
 191   break;
 192 }
 193 
 194 :(code)
 195 void test_subtract_r32_from_r32_signed_overflow() {
 196   Reg[EAX].i = 0x80000000;  // smallest negative signed integer
 197   Reg[EBX].i = 0x7fffffff;  // largest positive signed integer
 198   run(
 199       "== code 0x1\n"  // code segment
 200       // op     ModR/M  SIB   displacement  immediate
 201       "  29     d8                                    \n"  // subtract EBX from EAX
 202       // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
 203   );
 204   CHECK_TRACE_CONTENTS(
 205       "run: subtract EBX from r/m32\n"
 206       "run: r/m32 is EAX\n"
 207       "run: SF=0; ZF=0; CF=0; OF=1\n"
 208       "run: storing 0x00000001\n"
 209   );
 210 }
 211 
 212 void test_subtract_r32_from_r32_unsigned_overflow() {
 213   Reg[EAX].i = 0;
 214   Reg[EBX].i = 1;
 215   run(
 216       "== code 0x1\n"  // code segment
 217       // op     ModR/M  SIB   displacement  immediate
 218       "  29     d8                                    \n"  // subtract EBX from EAX
 219       // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
 220   );
 221   CHECK_TRACE_CONTENTS(
 222       "run: subtract EBX from r/m32\n"
 223       "run: r/m32 is EAX\n"
 224       "run: SF=1; ZF=0; CF=1; OF=0\n"
 225       "run: storing 0xffffffff\n"
 226   );
 227 }
 228 
 229 void test_subtract_r32_from_r32_signed_and_unsigned_overflow() {
 230   Reg[EAX].i = 0;
 231   Reg[EBX].i = 0x80000000;  // smallest negative signed integer
 232   run(
 233       "== code 0x1\n"  // code segment
 234       // op     ModR/M  SIB   displacement  immediate
 235       "  29     d8                                    \n"  // subtract EBX from EAX
 236       // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
 237   );
 238   CHECK_TRACE_CONTENTS(
 239       "run: subtract EBX from r/m32\n"
 240       "run: r/m32 is EAX\n"
 241       "run: SF=1; ZF=0; CF=1; OF=1\n"
 242       "run: storing 0x80000000\n"
 243   );
 244 }
 245 
 246 //:: multiply
 247 
 248 :(before "End Initialize Op Names")
 249 put_new(Name, "f7", "negate/multiply/divide rm32 (with EAX and EDX if necessary) depending on subop (neg/mul/idiv)");
 250 
 251 :(code)
 252 void test_multiply_EAX_by_r32() {
 253   Reg[EAX].i = 4;
 254   Reg[ECX].i = 3;
 255   run(
 256       "== code 0x1\n"  // code segment
 257       // op     ModR/M  SIB   displacement  immediate
 258       "  f7     e1                                    \n"  // multiply EAX by ECX
 259       // ModR/M in binary: 11 (direct mode) 100 (subop mul) 001 (src ECX)
 260   );
 261   CHECK_TRACE_CONTENTS(
 262       "run: operate on r/m32\n"
 263       "run: r/m32 is ECX\n"
 264       "run: subop: multiply EAX by r/m32\n"
 265       "run: storing 0x0000000c\n"
 266   );
 267 }
 268 
 269 :(before "End Single-Byte Opcodes")
 270 case 0xf7: {
 271   const uint8_t modrm = next();
 272   trace(Callstack_depth+1, "run") << "operate on r/m32" << end();
 273   int32_t* arg1 = effective_address(modrm);
 274   const uint8_t subop = (modrm>>3)&0x7;  // middle 3 'reg opcode' bits
 275   switch (subop) {
 276   case 4: {  // mul unsigned EAX by r/m32
 277     trace(Callstack_depth+1, "run") << "subop: multiply EAX by r/m32" << end();
 278     const uint64_t result = static_cast<uint64_t>(Reg[EAX].u) * static_cast<uint32_t>(*arg1);
 279     Reg[EAX].u = result & 0xffffffff;
 280     Reg[EDX].u = result >> 32;
 281     OF = (Reg[EDX].u != 0);
 282     CF = OF;
 283     trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
 284     trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[EAX].u << end();
 285     break;
 286   }
 287   // End Op f7 Subops
 288   default:
 289     cerr << "unrecognized subop for opcode f7: " << NUM(subop) << '\n';
 290     exit(1);
 291   }
 292   break;
 293 }
 294 
 295 //:
 296 
 297 :(before "End Initialize Op Names")
 298 put_new(Name_0f, "af", "multiply rm32 into r32 (imul)");
 299 
 300 :(code)
 301 void test_multiply_r32_into_r32() {
 302   Reg[EAX].i = 4;
 303   Reg[EBX].i = 2;
 304   run(
 305       "== code 0x1\n"  // code segment
 306       // op     ModR/M  SIB   displacement  immediate
 307       "  0f af  d8                                    \n"  // subtract EBX into EAX
 308       // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
 309   );
 310   CHECK_TRACE_CONTENTS(
 311       "run: multiply EBX by r/m32\n"
 312       "run: r/m32 is EAX\n"
 313       "run: storing 0x00000008\n"
 314   );
 315 }
 316 
 317 :(before "End Two-Byte Opcodes Starting With 0f")
 318 case 0xaf: {  // multiply r32 by r/m32
 319   const uint8_t modrm = next();
 320   const uint8_t arg1 = (modrm>>3)&0x7;
 321   trace(Callstack_depth+1, "run") << "multiply " << rname(arg1) << " by r/m32" << end();
 322   const int32_t* arg2 = effective_address(modrm);
 323   int32_t result = Reg[arg1].i * (*arg2);
 324   SF = (Reg[arg1].i < 0);
 325   ZF = (Reg[arg1].i == 0);
 326   int64_t full_result = static_cast<int64_t>(Reg[arg1].i) * (*arg2);
 327   OF = (Reg[arg1].i != full_result);
 328   CF = OF;
 329   trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
 330   Reg[arg1].i = result;
 331   trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[arg1].i << end();
 332   break;
 333 }
 334 
 335 //:: negate
 336 
 337 :(code)
 338 void test_negate_r32() {
 339   Reg[EBX].i = 1;
 340   run(
 341       "== code 0x1\n"  // code segment
 342       // op     ModR/M  SIB   displacement  immediate
 343       "  f7     db                                    \n"  // negate EBX
 344       // ModR/M in binary: 11 (direct mode) 011 (subop negate) 011 (dest EBX)
 345   );
 346   CHECK_TRACE_CONTENTS(
 347       "run: operate on r/m32\n"
 348       "run: r/m32 is EBX\n"
 349       "run: subop: negate\n"
 350       "run: storing 0xffffffff\n"
 351   );
 352 }
 353 
 354 :(before "End Op f7 Subops")
 355 case 3: {  // negate r/m32
 356   trace(Callstack_depth+1, "run") << "subop: negate" << end();
 357   // one case that can overflow
 358   if (static_cast<uint32_t>(*arg1) == 0x80000000) {
 359     trace(Callstack_depth+1, "run") << "overflow" << end();
 360     SF = true;
 361     ZF = false;
 362     OF = true;
 363     break;
 364   }
 365   int32_t result = -(*arg1);
 366   SF = (result >> 31);
 367   ZF = (result == 0);
 368   OF = false;
 369   CF = (*arg1 != 0);
 370   trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
 371   *arg1 = result;
 372   trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *arg1 << end();
 373   break;
 374 }
 375 
 376 :(code)
 377 // negate can overflow in exactly one situation
 378 void test_negate_can_overflow() {
 379   Reg[EBX].i = 0x80000000;  // INT_MIN
 380   run(
 381       "== code 0x1\n"  // code segment
 382       // op     ModR/M  SIB   displacement  immediate
 383       "  f7     db                                    \n"  // negate EBX
 384       // ModR/M in binary: 11 (direct mode) 011 (subop negate) 011 (dest EBX)
 385   );
 386   CHECK_TRACE_CONTENTS(
 387       "run: operate on r/m32\n"
 388       "run: r/m32 is EBX\n"
 389       "run: subop: negate\n"
 390       "run: overflow\n"
 391   );
 392 }
 393 
 394 //:: divide with remainder
 395 
 396 void test_divide_EAX_by_rm32() {
 397   Reg[EAX].u = 7;
 398   Reg[EDX].u = 0;
 399   Reg[ECX].i = 3;
 400   run(
 401       "== code 0x1\n"  // code segment
 402       // op     ModR/M  SIB   displacement  immediate
 403       "  f7     f9                                    \n"  // multiply EAX by ECX
 404       // ModR/M in binary: 11 (direct mode) 111 (subop idiv) 001 (divisor ECX)
 405   );
 406   CHECK_TRACE_CONTENTS(
 407       "run: operate on r/m32\n"
 408       "run: r/m32 is ECX\n"
 409       "run: subop: divide EDX:EAX by r/m32, storing quotient in EAX and remainder in EDX\n"
 410       "run: quotient: 0x00000002\n"
 411       "run: remainder: 0x00000001\n"
 412   );
 413 }
 414 
 415 :(before "End Op f7 Subops")
 416 case 7: {  // divide EDX:EAX by r/m32, storing quotient in EAX and remainder in EDX
 417   trace(Callstack_depth+1, "run") << "subop: divide EDX:EAX by r/m32, storing quotient in EAX and remainder in EDX" << end();
 418   int64_t dividend = static_cast<int64_t>((static_cast<uint64_t>(Reg[EDX].u) << 32) | Reg[EAX].u);
 419   int32_t divisor = *arg1;
 420   assert(divisor != 0);
 421   Reg[EAX].i = dividend/divisor;  // quotient
 422   Reg[EDX].i = dividend%divisor;  // remainder
 423   // flag state undefined
 424   trace(Callstack_depth+1, "run") << "quotient: 0x" << HEXWORD << Reg[EAX].i << end();
 425   trace(Callstack_depth+1, "run") << "remainder: 0x" << HEXWORD << Reg[EDX].i << end();
 426   break;
 427 }
 428 
 429 :(code)
 430 void test_divide_EAX_by_negative_rm32() {
 431   Reg[EAX].u = 7;
 432   Reg[EDX].u = 0;
 433   Reg[ECX].i = -3;
 434   run(
 435       "== code 0x1\n"  // code segment
 436       // op     ModR/M  SIB   displacement  immediate
 437       "  f7     f9                                    \n"  // multiply EAX by ECX
 438       // ModR/M in binary: 11 (direct mode) 111 (subop idiv) 001 (divisor ECX)
 439   );
 440   CHECK_TRACE_CONTENTS(
 441       "run: operate on r/m32\n"
 442       "run: r/m32 is ECX\n"
 443       "run: subop: divide EDX:EAX by r/m32, storing quotient in EAX and remainder in EDX\n"
 444       "run: quotient: 0xfffffffe\n"  // -2
 445       "run: remainder: 0x00000001\n"
 446   );
 447 }
 448 
 449 void test_divide_negative_EAX_by_rm32() {
 450   Reg[EAX].i = -7;
 451   Reg[EDX].i = -1;  // sign extend
 452   Reg[ECX].i = 3;
 453   run(
 454       "== code 0x1\n"  // code segment
 455       // op     ModR/M  SIB   displacement  immediate
 456       "  f7     f9                                    \n"  // multiply EAX by ECX
 457       // ModR/M in binary: 11 (direct mode) 111 (subop idiv) 001 (divisor ECX)
 458   );
 459   CHECK_TRACE_CONTENTS(
 460       "run: operate on r/m32\n"
 461       "run: r/m32 is ECX\n"
 462       "run: subop: divide EDX:EAX by r/m32, storing quotient in EAX and remainder in EDX\n"
 463       "run: quotient: 0xfffffffe\n"  // -2
 464       "run: remainder: 0xffffffff\n"  // -1, same sign as divident (EDX:EAX)
 465   );
 466 }
 467 
 468 void test_divide_negative_EDX_EAX_by_rm32() {
 469   Reg[EAX].i = 0;  // lower 32 bits are clear
 470   Reg[EDX].i = -7;
 471   Reg[ECX].i = 0x40000000;  // 2^30 (largest positive power of 2)
 472   run(
 473       "== code 0x1\n"  // code segment
 474       // op     ModR/M  SIB   displacement  immediate
 475       "  f7     f9                                    \n"  // multiply EAX by ECX
 476       // ModR/M in binary: 11 (direct mode) 111 (subop idiv) 001 (divisor ECX)
 477   );
 478   CHECK_TRACE_CONTENTS(
 479       "run: operate on r/m32\n"
 480       "run: r/m32 is ECX\n"
 481       "run: subop: divide EDX:EAX by r/m32, storing quotient in EAX and remainder in EDX\n"
 482       "run: quotient: 0xffffffe4\n"  // (-7 << 32) / (1 << 30) = -7 << 2 = -28
 483       "run: remainder: 0x00000000\n"
 484   );
 485 }
 486 
 487 //:: shift left
 488 
 489 :(before "End Initialize Op Names")
 490 put_new(Name, "d3", "shift rm32 by CL bits depending on subop (sal/sar/shl/shr)");
 491 
 492 :(code)
 493 void test_shift_left_r32_with_cl() {
 494   Reg[EBX].i = 13;
 495   Reg[ECX].i = 1;
 496   run(
 497       "== code 0x1\n"  // code segment
 498       // op     ModR/M  SIB   displacement  immediate
 499       "  d3     e3                                    \n"  // shift EBX left by CL bits
 500       // ModR/M in binary: 11 (direct mode) 100 (subop shift left) 011 (dest EBX)
 501   );
 502   CHECK_TRACE_CONTENTS(
 503       "run: operate on r/m32\n"
 504       "run: r/m32 is EBX\n"
 505       "run: subop: shift left by CL bits\n"
 506       "run: storing 0x0000001a\n"
 507   );
 508 }
 509 
 510 :(before "End Single-Byte Opcodes")
 511 case 0xd3: {
 512   const uint8_t modrm = next();
 513   trace(Callstack_depth+1, "run") << "operate on r/m32" << end();
 514   int32_t* arg1 = effective_address(modrm);
 515   const uint8_t subop = (modrm>>3)&0x7;  // middle 3 'reg opcode' bits
 516   switch (subop) {
 517   case 4: {  // shift left r/m32 by CL
 518     trace(Callstack_depth+1, "run") << "subop: shift left by CL bits" << end();
 519     uint8_t count = Reg[ECX].u & 0x1f;
 520     // OF is only defined if count is 1
 521     if (count == 1) {
 522       bool msb = (*arg1 & 0x80000000) >> 1;
 523       bool pnsb = (*arg1 & 0x40000000);
 524       OF = (msb != pnsb);
 525     }
 526     int32_t result = (*arg1 << count);
 527     ZF = (result == 0);
 528     SF = (result < 0);
 529     CF = (*arg1 << (count-1)) & 0x80000000;
 530     trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
 531     *arg1 = result;
 532     trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *arg1 << end();
 533     break;
 534   }
 535   // End Op d3 Subops
 536   default:
 537     cerr << "unrecognized subop for opcode d3: " << NUM(subop) << '\n';
 538     exit(1);
 539   }
 540   break;
 541 }
 542 
 543 //:: shift right arithmetic
 544 
 545 :(code)
 546 void test_shift_right_arithmetic_r32_with_cl() {
 547   Reg[EBX].i = 26;
 548   Reg[ECX].i = 1;
 549   run(
 550       "== code 0x1\n"  // code segment
 551       // op     ModR/M  SIB   displacement  immediate
 552       "  d3     fb                                    \n"  // shift EBX right by CL bits, while preserving sign
 553       // ModR/M in binary: 11 (direct mode) 111 (subop shift right arithmetic) 011 (dest EBX)
 554   );
 555   CHECK_TRACE_CONTENTS(
 556       "run: operate on r/m32\n"
 557       "run: r/m32 is EBX\n"
 558       "run: subop: shift right by CL bits, while preserving sign\n"
 559       "run: storing 0x0000000d\n"
 560   );
 561 }
 562 
 563 :(before "End Op d3 Subops")
 564 case 7: {  // shift right r/m32 by CL, preserving sign
 565   trace(Callstack_depth+1, "run") << "subop: shift right by CL bits, while preserving sign" << end();
 566   uint8_t count = Reg[ECX].u & 0x1f;
 567   *arg1 = (*arg1 >> count);
 568   ZF = (*arg1 == 0);
 569   SF = (*arg1 < 0);
 570   // OF is only defined if count is 1
 571   if (count == 1) OF = false;
 572   // CF undefined
 573   trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *arg1 << end();
 574   break;
 575 }
 576 
 577 :(code)
 578 void test_shift_right_arithmetic_odd_r32_with_cl() {
 579   Reg[EBX].i = 27;
 580   Reg[ECX].i = 1;
 581   run(
 582       "== code 0x1\n"  // code segment
 583       // op     ModR/M  SIB   displacement  immediate
 584       "  d3     fb                                    \n"  // shift EBX right by CL bits, while preserving sign
 585       // ModR/M in binary: 11 (direct mode) 111 (subop shift right arithmetic) 011 (dest EBX)
 586   );
 587   CHECK_TRACE_CONTENTS(
 588       "run: operate on r/m32\n"
 589       "run: r/m32 is EBX\n"
 590       "run: subop: shift right by CL bits, while preserving sign\n"
 591       // result: 13
 592       "run: storing 0x0000000d\n"
 593   );
 594 }
 595 
 596 void test_shift_right_arithmetic_negative_r32_with_cl() {
 597   Reg[EBX].i = 0xfffffffd;  // -3
 598   Reg[ECX].i = 1;
 599   run(
 600       "== code 0x1\n"  // code segment
 601       // op     ModR/M  SIB   displacement  immediate
 602       "  d3     fb                                    \n"  // shift EBX right by CL bits, while preserving sign
 603       // ModR/M in binary: 11 (direct mode) 111 (subop shift right arithmetic) 011 (dest EBX)
 604   );
 605   CHECK_TRACE_CONTENTS(
 606       "run: operate on r/m32\n"
 607       "run: r/m32 is EBX\n"
 608       "run: subop: shift right by CL bits, while preserving sign\n"
 609       // result: -2
 610       "run: storing 0xfffffffe\n"
 611   );
 612 }
 613 
 614 //:: shift right logical
 615 
 616 :(code)
 617 void test_shift_right_logical_r32_with_cl() {
 618   Reg[EBX].i = 26;
 619   Reg[ECX].i = 1;
 620   run(
 621       "== code 0x1\n"  // code segment
 622       // op     ModR/M  SIB   displacement  immediate
 623       "  d3     eb                                    \n"  // shift EBX right by CL bits, while padding zeroes
 624       // ModR/M in binary: 11 (direct mode) 101 (subop shift right logical) 011 (dest EBX)
 625   );
 626   CHECK_TRACE_CONTENTS(
 627       "run: operate on r/m32\n"
 628       "run: r/m32 is EBX\n"
 629       "run: subop: shift right by CL bits, while padding zeroes\n"
 630       // result: 13
 631       "run: storing 0x0000000d\n"
 632   );
 633 }
 634 
 635 :(before "End Op d3 Subops")
 636 case 5: {  // shift right r/m32 by CL, padding zeroes
 637   trace(Callstack_depth+1, "run") << "subop: shift right by CL bits, while padding zeroes" << end();
 638   uint8_t count = Reg[ECX].u & 0x1f;
 639   // OF is only defined if count is 1
 640   if (count == 1) {
 641     bool msb = (*arg1 & 0x80000000) >> 1;
 642     bool pnsb = (*arg1 & 0x40000000);
 643     OF = (msb != pnsb);
 644   }
 645   uint32_t* uarg1 = reinterpret_cast<uint32_t*>(arg1);
 646   *uarg1 = (*uarg1 >> count);
 647   ZF = (*uarg1 == 0);
 648   // result is always positive by definition
 649   SF = false;
 650   // CF undefined
 651   trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *arg1 << end();
 652   break;
 653 }
 654 
 655 :(code)
 656 void test_shift_right_logical_odd_r32_with_cl() {
 657   Reg[EBX].i = 27;
 658   Reg[ECX].i = 1;
 659   run(
 660       "== code 0x1\n"  // code segment
 661       // op     ModR/M  SIB   displacement  immediate
 662       "  d3     eb                                    \n"  // shift EBX right by CL bits, while padding zeroes
 663       // ModR/M in binary: 11 (direct mode) 101 (subop shift right logical) 011 (dest EBX)
 664   );
 665   CHECK_TRACE_CONTENTS(
 666       "run: operate on r/m32\n"
 667       "run: r/m32 is EBX\n"
 668       "run: subop: shift right by CL bits, while padding zeroes\n"
 669       // result: 13
 670       "run: storing 0x0000000d\n"
 671   );
 672 }
 673 
 674 void test_shift_right_logical_negative_r32_with_cl() {
 675   Reg[EBX].i = 0xfffffffd;
 676   Reg[ECX].i = 1;
 677   run(
 678       "== code 0x1\n"  // code segment
 679       // op     ModR/M  SIB   displacement  immediate
 680       "  d3     eb                                    \n"  // shift EBX right by CL bits, while padding zeroes
 681       // ModR/M in binary: 11 (direct mode) 101 (subop shift right logical) 011 (dest EBX)
 682   );
 683   CHECK_TRACE_CONTENTS(
 684       "run: operate on r/m32\n"
 685       "run: r/m32 is EBX\n"
 686       "run: subop: shift right by CL bits, while padding zeroes\n"
 687       "run: storing 0x7ffffffe\n"
 688   );
 689 }
 690 
 691 //:: and
 692 
 693 :(before "End Initialize Op Names")
 694 put_new(Name, "21", "rm32 = bitwise AND of r32 with rm32 (and)");
 695 
 696 :(code)
 697 void test_and_r32_with_r32() {
 698   Reg[EAX].i = 0x0a0b0c0d;
 699   Reg[EBX].i = 0x000000ff;
 700   run(
 701       "== code 0x1\n"  // code segment
 702       // op     ModR/M  SIB   displacement  immediate
 703       "  21     d8                                    \n"  // and EBX with destination EAX
 704       // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
 705   );
 706   CHECK_TRACE_CONTENTS(
 707       "run: and EBX with r/m32\n"
 708       "run: r/m32 is EAX\n"
 709       "run: storing 0x0000000d\n"
 710   );
 711 }
 712 
 713 :(before "End Single-Byte Opcodes")
 714 case 0x21: {  // and r32 with r/m32
 715   const uint8_t modrm = next();
 716   const uint8_t arg2 = (modrm>>3)&0x7;
 717   trace(Callstack_depth+1, "run") << "and " << rname(arg2) << " with r/m32" << end();
 718   // bitwise ops technically operate on unsigned numbers, but it makes no
 719   // difference
 720   int32_t* signed_arg1 = effective_address(modrm);
 721   *signed_arg1 &= Reg[arg2].i;
 722   trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *signed_arg1 << end();
 723   SF = (*signed_arg1 >> 31);
 724   ZF = (*signed_arg1 == 0);
 725   CF = false;
 726   OF = false;
 727   trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
 728   break;
 729 }
 730 
 731 //:: or
 732 
 733 :(before "End Initialize Op Names")
 734 put_new(Name, "09", "rm32 = bitwise OR of r32 with rm32 (or)");
 735 
 736 :(code)
 737 void test_or_r32_with_r32() {
 738   Reg[EAX].i = 0x0a0b0c0d;
 739   Reg[EBX].i = 0xa0b0c0d0;
 740   run(
 741       "== code 0x1\n"  // code segment
 742       // op     ModR/M  SIB   displacement  immediate
 743       "  09     d8                                    \n"  // or EBX with destination EAX
 744       // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
 745   );
 746   CHECK_TRACE_CONTENTS(
 747       "run: or EBX with r/m32\n"
 748       "run: r/m32 is EAX\n"
 749       "run: storing 0xaabbccdd\n"
 750   );
 751 }
 752 
 753 :(before "End Single-Byte Opcodes")
 754 case 0x09: {  // or r32 with r/m32
 755   const uint8_t modrm = next();
 756   const uint8_t arg2 = (modrm>>3)&0x7;
 757   trace(Callstack_depth+1, "run") << "or " << rname(arg2) << " with r/m32" << end();
 758   // bitwise ops technically operate on unsigned numbers, but it makes no
 759   // difference
 760   int32_t* signed_arg1 = effective_address(modrm);
 761   *signed_arg1 |= Reg[arg2].i;
 762   trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *signed_arg1 << end();
 763   SF = (*signed_arg1 >> 31);
 764   ZF = (*signed_arg1 == 0);
 765   CF = false;
 766   OF = false;
 767   trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
 768   break;
 769 }
 770 
 771 //:: xor
 772 
 773 :(before "End Initialize Op Names")
 774 put_new(Name, "31", "rm32 = bitwise XOR of r32 with rm32 (xor)");
 775 
 776 :(code)
 777 void test_xor_r32_with_r32() {
 778   Reg[EAX].i = 0x0a0b0c0d;
 779   Reg[EBX].i = 0xaabbc0d0;
 780   run(
 781       "== code 0x1\n"  // code segment
 782       // op     ModR/M  SIB   displacement  immediate
 783       "  31     d8                                    \n"  // xor EBX with destination EAX
 784       // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
 785   );
 786   CHECK_TRACE_CONTENTS(
 787       "run: xor EBX with r/m32\n"
 788       "run: r/m32 is EAX\n"
 789       "run: storing 0xa0b0ccdd\n"
 790   );
 791 }
 792 
 793 :(before "End Single-Byte Opcodes")
 794 case 0x31: {  // xor r32 with r/m32
 795   const uint8_t modrm = next();
 796   const uint8_t arg2 = (modrm>>3)&0x7;
 797   trace(Callstack_depth+1, "run") << "xor " << rname(arg2) << " with r/m32" << end();
 798   // bitwise ops technically operate on unsigned numbers, but it makes no
 799   // difference
 800   int32_t* signed_arg1 = effective_address(modrm);
 801   *signed_arg1 ^= Reg[arg2].i;
 802   trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *signed_arg1 << end();
 803   SF = (*signed_arg1 >> 31);
 804   ZF = (*signed_arg1 == 0);
 805   CF = false;
 806   OF = false;
 807   trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
 808   break;
 809 }
 810 
 811 //:: not
 812 
 813 :(code)
 814 void test_not_r32() {
 815   Reg[EBX].i = 0x0f0f00ff;
 816   run(
 817       "== code 0x1\n"  // code segment
 818       // op     ModR/M  SIB   displacement  immediate
 819       "  f7     d3                                    \n"  // not EBX
 820       // ModR/M in binary: 11 (direct mode) 010 (subop not) 011 (dest EBX)
 821   );
 822   CHECK_TRACE_CONTENTS(
 823       "run: operate on r/m32\n"
 824       "run: r/m32 is EBX\n"
 825       "run: subop: not\n"
 826       "run: storing 0xf0f0ff00\n"
 827   );
 828 }
 829 
 830 :(before "End Op f7 Subops")
 831 case 2: {  // not r/m32
 832   trace(Callstack_depth+1, "run") << "subop: not" << end();
 833   *arg1 = ~(*arg1);
 834   trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *arg1 << end();
 835   // no flags affected
 836   break;
 837 }
 838 
 839 //:: compare (cmp)
 840 
 841 :(before "End Initialize Op Names")
 842 put_new(Name, "39", "compare: set SF if rm32 < r32 (cmp)");
 843 
 844 :(code)
 845 void test_compare_r32_with_r32_greater() {
 846   Reg[EAX].i = 0x0a0b0c0d;
 847   Reg[EBX].i = 0x0a0b0c07;
 848   run(
 849       "== code 0x1\n"  // code segment
 850       // op     ModR/M  SIB   displacement  immediate
 851       "  39     d8                                    \n"  // compare EAX with EBX
 852       // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
 853   );
 854   CHECK_TRACE_CONTENTS(
 855       "run: compare r/m32 with EBX\n"
 856       "run: r/m32 is EAX\n"
 857       "run: SF=0; ZF=0; CF=0; OF=0\n"
 858   );
 859 }
 860 
 861 :(before "End Single-Byte Opcodes")
 862 case 0x39: {  // set SF if r/m32 < r32
 863   const uint8_t modrm = next();
 864   const uint8_t reg2 = (modrm>>3)&0x7;
 865   trace(Callstack_depth+1, "run") << "compare r/m32 with " << rname(reg2) << end();
 866   const int32_t* signed_arg1 = effective_address(modrm);
 867   const int32_t signed_difference = *signed_arg1 - Reg[reg2].i;
 868   SF = (signed_difference < 0);
 869   ZF = (signed_difference == 0);
 870   const int64_t signed_full_difference = static_cast<int64_t>(*signed_arg1) - Reg[reg2].i;
 871   OF = (signed_difference != signed_full_difference);
 872   // set CF
 873   const uint32_t unsigned_arg1 = static_cast<uint32_t>(*signed_arg1);
 874   const uint32_t unsigned_difference = unsigned_arg1 - Reg[reg2].u;
 875   const uint64_t unsigned_full_difference = static_cast<uint64_t>(unsigned_arg1) - Reg[reg2].u;
 876   CF = (unsigned_difference != unsigned_full_difference);
 877   trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
 878   break;
 879 }
 880 
 881 :(code)
 882 void test_compare_r32_with_r32_lesser_unsigned_and_signed() {
 883   Reg[EAX].i = 0x0a0b0c07;
 884   Reg[EBX].i = 0x0a0b0c0d;
 885   run(
 886       "== code 0x1\n"  // code segment
 887       // op     ModR/M  SIB   displacement  immediate
 888       "  39     d8                                    \n"  // compare EAX with EBX
 889       // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
 890   );
 891   CHECK_TRACE_CONTENTS(
 892       "run: compare r/m32 with EBX\n"
 893       "run: r/m32 is EAX\n"
 894       "run: SF=1; ZF=0; CF=1; OF=0\n"
 895   );
 896 }
 897 
 898 void test_compare_r32_with_r32_lesser_unsigned_and_signed_due_to_overflow() {
 899   Reg[EAX].i = 0x7fffffff;  // largest positive signed integer
 900   Reg[EBX].i = 0x80000000;  // smallest negative signed integer
 901   run(
 902       "== code 0x1\n"  // code segment
 903       // op     ModR/M  SIB   displacement  immediate
 904       "  39     d8                                    \n"  // compare EAX with EBX
 905       // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
 906   );
 907   CHECK_TRACE_CONTENTS(
 908       "run: compare r/m32 with EBX\n"
 909       "run: r/m32 is EAX\n"
 910       "run: SF=1; ZF=0; CF=1; OF=1\n"
 911   );
 912 }
 913 
 914 void test_compare_r32_with_r32_lesser_signed() {
 915   Reg[EAX].i = 0xffffffff;  // -1
 916   Reg[EBX].i = 0x00000001;  // 1
 917   run(
 918       "== code 0x1\n"  // code segment
 919       // op     ModR/M  SIB   displacement  immediate
 920       "  39     d8                                    \n"  // compare EAX with EBX
 921       // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
 922   );
 923   CHECK_TRACE_CONTENTS(
 924       "run: compare r/m32 with EBX\n"
 925       "run: r/m32 is EAX\n"
 926       "run: SF=1; ZF=0; CF=0; OF=0\n"
 927   );
 928 }
 929 
 930 void test_compare_r32_with_r32_lesser_unsigned() {
 931   Reg[EAX].i = 0x00000001;  // 1
 932   Reg[EBX].i = 0xffffffff;  // -1
 933   run(
 934       "== code 0x1\n"  // code segment
 935       // op     ModR/M  SIB   displacement  immediate
 936       "  39     d8                                    \n"  // compare EAX with EBX
 937       // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
 938   );
 939   CHECK_TRACE_CONTENTS(
 940       "run: compare r/m32 with EBX\n"
 941       "run: r/m32 is EAX\n"
 942       "run: SF=0; ZF=0; CF=1; OF=0\n"
 943   );
 944 }
 945 
 946 void test_compare_r32_with_r32_equal() {
 947   Reg[EAX].i = 0x0a0b0c0d;
 948   Reg[EBX].i = 0x0a0b0c0d;
 949   run(
 950       "== code 0x1\n"  // code segment
 951       // op     ModR/M  SIB   displacement  immediate
 952       "  39     d8                                    \n"  // compare EAX and EBX
 953       // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
 954   );
 955   CHECK_TRACE_CONTENTS(
 956       "run: compare r/m32 with EBX\n"
 957       "run: r/m32 is EAX\n"
 958       "run: SF=0; ZF=1; CF=0; OF=0\n"
 959   );
 960 }
 961 
 962 //:: copy (mov)
 963 
 964 :(before "End Initialize Op Names")
 965 put_new(Name, "89", "copy r32 to rm32 (mov)");
 966 
 967 :(code)
 968 void test_copy_r32_to_r32() {
 969   Reg[EBX].i = 0xaf;
 970   run(
 971       "== code 0x1\n"  // code segment
 972       // op     ModR/M  SIB   displacement  immediate
 973       "  89     d8                                    \n"  // copy EBX to EAX
 974       // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
 975   );
 976   CHECK_TRACE_CONTENTS(
 977       "run: copy EBX to r/m32\n"
 978       "run: r/m32 is EAX\n"
 979       "run: storing 0x000000af\n"
 980   );
 981 }
 982 
 983 :(before "End Single-Byte Opcodes")
 984 case 0x89: {  // copy r32 to r/m32
 985   const uint8_t modrm = next();
 986   const uint8_t rsrc = (modrm>>3)&0x7;
 987   trace(Callstack_depth+1, "run") << "copy " << rname(rsrc) << " to r/m32" << end();
 988   int32_t* dest = effective_address(modrm);
 989   *dest = Reg[rsrc].i;
 990   trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *dest << end();
 991   break;
 992 }
 993 
 994 //:: xchg
 995 
 996 :(before "End Initialize Op Names")
 997 put_new(Name, "87", "swap the contents of r32 and rm32 (xchg)");
 998 
 999 :(code)
1000 void test_xchg_r32_with_r32() {
1001   Reg[EBX].i = 0xaf;
1002   Reg[EAX].i = 0x2e;
1003   run(
1004       "== code 0x1\n"  // code segment
1005       // op     ModR/M  SIB   displacement  immediate
1006       "  87     d8                                    \n"  // exchange EBX with EAX
1007       // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
1008   );
1009   CHECK_TRACE_CONTENTS(
1010       "run: exchange EBX with r/m32\n"
1011       "run: r/m32 is EAX\n"
1012       "run: storing 0x000000af in r/m32\n"
1013       "run: storing 0x0000002e in EBX\n"
1014   );
1015 }
1016 
1017 :(before "End Single-Byte Opcodes")
1018 case 0x87: {  // exchange r32 with r/m32
1019   const uint8_t modrm = next();
1020   const uint8_t reg2 = (modrm>>3)&0x7;
1021   trace(Callstack_depth+1, "run") << "exchange " << rname(reg2) << " with r/m32" << end();
1022   int32_t* arg1 = effective_address(modrm);
1023   const int32_t tmp = *arg1;
1024   *arg1 = Reg[reg2].i;
1025   Reg[reg2].i = tmp;
1026   trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *arg1 << " in r/m32" << end();
1027   trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[reg2].i << " in " << rname(reg2) << end();
1028   break;
1029 }
1030 
1031 //:: increment
1032 
1033 :(before "End Initialize Op Names")
1034 put_new(Name, "40", "increment EAX (inc)");
1035 put_new(Name, "41", "increment ECX (inc)");
1036 put_new(Name, "42", "increment EDX (inc)");
1037 put_new(Name, "43", "increment EBX (inc)");
1038 put_new(Name, "44", "increment ESP (inc)");
1039 put_new(Name, "45", "increment EBP (inc)");
1040 put_new(Name, "46", "increment ESI (inc)");
1041 put_new(Name, "47", "increment EDI (inc)");
1042 
1043 :(code)
1044 void test_increment_r32() {
1045   Reg[ECX].u = 0x1f;
1046   run(
1047       "== code 0x1\n"  // code segment
1048       // op     ModR/M  SIB   displacement  immediate
1049       "  41                                           \n"  // increment ECX
1050   );
1051   CHECK_TRACE_CONTENTS(
1052       "run: increment ECX\n"
1053       "run: storing value 0x00000020\n"
1054   );
1055 }
1056 
1057 :(before "End Single-Byte Opcodes")
1058 case 0x40:
1059 case 0x41:
1060 case 0x42:
1061 case 0x43:
1062 case 0x44:
1063 case 0x45:
1064 case 0x46:
1065 case 0x47: {  // increment r32
1066   const uint8_t reg = op & 0x7;
1067   trace(Callstack_depth+1, "run") << "increment " << rname(reg) << end();
1068   ++Reg[reg].u;
1069   trace(Callstack_depth+1, "run") << "storing value 0x" << HEXWORD << Reg[reg].u << end();
1070   break;
1071 }
1072 
1073 :(before "End Initialize Op Names")
1074 put_new(Name, "ff", "increment/decrement/jump/push/call rm32 based on subop (inc/dec/jmp/push/call)");
1075 
1076 :(code)
1077 void test_increment_rm32() {
1078   Reg[EAX].u = 0x20;
1079   run(
1080       "== code 0x1\n"  // code segment
1081       // op     ModR/M  SIB   displacement  immediate
1082       "  ff     c0                                    \n"  // increment EAX
1083       // ModR/M in binary: 11 (direct mode) 000 (subop inc) 000 (EAX)
1084   );
1085   CHECK_TRACE_CONTENTS(
1086       "run: increment r/m32\n"
1087       "run: r/m32 is EAX\n"
1088       "run: storing value 0x00000021\n"
1089   );
1090 }
1091 
1092 :(before "End Single-Byte Opcodes")
1093 case 0xff: {
1094   const uint8_t modrm = next();
1095   const uint8_t subop = (modrm>>3)&0x7;  // middle 3 'reg opcode' bits
1096   switch (subop) {
1097     case 0: {  // increment r/m32
1098       trace(Callstack_depth+1, "run") << "increment r/m32" << end();
1099       int32_t* arg = effective_address(modrm);
1100       ++*arg;
1101       trace(Callstack_depth+1, "run") << "storing value 0x" << HEXWORD << *arg << end();
1102       break;
1103     }
1104     default:
1105       cerr << "unrecognized subop for ff: " << HEXBYTE << NUM(subop) << '\n';
1106       DUMP("");
1107       exit(1);
1108     // End Op ff Subops
1109   }
1110   break;
1111 }
1112 
1113 //:: decrement
1114 
1115 :(before "End Initialize Op Names")
1116 put_new(Name, "48", "decrement EAX (dec)");
1117 put_new(Name, "49", "decrement ECX (dec)");
1118 put_new(Name, "4a", "decrement EDX (dec)");
1119 put_new(Name, "4b", "decrement EBX (dec)");
1120 put_new(Name, "4c", "decrement ESP (dec)");
1121 put_new(Name, "4d", "decrement EBP (dec)");
1122 put_new(Name, "4e", "decrement ESI (dec)");
1123 put_new(Name, "4f", "decrement EDI (dec)");
1124 
1125 :(code)
1126 void test_decrement_r32() {
1127   Reg[ECX].u = 0x1f;
1128   run(
1129       "== code 0x1\n"  // code segment
1130       // op     ModR/M  SIB   displacement  immediate
1131       "  49                                           \n"  // decrement ECX
1132   );
1133   CHECK_TRACE_CONTENTS(
1134       "run: decrement ECX\n"
1135       "run: storing value 0x0000001e\n"
1136   );
1137 }
1138 
1139 :(before "End Single-Byte Opcodes")
1140 case 0x48:
1141 case 0x49:
1142 case 0x4a:
1143 case 0x4b:
1144 case 0x4c:
1145 case 0x4d:
1146 case 0x4e:
1147 case 0x4f: {  // decrement r32
1148   const uint8_t reg = op & 0x7;
1149   trace(Callstack_depth+1, "run") << "decrement " << rname(reg) << end();
1150   --Reg[reg].u;
1151   trace(Callstack_depth+1, "run") << "storing value 0x" << HEXWORD << Reg[reg].u << end();
1152   break;
1153 }
1154 
1155 :(code)
1156 void test_decrement_rm32() {
1157   Reg[EAX].u = 0x20;
1158   run(
1159       "== code 0x1\n"  // code segment
1160       // op     ModR/M  SIB   displacement  immediate
1161       "  ff     c8                                    \n"  // decrement EAX
1162       // ModR/M in binary: 11 (direct mode) 001 (subop inc) 000 (EAX)
1163   );
1164   CHECK_TRACE_CONTENTS(
1165       "run: decrement r/m32\n"
1166       "run: r/m32 is EAX\n"
1167       "run: storing value 0x0000001f\n"
1168   );
1169 }
1170 
1171 :(before "End Op ff Subops")
1172 case 1: {  // decrement r/m32
1173   trace(Callstack_depth+1, "run") << "decrement r/m32" << end();
1174   int32_t* arg = effective_address(modrm);
1175   --*arg;
1176   trace(Callstack_depth+1, "run") << "storing value 0x" << HEXWORD << *arg << end();
1177   break;
1178 }
1179 
1180 //:: push
1181 
1182 :(before "End Initialize Op Names")
1183 put_new(Name, "50", "push EAX to stack (push)");
1184 put_new(Name, "51", "push ECX to stack (push)");
1185 put_new(Name, "52", "push EDX to stack (push)");
1186 put_new(Name, "53", "push EBX to stack (push)");
1187 put_new(Name, "54", "push ESP to stack (push)");
1188 put_new(Name, "55", "push EBP to stack (push)");
1189 put_new(Name, "56", "push ESI to stack (push)");
1190 put_new(Name, "57", "push EDI to stack (push)");
1191 
1192 :(code)
1193 void test_push_r32() {
1194   Mem.push_back(vma(0xbd000000));  // manually allocate memory
1195   Reg[ESP].u = 0xbd000008;
1196   Reg[EBX].i = 0x0000000a;
1197   run(
1198       "== code 0x1\n"  // code segment
1199       // op     ModR/M  SIB   displacement  immediate
1200       "  53                                           \n"  // push EBX to stack
1201   );
1202   CHECK_TRACE_CONTENTS(
1203       "run: push EBX\n"
1204       "run: decrementing ESP to 0xbd000004\n"
1205       "run: pushing value 0x0000000a\n"
1206   );
1207 }
1208 
1209 :(before "End Single-Byte Opcodes")
1210 case 0x50:
1211 case 0x51:
1212 case 0x52:
1213 case 0x53:
1214 case 0x54:
1215 case 0x55:
1216 case 0x56:
1217 case 0x57: {  // push r32 to stack
1218   uint8_t reg = op & 0x7;
1219   trace(Callstack_depth+1, "run") << "push " << rname(reg) << end();
1220 //?   cerr << "push: " << NUM(reg) << ": " << Reg[reg].u << " => " << Reg[ESP].u << '\n';
1221   push(Reg[reg].u);
1222   break;
1223 }
1224 
1225 //:: pop
1226 
1227 :(before "End Initialize Op Names")
1228 put_new(Name, "58", "pop top of stack to EAX (pop)");
1229 put_new(Name, "59", "pop top of stack to ECX (pop)");
1230 put_new(Name, "5a", "pop top of stack to EDX (pop)");
1231 put_new(Name, "5b", "pop top of stack to EBX (pop)");
1232 put_new(Name, "5c", "pop top of stack to ESP (pop)");
1233 put_new(Name, "5d", "pop top of stack to EBP (pop)");
1234 put_new(Name, "5e", "pop top of stack to ESI (pop)");
1235 put_new(Name, "5f", "pop top of stack to EDI (pop)");
1236 
1237 :(code)
1238 void test_pop_r32() {
1239   Mem.push_back(vma(0xbd000000));  // manually allocate memory
1240   Reg[ESP].u = 0xbd000008;
1241   write_mem_i32(0xbd000008, 0x0000000a);  // ..before this write
1242   run(
1243       "== code 0x1\n"  // code segment
1244       // op     ModR/M  SIB   displacement  immediate
1245       "  5b                                           \n"  // pop stack to EBX
1246       "== data 0x2000\n"  // data segment
1247       "0a 00 00 00\n"  // 0x0000000a
1248   );
1249   CHECK_TRACE_CONTENTS(
1250       "run: pop into EBX\n"
1251       "run: popping value 0x0000000a\n"
1252       "run: incrementing ESP to 0xbd00000c\n"
1253   );
1254 }
1255 
1256 :(before "End Single-Byte Opcodes")
1257 case 0x58:
1258 case 0x59:
1259 case 0x5a:
1260 case 0x5b:
1261 case 0x5c:
1262 case 0x5d:
1263 case 0x5e:
1264 case 0x5f: {  // pop stack into r32
1265   const uint8_t reg = op & 0x7;
1266   trace(Callstack_depth+1, "run") << "pop into " << rname(reg) << end();
1267 //?   cerr << "pop from " << Reg[ESP].u << '\n';
1268   Reg[reg].u = pop();
1269 //?   cerr << "=> " << NUM(reg) << ": " << Reg[reg].u << '\n';
1270   break;
1271 }
1272 :(code)
1273 uint32_t pop() {
1274   const uint32_t result = read_mem_u32(Reg[ESP].u);
1275   trace(Callstack_depth+1, "run") << "popping value 0x" << HEXWORD << result << end();
1276   Reg[ESP].u += 4;
1277   trace(Callstack_depth+1, "run") << "incrementing ESP to 0x" << HEXWORD << Reg[ESP].u << end();
1278   assert(Reg[ESP].u < AFTER_STACK);
1279   return result;
1280 }