https://github.com/akkartik/mu/blob/main/linux/bootstrap/018jump_disp32.cc

      1 //: jump to 32-bit offset
      2
      3 //:: jump
      4
      5 :(before "End Initialize Op Names")
      6 put_new(Name, "e9", "jump disp32 bytes away (jmp)");
      7
      8 :(code)
      9 void test_jump_disp32() {
     10   run(
     11       "== code 0x1\n"
     12       // op     ModR/M  SIB   displacement  immediate
     13       "  e9                   05 00 00 00               \n"  // skip 1 instruction
     14       "  05                                 00 00 00 01 \n"
     15       "  05                                 00 00 00 02 \n"
     16   );
     17   CHECK_TRACE_CONTENTS(
     18       "run: 0x00000001 opcode: e9\n"
     19       "run: jump 5\n"
     20       "run: 0x0000000b opcode: 05\n"
     21   );
     22   CHECK_TRACE_DOESNT_CONTAIN("run: 0x00000006 opcode: 05");
     23 }
     24
     25 :(before "End Single-Byte Opcodes")
     26 case 0xe9: {  // jump disp32
     27   const int32_t offset = next32();
     28   trace(Callstack_depth+1, "run") << "jump " << offset << end();
     29   EIP += offset;
     30   break;
     31 }
     32
     33 //:: jump if equal/zero
     34
     35 :(before "End Initialize Op Names")
     36 put_new(Name_0f, "84", "jump disp32 bytes away if equal, if ZF is set (jcc/jz/je)");
     37
     38 :(code)
     39 void test_je_disp32_success() {
     40   ZF = true;
     41   run(
     42       "== code 0x1\n"
     43       // op     ModR/M  SIB   displacement  immediate
     44       "  0f 84                05 00 00 00               \n"  // skip 1 instruction
     45       "  05                                 00 00 00 01 \n"
     46       "  05                                 00 00 00 02 \n"
     47   );
     48   CHECK_TRACE_CONTENTS(
     49       "run: 0x00000001 opcode: 0f\n"
     50       "run: jump 5\n"
     51       "run: 0x0000000c opcode: 05\n"
     52   );
     53   CHECK_TRACE_DOESNT_CONTAIN("run: 0x00000007 opcode: 05");
     54 }
     55
     56 :(before "End Two-Byte Opcodes Starting With 0f")
     57 case 0x84: {  // jump disp32 if ZF
     58   const int32_t offset = next32();
     59   if (ZF) {
     60     trace(Callstack_depth+1, "run") << "jump " << offset << end();
     61     EIP += offset;
     62   }
     63   break;
     64 }
     65
     66 :(code)
     67 void test_je_disp32_fail() {
     68   ZF = false;
     69   run(
     70       "== code 0x1\n"
     71       // op     ModR/M  SIB   displacement  immediate
     72       "  0f 84                05 00 00 00               \n"  // skip 1 instruction
     73       "  05                                 00 00 00 01 \n"
     74       "  05                                 00 00 00 02 \n"
     75   );
     76   CHECK_TRACE_CONTENTS(
     77       "run: 0x00000001 opcode: 0f\n"
     78       "run: 0x00000007 opcode: 05\n"
     79       "run: 0x0000000c opcode: 05\n"
     80   );
     81   CHECK_TRACE_DOESNT_CONTAIN("run: jump 5");
     82 }
     83
     84 //:: jump if not equal/not zero
     85
     86 :(before "End Initialize Op Names")
     87 put_new(Name_0f, "85", "jump disp32 bytes away if not equal, if ZF is not set (jcc/jnz/jne)");
     88
     89 :(code)
     90 void test_jne_disp32_success() {
     91   ZF = false;
     92   run(
     93       "== code 0x1\n"
     94       // op     ModR/M  SIB   displacement  immediate
     95       "  0f 85                05 00 00 00               \n"  // skip 1 instruction
     96       "  05                                 00 00 00 01 \n"
     97       "  05                                 00 00 00 02 \n"
     98   );
     99   CHECK_TRACE_CONTENTS(
    100       "run: 0x00000001 opcode: 0f\n"
    101       "run: jump 5\n"
    102       "run: 0x0000000c opcode: 05\n"
    103   );
    104   CHECK_TRACE_DOESNT_CONTAIN("run: 0x00000007 opcode: 05");
    105 }
    106
    107 :(before "End Two-Byte Opcodes Starting With 0f")
    108 case 0x85: {  // jump disp32 if !ZF
    109   const int32_t offset = next32();
    110   if (!ZF) {
    111     trace(Callstack_depth+1, "run") << "jump " << offset << end();
    112     EIP += offset;
    113   }
    114   break;
    115 }
    116
    117 :(code)
    118 void test_jne_disp32_fail() {
    119   ZF = true;
    120   run(
    121       "== code 0x1\n"
    122       // op     ModR/M  SIB   displacement  immediate
    123       "  0f 85                05 00 00 00               \n"  // skip 1 instruction
    124       "  05                                 00 00 00 01 \n"
    125       "  05                                 00 00 00 02 \n"
    126   );
    127   CHECK_TRACE_CONTENTS(
    128       "run: 0x00000001 opcode: 0f\n"
    129       "run: 0x00000007 opcode: 05\n"
    130       "run: 0x0000000c opcode: 05\n"
    131   );
    132   CHECK_TRACE_DOESNT_CONTAIN("run: jump 5");
    133 }
    134
    135 //:: jump if greater
    136
    137 :(before "End Initialize Op Names")
    138 put_new(Name_0f, "8f", "jump disp32 bytes away if greater, if ZF is unset and SF == OF (jcc/jg/jnle)");
    139 put_new(Name_0f, "87", "jump disp32 bytes away if greater (addr, float), if ZF is unset and CF is unset (jcc/ja/jnbe)");
    140
    141 :(code)
    142 void test_jg_disp32_success() {
    143   ZF = false;
    144   SF = false;
    145   OF = false;
    146   run(
    147       "== code 0x1\n"
    148       // op     ModR/M  SIB   displacement  immediate
    149       "  0f 8f                05 00 00 00               \n"  // skip 1 instruction
    150       "  05                                 00 00 00 01 \n"
    151       "  05                                 00 00 00 02 \n"
    152   );
    153   CHECK_TRACE_CONTENTS(
    154       "run: 0x00000001 opcode: 0f\n"
    155       "run: jump 5\n"
    156       "run: 0x0000000c opcode: 05\n"
    157   );
    158   CHECK_TRACE_DOESNT_CONTAIN("run: 0x00000007 opcode: 05");
    159 }
    160
    161 :(before "End Two-Byte Opcodes Starting With 0f")
    162 case 0x8f: {  // jump disp32 if !SF and !ZF
    163   const int32_t offset = next32();
    164   if (!ZF && SF == OF) {
    165     trace(Callstack_depth+1, "run") << "jump " << offset << end();
    166     EIP += offset;
    167   }
    168   break;
    169 }
    170 case 0x87: {  // jump disp32 if !CF and !ZF
    171   const int32_t offset = next32();
    172   if (!CF && !ZF) {
    173     trace(Callstack_depth+1, "run") << "jump " << offset << end();
    174     EIP += offset;
    175   }
    176   break;
    177 }
    178
    179 :(code)
    180 void test_jg_disp32_fail() {
    181   ZF = false;
    182   SF = true;
    183   OF = false;
    184   run(
    185       "== code 0x1\n"
    186       // op     ModR/M  SIB   displacement  immediate
    187       "  0f 8f                05 00 00 00               \n"  // skip 1 instruction
    188       "  05                                 00 00 00 01 \n"
    189       "  05                                 00 00 00 02 \n"
    190   );
    191   CHECK_TRACE_CONTENTS(
    192       "run: 0x00000001 opcode: 0f\n"
    193       "run: 0x00000007 opcode: 05\n"
    194       "run: 0x0000000c opcode: 05\n"
    195   );
    196   CHECK_TRACE_DOESNT_CONTAIN("run: jump 5");
    197 }
    198
    199 //:: jump if greater or equal
    200
    201 :(before "End Initialize Op Names")
    202 put_new(Name_0f, "8d", "jump disp32 bytes away if greater or equal, if SF == OF (jcc/jge/jnl)");
    203 put_new(Name_0f, "83", "jump disp32 bytes away if greater or equal (addr, float), if CF is unset (jcc/jae/jnb)");
    204
    205 :(code)
    206 void test_jge_disp32_success() {
    207   SF = false;
    208   OF = false;
    209   run(
    210       "== code 0x1\n"
    211       // op     ModR/M  SIB   displacement  immediate
    212       "  0f 8d                05 00 00 00               \n"  // skip 1 instruction
    213       "  05                                 00 00 00 01 \n"
    214       "  05                                 00 00 00 02 \n"
    215   );
    216   CHECK_TRACE_CONTENTS(
    217       "run: 0x00000001 opcode: 0f\n"
    218       "run: jump 5\n"
    219       "run: 0x0000000c opcode: 05\n"
    220   );
    221   CHECK_TRACE_DOESNT_CONTAIN("run: 0x00000007 opcode: 05");
    222 }
    223
    224 :(before "End Two-Byte Opcodes Starting With 0f")
    225 case 0x8d: {  // jump disp32 if !SF
    226   const int32_t offset = next32();
    227   if (SF == OF) {
    228     trace(Callstack_depth+1, "run") << "jump " << offset << end();
    229     EIP += offset;
    230   }
    231   break;
    232 }
    233 case 0x83: {  // jump disp32 if !CF
    234   const int32_t offset = next32();
    235   if (!CF) {
    236     trace(Callstack_depth+1, "run") << "jump " << offset << end();
    237     EIP += offset;
    238   }
    239   break;
    240 }
    241
    242 :(code)
    243 void test_jge_disp32_fail() {
    244   SF = true;
    245   OF = false;
    246   run(
    247       "== code 0x1\n"
    248       // op     ModR/M  SIB   displacement  immediate
    249       "  0f 8d                05 00 00 00               \n"  // skip 1 instruction
    250       "  05                                 00 00 00 01 \n"
    251       "  05                                 00 00 00 02 \n"
    252   );
    253   CHECK_TRACE_CONTENTS(
    254       "run: 0x00000001 opcode: 0f\n"
    255       "run: 0x00000007 opcode: 05\n"
    256       "run: 0x0000000c opcode: 05\n"
    257   );
    258   CHECK_TRACE_DOESNT_CONTAIN("run: jump 5");
    259 }
    260
    261 //:: jump if lesser
    262
    263 :(before "End Initialize Op Names")
    264 put_new(Name_0f, "8c", "jump disp32 bytes away if lesser, if SF != OF (jcc/jl/jnge)");
    265 put_new(Name_0f, "82", "jump disp32 bytes away if lesser (addr, float), if CF is set (jcc/jb/jnae)");
    266
    267 :(code)
    268 void test_jl_disp32_success() {
    269   ZF = false;
    270   SF = true;
    271   OF = false;
    272   run(
    273       "== code 0x1\n"
    274       // op     ModR/M  SIB   displacement  immediate
    275       "  0f 8c                05 00 00 00               \n"  // skip 1 instruction
    276       "  05                                 00 00 00 01 \n"
    277       "  05                                 00 00 00 02 \n"
    278   );
    279   CHECK_TRACE_CONTENTS(
    280       "run: 0x00000001 opcode: 0f\n"
    281       "run: jump 5\n"
    282       "run: 0x0000000c opcode: 05\n"
    283   );
    284   CHECK_TRACE_DOESNT_CONTAIN("run: 0x00000007 opcode: 05");
    285 }
    286
    287 :(before "End Two-Byte Opcodes Starting With 0f")
    288 case 0x8c: {  // jump disp32 if SF and !ZF
    289   const int32_t offset = next32();
    290   if (SF != OF) {
    291     trace(Callstack_depth+1, "run") << "jump " << offset << end();
    292     EIP += offset;
    293   }
    294   break;
    295 }
    296 case 0x82: {  // jump disp32 if CF
    297   const int32_t offset = next32();
    298   if (CF) {
    299     trace(Callstack_depth+1, "run") << "jump " << offset << end();
    300     EIP += offset;
    301   }
    302   break;
    303 }
    304
    305 :(code)
    306 void test_jl_disp32_fail() {
    307   ZF = false;
    308   SF = false;
    309   OF = false;
    310   run(
    311       "== code 0x1\n"
    312       // op     ModR/M  SIB   displacement  immediate
    313       "  0f 8c                05 00 00 00               \n"  // skip 1 instruction
    314       "  05                                 00 00 00 01 \n"
    315       "  05                                 00 00 00 02 \n"
    316   );
    317   CHECK_TRACE_CONTENTS(
    318       "run: 0x00000001 opcode: 0f\n"
    319       "run: 0x00000007 opcode: 05\n"
    320       "run: 0x0000000c opcode: 05\n"
    321   );
    322   CHECK_TRACE_DOESNT_CONTAIN("run: jump 5");
    323 }
    324
    325 //:: jump if lesser or equal
    326
    327 :(before "End Initialize Op Names")
    328 put_new(Name_0f, "8e", "jump disp32 bytes away if lesser or equal, if ZF is set or SF != OF (jcc/jle/jng)");
    329 put_new(Name_0f, "86", "jump disp32 bytes away if lesser or equal (addr, float), if ZF is set or CF is set (jcc/jbe/jna)");
    330
    331 :(code)
    332 void test_jle_disp32_equal() {
    333   ZF = true;
    334   SF = false;
    335   OF = false;
    336   run(
    337       "== code 0x1\n"
    338       // op     ModR/M  SIB   displacement  immediate
    339       "  0f 8e                05 00 00 00               \n"  // skip 1 instruction
    340       "  05                                 00 00 00 01 \n"
    341       "  05                                 00 00 00 02 \n"
    342   );
    343   CHECK_TRACE_CONTENTS(
    344       "run: 0x00000001 opcode: 0f\n"
    345       "run: jump 5\n"
    346       "run: 0x0000000c opcode: 05\n"
    347   );
    348   CHECK_TRACE_DOESNT_CONTAIN("run: 0x00000007 opcode: 05");
    349 }
    350
    351 :(code)
    352 void test_jle_disp32_lesser() {
    353   ZF = false;
    354   SF = true;
    355   OF = false;
    356   run(
    357       "== code 0x1\n"
    358       // op     ModR/M  SIB   displacement  immediate
    359       "  0f 8e                05 00 00 00               \n"  // skip 1 instruction
    360       "  05                                 00 00 00 01 \n"
    361       "  05                                 00 00 00 02 \n"
    362   );
    363   CHECK_TRACE_CONTENTS(
    364       "run: 0x00000001 opcode: 0f\n"
    365       "run: jump 5\n"
    366       "run: 0x0000000c opcode: 05\n"
    367   );
    368   CHECK_TRACE_DOESNT_CONTAIN("run: 0x00000007 opcode: 05");
    369 }
    370
    371 :(before "End Two-Byte Opcodes Starting With 0f")
    372 case 0x8e: {  // jump disp32 if SF or ZF
    373   const int32_t offset = next32();
    374   if (ZF || SF != OF) {
    375     trace(Callstack_depth+1, "run") << "jump " << offset << end();
    376     EIP += offset;
    377   }
    378   break;
    379 }
    380 case 0x86: {  // jump disp32 if ZF or CF
    381   const int32_t offset = next32();
    382   if (ZF || CF) {
    383     trace(Callstack_depth+1, "run") << "jump " << offset << end();
    384     EIP += offset;
    385   }
    386   break;
    387 }
    388
    389 :(code)
    390 void test_jle_disp32_greater() {
    391   ZF = false;
    392   SF = false;
    393   OF = false;
    394   run(
    395       "== code 0x1\n"
    396       // op     ModR/M  SIB   displacement  immediate
    397       "  0f 8e                05 00 00 00               \n"  // skip 1 instruction
    398       "  05                                 00 00 00 01 \n"
    399       "  05                                 00 00 00 02 \n"
    400   );
    401   CHECK_TRACE_CONTENTS(
    402       "run: 0x00000001 opcode: 0f\n"
    403       "run: 0x00000007 opcode: 05\n"
    404       "run: 0x0000000c opcode: 05\n"
    405   );
    406   CHECK_TRACE_DOESNT_CONTAIN("run: jump 5");
    407 }
    408
    409 //:: jump if overflow
    410
    411 :(before "End Initialize Op Names")
    412 put_new(Name_0f, "80", "jump disp32 bytes away if OF is set (jcc/jo)");
    413 put_new(Name_0f, "81", "jump disp32 bytes away if OF is unset (jcc/jno)");
    414
    415 :(before "End Two-Byte Opcodes Starting With 0f")
    416 case 0x80: {  // jump disp8 if OF is set
    417   const int32_t offset = next32();
    418   if (OF) {
    419     trace(Callstack_depth+1, "run") << "jump " << NUM(offset) << end();
    420     EIP += offset;
    421   }
    422   break;
    423 }
    424 case 0x81: {  // jump disp8 if OF is unset
    425   const int32_t offset = next32();
    426   if (!OF) {
    427     trace(Callstack_depth+1, "run") << "jump " << NUM(offset) << end();
    428     EIP += offset;
    429   }
    430   break;
    431 }