https://github.com/akkartik/mu/blob/master/subx/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       "== 0x1\n"  // code segment
 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       "== 0x1\n"  // code segment
 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 " << NUM(offset) << end();
 61     EIP += offset;
 62   }
 63   break;
 64 }
 65 
 66 :(code)
 67 void test_je_disp32_fail() {
 68   ZF = false;
 69   run(
 70       "== 0x1\n"  // code segment
 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       "== 0x1\n"  // code segment
 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 unless ZF
109   const int32_t offset = next32();
110   if (!ZF) {
111     trace(Callstack_depth+1, "run") << "jump " << NUM(offset) << end();
112     EIP += offset;
113   }
114   break;
115 }
116 
117 :(code)
118 void test_jne_disp32_fail() {
119   ZF = true;
120   run(
121       "== 0x1\n"  // code segment
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 
140 :(code)
141 void test_jg_disp32_success() {
142   ZF = false;
143   SF = false;
144   OF = false;
145   run(
146       "== 0x1\n"  // code segment
147       // op     ModR/M  SIB   displacement  immediate
148       "  0f 8f                05 00 00 00               \n"  // skip 1 instruction
149       "  05                                 00 00 00 01 \n"
150       "  05                                 00 00 00 02 \n"
151   );
152   CHECK_TRACE_CONTENTS(
153       "run: 0x00000001 opcode: 0f\n"
154       "run: jump 5\n"
155       "run: 0x0000000c opcode: 05\n"
156   );
157   CHECK_TRACE_DOESNT_CONTAIN("run: 0x00000007 opcode: 05");
158 }
159 
160 :(before "End Two-Byte Opcodes Starting With 0f")
161 case 0x8f: {  // jump disp32 if !SF and !ZF
162   const int32_t offset = next32();
163   if (!ZF && SF == OF) {
164     trace(Callstack_depth+1, "run") << "jump " << NUM(offset) << end();
165     EIP += offset;
166   }
167   break;
168 }
169 
170 :(code)
171 void test_jg_disp32_fail() {
172   ZF = false;
173   SF = true;
174   OF = false;
175   run(
176       "== 0x1\n"  // code segment
177       // op     ModR/M  SIB   displacement  immediate
178       "  0f 8f                05 00 00 00               \n"  // skip 1 instruction
179       "  05                                 00 00 00 01 \n"
180       "  05                                 00 00 00 02 \n"
181   );
182   CHECK_TRACE_CONTENTS(
183       "run: 0x00000001 opcode: 0f\n"
184       "run: 0x00000007 opcode: 05\n"
185       "run: 0x0000000c opcode: 05\n"
186   );
187   CHECK_TRACE_DOESNT_CONTAIN("run: jump 5");
188 }
189 
190 //:: jump if greater or equal
191 
192 :(before "End Initialize Op Names")
193 put_new(Name_0f, "8d", "jump disp32 bytes away if greater or equal, if SF == OF (jcc/jge/jnl)");
194 
195 :(code)
196 void test_jge_disp32_success() {
197   SF = false;
198   OF = false;
199   run(
200       "== 0x1\n"  // code segment
201       // op     ModR/M  SIB   displacement  immediate
202       "  0f 8d                05 00 00 00               \n"  // skip 1 instruction
203       "  05                                 00 00 00 01 \n"
204       "  05                                 00 00 00 02 \n"
205   );
206   CHECK_TRACE_CONTENTS(
207       "run: 0x00000001 opcode: 0f\n"
208       "run: jump 5\n"
209       "run: 0x0000000c opcode: 05\n"
210   );
211   CHECK_TRACE_DOESNT_CONTAIN("run: 0x00000007 opcode: 05");
212 }
213 
214 :(before "End Two-Byte Opcodes Starting With 0f")
215 case 0x8d: {  // jump disp32 if !SF
216   const int32_t offset = next32();
217   if (SF == OF) {
218     trace(Callstack_depth+1, "run") << "jump " << NUM(offset) << end();
219     EIP += offset;
220   }
221   break;
222 }
223 
224 :(code)
225 void test_jge_disp32_fail() {
226   SF = true;
227   OF = false;
228   run(
229       "== 0x1\n"  // code segment
230       // op     ModR/M  SIB   displacement  immediate
231       "  0f 8d                05 00 00 00               \n"  // skip 1 instruction
232       "  05                                 00 00 00 01 \n"
233       "  05                                 00 00 00 02 \n"
234   );
235   CHECK_TRACE_CONTENTS(
236       "run: 0x00000001 opcode: 0f\n"
237       "run: 0x00000007 opcode: 05\n"
238       "run: 0x0000000c opcode: 05\n"
239   );
240   CHECK_TRACE_DOESNT_CONTAIN("run: jump 5");
241 }
242 
243 //:: jump if lesser
244 
245 :(before "End Initialize Op Names")
246 put_new(Name_0f, "8c", "jump disp32 bytes away if lesser, if SF != OF (jcc/jl/jnge)");
247 
248 :(code)
249 void test_jl_disp32_success() {
250   ZF = false;
251   SF = true;
252   OF = false;
253   run(
254       "== 0x1\n"  // code segment
255       // op     ModR/M  SIB   displacement  immediate
256       "  0f 8c                05 00 00 00               \n"  // skip 1 instruction
257       "  05                                 00 00 00 01 \n"
258       "  05                                 00 00 00 02 \n"
259   );
260   CHECK_TRACE_CONTENTS(
261       "run: 0x00000001 opcode: 0f\n"
262       "run: jump 5\n"
263       "run: 0x0000000c opcode: 05\n"
264   );
265   CHECK_TRACE_DOESNT_CONTAIN("run: 0x00000007 opcode: 05");
266 }
267 
268 :(before "End Two-Byte Opcodes Starting With 0f")
269 case 0x8c: {  // jump disp32 if SF and !ZF
270   const int32_t offset = next32();
271   if (SF != OF) {
272     trace(Callstack_depth+1, "run") << "jump " << NUM(offset) << end();
273     EIP += offset;
274   }
275   break;
276 }
277 
278 :(code)
279 void test_jl_disp32_fail() {
280   ZF = false;
281   SF = false;
282   OF = false;
283   run(
284       "== 0x1\n"  // code segment
285       // op     ModR/M  SIB   displacement  immediate
286       "  0f 8c                05 00 00 00               \n"  // skip 1 instruction
287       "  05                                 00 00 00 01 \n"
288       "  05                                 00 00 00 02 \n"
289   );
290   CHECK_TRACE_CONTENTS(
291       "run: 0x00000001 opcode: 0f\n"
292       "run: 0x00000007 opcode: 05\n"
293       "run: 0x0000000c opcode: 05\n"
294   );
295   CHECK_TRACE_DOESNT_CONTAIN("run: jump 5");
296 }
297 
298 //:: jump if lesser or equal
299 
300 :(before "End Initialize Op Names")
301 put_new(Name_0f, "8e", "jump disp32 bytes away if lesser or equal, if ZF is set or SF != OF (jcc/jle/jng)");
302 
303 :(code)
304 void test_jle_disp32_equal() {
305   ZF = true;
306   SF = false;
307   OF = false;
308   run(
309       "== 0x1\n"  // code segment
310       // op     ModR/M  SIB   displacement  immediate
311       "  0f 8e                05 00 00 00               \n"  // skip 1 instruction
312       "  05                                 00 00 00 01 \n"
313       "  05                                 00 00 00 02 \n"
314   );
315   CHECK_TRACE_CONTENTS(
316       "run: 0x00000001 opcode: 0f\n"
317       "run: jump 5\n"
318       "run: 0x0000000c opcode: 05\n"
319   );
320   CHECK_TRACE_DOESNT_CONTAIN("run: 0x00000007 opcode: 05");
321 }
322 
323 :(code)
324 void test_jle_disp32_lesser() {
325   ZF = false;
326   SF = true;
327   OF = false;
328   run(
329       "== 0x1\n"  // code segment
330       // op     ModR/M  SIB   displacement  immediate
331       "  0f 8e                05 00 00 00               \n"  // skip 1 instruction
332       "  05                                 00 00 00 01 \n"
333       "  05                                 00 00 00 02 \n"
334   );
335   CHECK_TRACE_CONTENTS(
336       "run: 0x00000001 opcode: 0f\n"
337       "run: jump 5\n"
338       "run: 0x0000000c opcode: 05\n"
339   );
340   CHECK_TRACE_DOESNT_CONTAIN("run: 0x00000007 opcode: 05");
341 }
342 
343 :(before "End Two-Byte Opcodes Starting With 0f")
344 case 0x8e: {  // jump disp32 if SF or ZF
345   const int32_t offset = next32();
346   if (ZF || SF != OF) {
347     trace(Callstack_depth+1, "run") << "jump " << NUM(offset) << end();
348     EIP += offset;
349   }
350   break;
351 }
352 
353 :(code)
354 void test_jle_disp32_greater() {
355   ZF = false;
356   SF = false;
357   OF = false;
358   run(
359       "== 0x1\n"  // code segment
360       // op     ModR/M  SIB   displacement  immediate
361       "  0f 8e                05 00 00 00               \n"  // skip 1 instruction
362       "  05                                 00 00 00 01 \n"
363       "  05                                 00 00 00 02 \n"
364   );
365   CHECK_TRACE_CONTENTS(
366       "run: 0x00000001 opcode: 0f\n"
367       "run: 0x00000007 opcode: 05\n"
368       "run: 0x0000000c opcode: 05\n"
369   );
370   CHECK_TRACE_DOESNT_CONTAIN("run: jump 5");
371 }