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