# Mu - subx/015immediate_addressing.cc

      1 //: instructions that (immediately) contain an argument to act with
      2
      3 :(before "End Initialize Op Names")
      4 put_new(Name, "81", "combine rm32 with imm32 based on subop (add/sub/and/or/xor/cmp)");
      5
      6 :(scenario add_imm32_to_r32)
      7 % Reg[EBX].i = 1;
      8 == 0x1
      9 # op  ModR/M  SIB   displacement  immediate
     10   81  c3                          0a 0b 0c 0d  # add 0x0d0c0b0a to EBX
     11 # ModR/M in binary: 11 (direct mode) 000 (add imm32) 011 (dest EBX)
     12 +run: combine imm32 with r/m32
     13 +run: r/m32 is EBX
     14 +run: imm32 is 0x0d0c0b0a
     15 +run: subop add
     16 +run: storing 0x0d0c0b0b
     17
     18 :(before "End Single-Byte Opcodes")
     19 case 0x81: {  // combine imm32 with r/m32
     20   trace(90, "run") << "combine imm32 with r/m32" << end();
     21   const uint8_t modrm = next();
     22   int32_t* arg1 = effective_address(modrm);
     23   const int32_t arg2 = next32();
     24   trace(90, "run") << "imm32 is 0x" << HEXWORD << arg2 << end();
     25   const uint8_t subop = (modrm>>3)&0x7;  // middle 3 'reg opcode' bits
     26   switch (subop) {
     27   case 0:
     28     trace(90, "run") << "subop add" << end();
     29     BINARY_ARITHMETIC_OP(+, *arg1, arg2);
     30     break;
     31   // End Op 81 Subops
     32   default:
     33     cerr << "unrecognized sub-opcode after 81: " << NUM(subop) << '\n';
     34     exit(1);
     35   }
     36   break;
     37 }
     38
     39 //:
     40
     41 :(scenario add_imm32_to_mem_at_r32)
     42 % Reg[EBX].i = 0x2000;
     43 == 0x01  # code segment
     44 # op  ModR/M  SIB   displacement  immediate
     45   81  03                          0a 0b 0c 0d  # add 0x0d0c0b0a to *EBX
     46 # ModR/M in binary: 00 (indirect mode) 000 (add imm32) 011 (dest EBX)
     47 == 0x2000  # data segment
     48 01 00 00 00  # 1
     49 +run: combine imm32 with r/m32
     50 +run: effective address is 0x00002000 (EBX)
     51 +run: imm32 is 0x0d0c0b0a
     52 +run: subop add
     53 +run: storing 0x0d0c0b0b
     54
     55 //:: subtract
     56
     57 :(before "End Initialize Op Names")
     58 put_new(Name, "2d", "subtract imm32 from EAX (sub)");
     59
     60 :(scenario subtract_imm32_from_eax)
     61 % Reg[EAX].i = 0x0d0c0baa;
     62 == 0x1
     63 # op  ModR/M  SIB   displacement  immediate
     64   2d                              0a 0b 0c 0d  # subtract 0x0d0c0b0a from EAX
     65 +run: subtract imm32 0x0d0c0b0a from EAX
     66 +run: storing 0x000000a0
     67
     68 :(before "End Single-Byte Opcodes")
     69 case 0x2d: {  // subtract imm32 from EAX
     70   const int32_t arg2 = next32();
     71   trace(90, "run") << "subtract imm32 0x" << HEXWORD << arg2 << " from EAX" << end();
     72   BINARY_ARITHMETIC_OP(-, Reg[EAX].i, arg2);
     73   break;
     74 }
     75
     76 //:
     77
     78 :(scenario subtract_imm32_from_mem_at_r32)
     79 % Reg[EBX].i = 0x2000;
     80 == 0x01  # code segment
     81 # op  ModR/M  SIB   displacement  immediate
     82   81  2b                          01 00 00 00  # subtract 1 from *EBX
     83 # ModR/M in binary: 00 (indirect mode) 101 (subtract imm32) 011 (dest EBX)
     84 == 0x2000  # data segment
     85 0a 00 00 00  # 10
     86 +run: combine imm32 with r/m32
     87 +run: effective address is 0x00002000 (EBX)
     88 +run: imm32 is 0x00000001
     89 +run: subop subtract
     90 +run: storing 0x00000009
     91
     92 :(before "End Op 81 Subops")
     93 case 5: {
     94   trace(90, "run") << "subop subtract" << end();
     95   BINARY_ARITHMETIC_OP(-, *arg1, arg2);
     96   break;
     97 }
     98
     99 //:
    100
    101 :(scenario subtract_imm32_from_r32)
    102 % Reg[EBX].i = 10;
    103 == 0x1
    104 # op  ModR/M  SIB   displacement  immediate
    105   81  eb                          01 00 00 00  # subtract 1 from EBX
    106 # ModR/M in binary: 11 (direct mode) 101 (subtract imm32) 011 (dest EBX)
    107 +run: combine imm32 with r/m32
    108 +run: r/m32 is EBX
    109 +run: imm32 is 0x00000001
    110 +run: subop subtract
    111 +run: storing 0x00000009
    112
    113 //:: and
    114
    115 :(before "End Initialize Op Names")
    116 put_new(Name, "25", "EAX = bitwise AND of imm32 with EAX (and)");
    117
    118 :(scenario and_imm32_with_eax)
    119 % Reg[EAX].i = 0xff;
    120 == 0x1
    121 # op  ModR/M  SIB   displacement  immediate
    122   25                              0a 0b 0c 0d  # and 0x0d0c0b0a with EAX
    123 +run: and imm32 0x0d0c0b0a with EAX
    124 +run: storing 0x0000000a
    125
    126 :(before "End Single-Byte Opcodes")
    127 case 0x25: {  // and imm32 with EAX
    128   const int32_t arg2 = next32();
    129   trace(90, "run") << "and imm32 0x" << HEXWORD << arg2 << " with EAX" << end();
    130   BINARY_BITWISE_OP(&, Reg[EAX].i, arg2);
    131   break;
    132 }
    133
    134 //:
    135
    136 :(scenario and_imm32_with_mem_at_r32)
    137 % Reg[EBX].i = 0x2000;
    138 == 0x01  # code segment
    139 # op  ModR/M  SIB   displacement  immediate
    140   81  23                          0a 0b 0c 0d  # and 0x0d0c0b0a with *EBX
    141 # ModR/M in binary: 00 (indirect mode) 100 (and imm32) 011 (dest EBX)
    142 == 0x2000  # data segment
    143 ff 00 00 00  # 0xff
    144 +run: combine imm32 with r/m32
    145 +run: effective address is 0x00002000 (EBX)
    146 +run: imm32 is 0x0d0c0b0a
    147 +run: subop and
    148 +run: storing 0x0000000a
    149
    150 :(before "End Op 81 Subops")
    151 case 4: {
    152   trace(90, "run") << "subop and" << end();
    153   BINARY_BITWISE_OP(&, *arg1, arg2);
    154   break;
    155 }
    156
    157 //:
    158
    159 :(scenario and_imm32_with_r32)
    160 % Reg[EBX].i = 0xff;
    161 == 0x1
    162 # op  ModR/M  SIB   displacement  immediate
    163   81  e3                          0a 0b 0c 0d  # and 0x0d0c0b0a with EBX
    164 # ModR/M in binary: 11 (direct mode) 100 (and imm32) 011 (dest EBX)
    165 +run: combine imm32 with r/m32
    166 +run: r/m32 is EBX
    167 +run: imm32 is 0x0d0c0b0a
    168 +run: subop and
    169 +run: storing 0x0000000a
    170
    171 //:: or
    172
    173 :(before "End Initialize Op Names")
    174 put_new(Name, "0d", "EAX = bitwise OR of imm32 with EAX (or)");
    175
    176 :(scenario or_imm32_with_eax)
    177 % Reg[EAX].i = 0xd0c0b0a0;
    178 == 0x1
    179 # op  ModR/M  SIB   displacement  immediate
    180   0d                              0a 0b 0c 0d  # or 0x0d0c0b0a with EAX
    181 +run: or imm32 0x0d0c0b0a with EAX
    182 +run: storing 0xddccbbaa
    183
    184 :(before "End Single-Byte Opcodes")
    185 case 0x0d: {  // or imm32 with EAX
    186   const int32_t arg2 = next32();
    187   trace(90, "run") << "or imm32 0x" << HEXWORD << arg2 << " with EAX" << end();
    188   BINARY_BITWISE_OP(|, Reg[EAX].i, arg2);
    189   break;
    190 }
    191
    192 //:
    193
    194 :(scenario or_imm32_with_mem_at_r32)
    195 % Reg[EBX].i = 0x2000;
    196 == 0x01  # code segment
    197 # op  ModR/M  SIB   displacement  immediate
    198   81  0b                          0a 0b 0c 0d  # or 0x0d0c0b0a with *EBX
    199 # ModR/M in binary: 00 (indirect mode) 001 (or imm32) 011 (dest EBX)
    200 == 0x2000  # data segment
    201 a0 b0 c0 d0  # 0xd0c0b0a0
    202 +run: combine imm32 with r/m32
    203 +run: effective address is 0x00002000 (EBX)
    204 +run: imm32 is 0x0d0c0b0a
    205 +run: subop or
    206 +run: storing 0xddccbbaa
    207
    208 :(before "End Op 81 Subops")
    209 case 1: {
    210   trace(90, "run") << "subop or" << end();
    211   BINARY_BITWISE_OP(|, *arg1, arg2);
    212   break;
    213 }
    214
    215 :(scenario or_imm32_with_r32)
    216 % Reg[EBX].i = 0xd0c0b0a0;
    217 == 0x1
    218 # op  ModR/M  SIB   displacement  immediate
    219   81  cb                          0a 0b 0c 0d  # or 0x0d0c0b0a with EBX
    220 # ModR/M in binary: 11 (direct mode) 001 (or imm32) 011 (dest EBX)
    221 +run: combine imm32 with r/m32
    222 +run: r/m32 is EBX
    223 +run: imm32 is 0x0d0c0b0a
    224 +run: subop or
    225 +run: storing 0xddccbbaa
    226
    227 //:: xor
    228
    229 :(before "End Initialize Op Names")
    230 put_new(Name, "35", "EAX = bitwise XOR of imm32 with EAX (xor)");
    231
    232 :(scenario xor_imm32_with_eax)
    233 % Reg[EAX].i = 0xddccb0a0;
    234 == 0x1
    235 # op  ModR/M  SIB   displacement  immediate
    236   35                              0a 0b 0c 0d  # xor 0x0d0c0b0a with EAX
    237 +run: xor imm32 0x0d0c0b0a with EAX
    238 +run: storing 0xd0c0bbaa
    239
    240 :(before "End Single-Byte Opcodes")
    241 case 0x35: {  // xor imm32 with EAX
    242   const int32_t arg2 = next32();
    243   trace(90, "run") << "xor imm32 0x" << HEXWORD << arg2 << " with EAX" << end();
    244   BINARY_BITWISE_OP(^, Reg[EAX].i, arg2);
    245   break;
    246 }
    247
    248 //:
    249
    250 :(scenario xor_imm32_with_mem_at_r32)
    251 % Reg[EBX].i = 0x2000;
    252 == 0x01  # code segment
    253 # op  ModR/M  SIB   displacement  immediate
    254   81  33                          0a 0b 0c 0d  # xor 0x0d0c0b0a with *EBX
    255 # ModR/M in binary: 00 (indirect mode) 110 (xor imm32) 011 (dest EBX)
    256 == 0x2000  # data segment
    257 a0 b0 c0 d0  # 0xd0c0b0a0
    258 +run: combine imm32 with r/m32
    259 +run: effective address is 0x00002000 (EBX)
    260 +run: imm32 is 0x0d0c0b0a
    261 +run: subop xor
    262 +run: storing 0xddccbbaa
    263
    264 :(before "End Op 81 Subops")
    265 case 6: {
    266   trace(90, "run") << "subop xor" << end();
    267   BINARY_BITWISE_OP(^, *arg1, arg2);
    268   break;
    269 }
    270
    271 :(scenario xor_imm32_with_r32)
    272 % Reg[EBX].i = 0xd0c0b0a0;
    273 == 0x1
    274 # op  ModR/M  SIB   displacement  immediate
    275   81  f3                          0a 0b 0c 0d  # xor 0x0d0c0b0a with EBX
    276 # ModR/M in binary: 11 (direct mode) 110 (xor imm32) 011 (dest EBX)
    277 +run: combine imm32 with r/m32
    278 +run: r/m32 is EBX
    279 +run: imm32 is 0x0d0c0b0a
    280 +run: subop xor
    281 +run: storing 0xddccbbaa
    282
    283 //:: compare (cmp)
    284
    285 :(before "End Initialize Op Names")
    286 put_new(Name, "3d", "compare: set SF if EAX < imm32 (cmp)");
    287
    288 :(scenario compare_imm32_with_eax_greater)
    289 % Reg[EAX].i = 0x0d0c0b0a;
    290 == 0x1
    291 # op  ModR/M  SIB   displacement  immediate
    292   3d                              07 0b 0c 0d  # compare 0x0d0c0b07 with EAX
    293 +run: compare EAX and imm32 0x0d0c0b07
    294 +run: SF=0; ZF=0; OF=0
    295
    296 :(before "End Single-Byte Opcodes")
    297 case 0x3d: {  // compare EAX with imm32
    298   const int32_t arg1 = Reg[EAX].i;
    299   const int32_t arg2 = next32();
    300   trace(90, "run") << "compare EAX and imm32 0x" << HEXWORD << arg2 << end();
    301   const int32_t tmp1 = arg1 - arg2;
    302   SF = (tmp1 < 0);
    303   ZF = (tmp1 == 0);
    304   const int64_t tmp2 = arg1 - arg2;
    305   OF = (tmp1 != tmp2);
    306   trace(90, "run") << "SF=" << SF << "; ZF=" << ZF << "; OF=" << OF << end();
    307   break;
    308 }
    309
    310 :(scenario compare_imm32_with_eax_lesser)
    311 % Reg[EAX].i = 0x0d0c0b07;
    312 == 0x1
    313 # op  ModR/M  SIB   displacement  immediate
    314   3d                              0a 0b 0c 0d  # compare 0x0d0c0b0a with EAX
    315 +run: compare EAX and imm32 0x0d0c0b0a
    316 +run: SF=1; ZF=0; OF=0
    317
    318 :(scenario compare_imm32_with_eax_equal)
    319 % Reg[EAX].i = 0x0d0c0b0a;
    320 == 0x1
    321 # op  ModR/M  SIB   displacement  immediate
    322   3d                              0a 0b 0c 0d  # compare 0x0d0c0b0a with EAX
    323 +run: compare EAX and imm32 0x0d0c0b0a
    324 +run: SF=0; ZF=1; OF=0
    325
    326 //:
    327
    328 :(scenario compare_imm32_with_r32_greater)
    329 % Reg[EBX].i = 0x0d0c0b0a;
    330 == 0x1
    331 # op  ModR/M  SIB   displacement  immediate
    332   81  fb                          07 0b 0c 0d  # compare 0x0d0c0b07 with EBX
    333 # ModR/M in binary: 11 (direct mode) 111 (compare imm32) 011 (dest EBX)
    334 +run: combine imm32 with r/m32
    335 +run: r/m32 is EBX
    336 +run: imm32 is 0x0d0c0b07
    337 +run: SF=0; ZF=0; OF=0
    338
    339 :(before "End Op 81 Subops")
    340 case 7: {
    341   trace(90, "run") << "subop compare" << end();
    342   const int32_t tmp1 = *arg1 - arg2;
    343   SF = (tmp1 < 0);
    344   ZF = (tmp1 == 0);
    345   const int64_t tmp2 = *arg1 - arg2;
    346   OF = (tmp1 != tmp2);
    347   trace(90, "run") << "SF=" << SF << "; ZF=" << ZF << "; OF=" << OF << end();
    348   break;
    349 }
    350
    351 :(scenario compare_imm32_with_r32_lesser)
    352 % Reg[EBX].i = 0x0d0c0b07;
    353 == 0x1
    354 # op  ModR/M  SIB   displacement  immediate
    355   81  fb                          0a 0b 0c 0d  # compare 0x0d0c0b0a with EBX
    356 # ModR/M in binary: 11 (direct mode) 111 (compare imm32) 011 (dest EBX)
    357 +run: combine imm32 with r/m32
    358 +run: r/m32 is EBX
    359 +run: imm32 is 0x0d0c0b0a
    360 +run: SF=1; ZF=0; OF=0
    361
    362 :(scenario compare_imm32_with_r32_equal)
    363 % Reg[EBX].i = 0x0d0c0b0a;
    364 == 0x1
    365 # op  ModR/M  SIB   displacement  immediate
    366   81  fb                          0a 0b 0c 0d  # compare 0x0d0c0b0a with EBX
    367 # ModR/M in binary: 11 (direct mode) 111 (compare imm32) 011 (dest EBX)
    368 +run: combine imm32 with r/m32
    369 +run: r/m32 is EBX
    370 +run: imm32 is 0x0d0c0b0a
    371 +run: SF=0; ZF=1; OF=0
    372
    373 :(scenario compare_imm32_with_mem_at_r32_greater)
    374 % Reg[EBX].i = 0x2000;
    375 == 0x01  # code segment
    376 # op  ModR/M  SIB   displacement  immediate
    377   81  3b                          07 0b 0c 0d  # compare 0x0d0c0b07 with *EBX
    378 # ModR/M in binary: 00 (indirect mode) 111 (compare imm32) 011 (dest EBX)
    379 == 0x2000  # data segment
    380 0a 0b 0c 0d  # 0x0d0c0b0a
    381 +run: combine imm32 with r/m32
    382 +run: effective address is 0x00002000 (EBX)
    383 +run: imm32 is 0x0d0c0b07
    384 +run: SF=0; ZF=0; OF=0
    385
    386 :(scenario compare_imm32_with_mem_at_r32_lesser)
    387 % Reg[EBX].i = 0x2000;
    388 == 0x01  # code segment
    389 # op  ModR/M  SIB   displacement  immediate
    390   81  3b                          0a 0b 0c 0d  # compare 0x0d0c0b0a with *EBX
    391 # ModR/M in binary: 00 (indirect mode) 111 (compare imm32) 011 (dest EBX)
    392 == 0x2000  # data segment
    393 07 0b 0c 0d  # 0x0d0c0b07
    394 +run: combine imm32 with r/m32
    395 +run: effective address is 0x00002000 (EBX)
    396 +run: imm32 is 0x0d0c0b0a
    397 +run: SF=1; ZF=0; OF=0
    398
    399 :(scenario compare_imm32_with_mem_at_r32_equal)
    400 % Reg[EBX].i = 0x0d0c0b0a;
    401 % Reg[EBX].i = 0x2000;
    402 == 0x01  # code segment
    403 # op  ModR/M  SIB   displacement  immediate
    404   81  3b                          0a 0b 0c 0d  # compare 0x0d0c0b0a with *EBX
    405 # ModR/M in binary: 00 (indirect mode) 111 (compare imm32) 011 (dest EBX)
    406 == 0x2000  # data segment
    407 0a 0b 0c 0d  # 0x0d0c0b0a
    408 +run: combine imm32 with r/m32
    409 +run: effective address is 0x00002000 (EBX)
    410 +run: imm32 is 0x0d0c0b0a
    411 +run: SF=0; ZF=1; OF=0
    412
    413 //:: copy (mov)
    414
    415 :(before "End Initialize Op Names")
    416 put_new(Name, "b8", "copy imm32 to EAX (mov)");
    417 put_new(Name, "b9", "copy imm32 to ECX (mov)");
    418 put_new(Name, "ba", "copy imm32 to EDX (mov)");
    419 put_new(Name, "bb", "copy imm32 to EBX (mov)");
    420 put_new(Name, "bc", "copy imm32 to ESP (mov)");
    421 put_new(Name, "bd", "copy imm32 to EBP (mov)");
    422 put_new(Name, "be", "copy imm32 to ESI (mov)");
    423 put_new(Name, "bf", "copy imm32 to EDI (mov)");
    424
    425 :(scenario copy_imm32_to_r32)
    426 == 0x1
    427 # op  ModR/M  SIB   displacement  immediate
    428   bb                              0a 0b 0c 0d  # copy 0x0d0c0b0a to EBX
    429 +run: copy imm32 0x0d0c0b0a to EBX
    430
    431 :(before "End Single-Byte Opcodes")
    432 case 0xb8:
    433 case 0xb9:
    434 case 0xba:
    435 case 0xbb:
    436 case 0xbc:
    437 case 0xbd:
    438 case 0xbe:
    439 case 0xbf: {  // copy imm32 to r32
    440   const uint8_t rdest = op & 0x7;
    441   const int32_t src = next32();
    442   trace(90, "run") << "copy imm32 0x" << HEXWORD << src << " to " << rname(rdest) << end();
    443   Reg[rdest].i = src;
    444   break;
    445 }
    446
    447 //:
    448
    449 :(before "End Initialize Op Names")
    450 put_new(Name, "c7", "copy imm32 to rm32 (mov)");
    451
    452 :(scenario copy_imm32_to_mem_at_r32)
    453 % Reg[EBX].i = 0x60;
    454 == 0x1
    455 # op  ModR/M  SIB   displacement  immediate
    456   c7  03                          0a 0b 0c 0d  # copy 0x0d0c0b0a to *EBX
    457 # ModR/M in binary: 00 (indirect mode) 000 (unused) 011 (dest EBX)
    458 +run: copy imm32 to r/m32
    459 +run: effective address is 0x00000060 (EBX)
    460 +run: imm32 is 0x0d0c0b0a
    461
    462 :(before "End Single-Byte Opcodes")
    463 case 0xc7: {  // copy imm32 to r32
    464   const uint8_t modrm = next();
    465   trace(90, "run") << "copy imm32 to r/m32" << end();
    466   int32_t* dest = effective_address(modrm);
    467   const int32_t src = next32();
    468   trace(90, "run") << "imm32 is 0x" << HEXWORD << src << end();
    469   *dest = src;
    470   break;
    471 }
    472
    473 //:: push
    474
    475 :(before "End Initialize Op Names")
    476 put_new(Name, "68", "push imm32 to stack (push)");
    477
    478 :(scenario push_imm32)
    479 % Reg[ESP].u = 0x14;
    480 == 0x1
    481 # op  ModR/M  SIB   displacement  immediate
    482   68                              af 00 00 00  # push *EAX to stack
    483 +run: push imm32 0x000000af
    484 +run: ESP is now 0x00000010
    485 +run: contents at ESP: 0x000000af
    486
    487 :(before "End Single-Byte Opcodes")
    488 case 0x68: {
    489   const uint32_t val = static_cast<uint32_t>(next32());
    490   trace(90, "run") << "push imm32 0x" << HEXWORD << val << end();
    491 //?   cerr << "push: " << val << " => " << Reg[ESP].u << '\n';
    492   push(val);
    493   trace(90, "run") << "ESP is now 0x" << HEXWORD << Reg[ESP].u << end();
    494   trace(90, "run") << "contents at ESP: 0x" << HEXWORD << read_mem_u32(Reg[ESP].u) << end();
    495   break;
    496 }