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