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