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 }