https://github.com/akkartik/mu/blob/master/subx/015immediate_addressing.cc
  1 //: instructions that (immediately) contain an argument to act with
  2 
  3 :(before "End Initialize Op Names")
  4 put_new(Name, "81", "combine rm32 with imm32 based on subop (add/sub/and/or/xor/cmp)");
  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 with r/m32
 13 +run: r/m32 is EBX
 14 +run: imm32 is 0x0d0c0b0a
 15 +run: subop add
 16 +run: storing 0x0d0c0b0b
 17 
 18 :(before "End Single-Byte Opcodes")
 19 case 0x81: {  // combine imm32 with r/m32
 20   trace(90, "run") << "combine imm32 with r/m32" << end();
 21   const uint8_t modrm = next();
 22   int32_t* arg1 = effective_address(modrm);
 23   const int32_t arg2 = next32();
 24   trace(90, "run") << "imm32 is 0x" << HEXWORD << arg2 << end();
 25   const uint8_t subop = (modrm>>3)&0x7;  // middle 3 'reg opcode' bits
 26   switch (subop) {
 27   case 0:
 28     trace(90, "run") << "subop add" << end();
 29     BINARY_ARITHMETIC_OP(+, *arg1, arg2);
 30     break;
 31   // End Op 81 Subops
 32   default:
 33     cerr << "unrecognized subop for opcode 81: " << NUM(subop) << '\n';
 34     exit(1);
 35   }
 36   break;
 37 }
 38 
 39 //:
 40 
 41 :(scenario add_imm32_to_mem_at_r32)
 42 % Reg[EBX].i = 0x2000;
 43 == 0x01  # code segment
 44 # op  ModR/M  SIB   displacement  immediate
 45   81  03                          0a 0b 0c 0d  # add 0x0d0c0b0a to *EBX
 46 # ModR/M in binary: 00 (indirect mode) 000 (add imm32) 011 (dest EBX)
 47 == 0x2000  # data segment
 48 01 00 00 00  # 1
 49 +run: combine imm32 with r/m32
 50 +run: effective address is 0x00002000 (EBX)
 51 +run: imm32 is 0x0d0c0b0a
 52 +run: subop add
 53 +run: storing 0x0d0c0b0b
 54 
 55 //:: subtract
 56 
 57 :(before "End Initialize Op Names")
 58 put_new(Name, "2d", "subtract imm32 from EAX (sub)");
 59 
 60 :(scenario subtract_imm32_from_eax)
 61 % Reg[EAX].i = 0x0d0c0baa;
 62 == 0x1
 63 # op  ModR/M  SIB   displacement  immediate
 64   2d                              0a 0b 0c 0d  # subtract 0x0d0c0b0a from EAX
 65 +run: subtract imm32 0x0d0c0b0a from EAX
 66 +run: storing 0x000000a0
 67 
 68 :(before "End Single-Byte Opcodes")
 69 case 0x2d: {  // subtract imm32 from EAX
 70   const int32_t arg2 = next32();
 71   trace(90, "run") << "subtract imm32 0x" << HEXWORD << arg2 << " from EAX" << end();
 72   BINARY_ARITHMETIC_OP(-, Reg[EAX].i, arg2);
 73   break;
 74 }
 75 
 76 //:
 77 
 78 :(scenario subtract_imm32_from_mem_at_r32)
 79 % Reg[EBX].i = 0x2000;
 80 == 0x01  # code segment
 81 # op  ModR/M  SIB   displacement  immediate
 82   81  2b                          01 00 00 00  # subtract 1 from *EBX
 83 # ModR/M in binary: 00 (indirect mode) 101 (subtract imm32) 011 (dest EBX)
 84 == 0x2000  # data segment
 85 0a 00 00 00  # 10
 86 +run: combine imm32 with r/m32
 87 +run: effective address is 0x00002000 (EBX)
 88 +run: imm32 is 0x00000001
 89 +run: subop subtract
 90 +run: storing 0x00000009
 91 
 92 :(before "End Op 81 Subops")
 93 case 5: {
 94   trace(90, "run") << "subop subtract" << end();
 95   BINARY_ARITHMETIC_OP(-, *arg1, arg2);
 96   break;
 97 }
 98 
 99 //:
100 
101 :(scenario subtract_imm32_from_r32)
102 % Reg[EBX].i = 10;
103 == 0x1
104 # op  ModR/M  SIB   displacement  immediate
105   81  eb                          01 00 00 00  # subtract 1 from EBX
106 # ModR/M in binary: 11 (direct mode) 101 (subtract imm32) 011 (dest EBX)
107 +run: combine imm32 with r/m32
108 +run: r/m32 is EBX
109 +run: imm32 is 0x00000001
110 +run: subop subtract
111 +run: storing 0x00000009
112 
113 //:: shift left
114 
115 :(before "End Initialize Op Names")
116 put_new(Name, "c1", "shift rm32 by imm8 bits depending on subop (sal/sar/shl/shr)");
117 
118 :(scenario shift_left_r32_with_imm8)
119 % Reg[EBX].i = 13;
120 == 0x1
121 # op  ModR/M  SIB   displacement  immediate
122   c1  e3                          01          # negate EBX
123 # ModR/M in binary: 11 (direct mode) 100 (subop shift left) 011 (dest EBX)
124 +run: operate on r/m32
125 +run: r/m32 is EBX
126 +run: subop: shift left by CL bits
127 +run: storing 0x0000001a
128 
129 :(before "End Single-Byte Opcodes")
130 case 0xc1: {
131   const uint8_t modrm = next();
132   trace(90, "run") << "operate on r/m32" << end();
133   int32_t* arg1 = effective_address(modrm);
134   const uint8_t subop = (modrm>>3)&0x7;  // middle 3 'reg opcode' bits
135   switch (subop) {
136   case 4: {  // shift left r/m32 by CL
137     trace(90, "run") << "subop: shift left by CL bits" << end();
138     uint8_t count = next() & 0x1f;
139     // OF is only defined if count is 1
140     if (count == 1) {
141       bool msb = (*arg1 & 0x80000000) >> 1;
142       bool pnsb = (*arg1 & 0x40000000);
143       OF = (msb != pnsb);
144     }
145     *arg1 = (*arg1 << count);
146     ZF = (*arg1 == 0);
147     SF = (*arg1 < 0);
148     trace(90, "run") << "storing 0x" << HEXWORD << *arg1 << end();
149     break;
150   }
151   // End Op c1 Subops
152   default:
153     cerr << "unrecognized subop for opcode c1: " << NUM(subop) << '\n';
154     exit(1);
155   }
156   break;
157 }
158 
159 //:: shift right arithmetic
160 
161 :(scenario shift_right_arithmetic_r32_with_imm8)
162 % Reg[EBX].i = 26;
163 == 0x1
164 # op  ModR/M  SIB   displacement  immediate
165   c1  fb                          01          # negate EBX
166 # ModR/M in binary: 11 (direct mode) 111 (subop shift right arithmetic) 011 (dest EBX)
167 +run: operate on r/m32
168 +run: r/m32 is EBX
169 +run: subop: shift right by CL bits, while preserving sign
170 +run: storing 0x0000000d
171 
172 :(before "End Op c1 Subops")
173 case 7: {  // shift right r/m32 by CL, preserving sign
174   trace(90, "run") << "subop: shift right by CL bits, while preserving sign" << end();
175   uint8_t count = next() & 0x1f;
176   *arg1 = (*arg1 >> count);
177   ZF = (*arg1 == 0);
178   SF = (*arg1 < 0);
179   // OF is only defined if count is 1
180   if (count == 1) OF = false;
181   trace(90, "run") << "storing 0x" << HEXWORD << *arg1 << end();
182   break;
183 }
184 
185 :(scenario shift_right_arithmetic_odd_r32_with_imm8)
186 % Reg[EBX].i = 27;
187 == 0x1
188 # op  ModR/M  SIB   displacement  immediate
189   c1  fb                          01          # negate EBX
190 # ModR/M in binary: 11 (direct mode) 111 (subop shift right arithmetic) 011 (dest EBX)
191 +run: operate on r/m32
192 +run: r/m32 is EBX
193 +run: subop: shift right by CL bits, while preserving sign
194 # result: 13
195 +run: storing 0x0000000d
196 
197 :(scenario shift_right_arithmetic_negative_r32_with_imm8)
198 % Reg[EBX].i = 0xfffffffd;  // -3
199 == 0x1
200 # op  ModR/M  SIB   displacement  immediate
201   c1  fb                          01          # negate EBX
202 # ModR/M in binary: 11 (direct mode) 111 (subop shift right arithmetic) 011 (dest EBX)
203 +run: operate on r/m32
204 +run: r/m32 is EBX
205 +run: subop: shift right by CL bits, while preserving sign
206 # result: -2
207 +run: storing 0xfffffffe
208 
209 //:: shift right logical
210 
211 :(scenario shift_right_logical_r32_with_imm8)
212 % Reg[EBX].i = 26;
213 == 0x1
214 # op  ModR/M  SIB   displacement  immediate
215   c1  eb                          01          # negate EBX
216 # ModR/M in binary: 11 (direct mode) 101 (subop shift right logical) 011 (dest EBX)
217 +run: operate on r/m32
218 +run: r/m32 is EBX
219 +run: subop: shift right by CL bits, while padding zeroes
220 +run: storing 0x0000000d
221 
222 :(before "End Op c1 Subops")
223 case 5: {  // shift right r/m32 by CL, preserving sign
224   trace(90, "run") << "subop: shift right by CL bits, while padding zeroes" << end();
225   uint8_t count = next() & 0x1f;
226   // OF is only defined if count is 1
227   if (count == 1) {
228     bool msb = (*arg1 & 0x80000000) >> 1;
229     bool pnsb = (*arg1 & 0x40000000);
230     OF = (msb != pnsb);
231   }
232   uint32_t* uarg1 = reinterpret_cast<uint32_t*>(arg1);
233   *uarg1 = (*uarg1 >> count);
234   ZF = (*uarg1 == 0);
235   // result is always positive by definition
236   SF = false;
237   trace(90, "run") << "storing 0x" << HEXWORD << *arg1 << end();
238   break;
239 }
240 
241 :(scenario shift_right_logical_odd_r32_with_imm8)
242 % Reg[EBX].i = 27;
243 == 0x1
244 # op  ModR/M  SIB   displacement  immediate
245   c1  eb                          01          # negate EBX
246 # ModR/M in binary: 11 (direct mode) 101 (subop shift right logical) 011 (dest EBX)
247 +run: operate on r/m32
248 +run: r/m32 is EBX
249 +run: subop: shift right by CL bits, while padding zeroes
250 # result: 13
251 +run: storing 0x0000000d
252 
253 :(scenario shift_right_logical_negative_r32_with_imm8)
254 % Reg[EBX].i = 0xfffffffd;
255 == 0x1
256 # op  ModR/M  SIB   displacement  immediate
257   c1  eb                          01          # negate EBX
258 # ModR/M in binary: 11 (direct mode) 101 (subop shift right logical) 011 (dest EBX)
259 +run: operate on r/m32
260 +run: r/m32 is EBX
261 +run: subop: shift right by CL bits, while padding zeroes
262 +run: storing 0x7ffffffe
263 
264 //:: and
265 
266 :(before "End Initialize Op Names")
267 put_new(Name, "25", "EAX = bitwise AND of imm32 with EAX (and)");
268 
269 :(scenario and_imm32_with_eax)
270 % Reg[EAX].i = 0xff;
271 == 0x1
272 # op  ModR/M  SIB   displacement  immediate
273   25                              0a 0b 0c 0d  # and 0x0d0c0b0a with EAX
274 +run: and imm32 0x0d0c0b0a with EAX
275 +run: storing 0x0000000a
276 
277 :(before "End Single-Byte Opcodes")
278 case 0x25: {  // and imm32 with EAX
279   const int32_t arg2 = next32();
280   trace(90, "run") << "and imm32 0x" << HEXWORD << arg2 << " with EAX" << end();
281   BINARY_BITWISE_OP(&, Reg[EAX].i, arg2);
282   break;
283 }
284 
285 //:
286 
287 :(scenario and_imm32_with_mem_at_r32)
288 % Reg[EBX].i = 0x2000;
289 == 0x01  # code segment
290 # op  ModR/M  SIB   displacement  immediate
291   81  23                          0a 0b 0c 0d  # and 0x0d0c0b0a with *EBX
292 # ModR/M in binary: 00 (indirect mode) 100 (and imm32) 011 (dest EBX)
293 == 0x2000  # data segment
294 ff 00 00 00  # 0xff
295 +run: combine imm32 with r/m32
296 +run: effective address is 0x00002000 (EBX)
297 +run: imm32 is 0x0d0c0b0a
298 +run: subop and
299 +run: storing 0x0000000a
300 
301 :(before "End Op 81 Subops")
302 case 4: {
303   trace(90, "run") << "subop and" << end();
304   BINARY_BITWISE_OP(&, *arg1, arg2);
305   break;
306 }
307 
308 //:
309 
310 :(scenario and_imm32_with_r32)
311 % Reg[EBX].i = 0xff;
312 == 0x1
313 # op  ModR/M  SIB   displacement  immediate
314   81  e3                          0a 0b 0c 0d  # and 0x0d0c0b0a with EBX
315 # ModR/M in binary: 11 (direct mode) 100 (and imm32) 011 (dest EBX)
316 +run: combine imm32 with r/m32
317 +run: r/m32 is EBX
318 +run: imm32 is 0x0d0c0b0a
319 +run: subop and
320 +run: storing 0x0000000a
321 
322 //:: or
323 
324 :(before "End Initialize Op Names")
325 put_new(Name, "0d", "EAX = bitwise OR of imm32 with EAX (or)");
326 
327 :(scenario or_imm32_with_eax)
328 % Reg[EAX].i = 0xd0c0b0a0;
329 == 0x1
330 # op  ModR/M  SIB   displacement  immediate
331   0d                              0a 0b 0c 0d  # or 0x0d0c0b0a with EAX
332 +run: or imm32 0x0d0c0b0a with EAX
333 +run: storing 0xddccbbaa
334 
335 :(before "End Single-Byte Opcodes")
336 case 0x0d: {  // or imm32 with EAX
337   const int32_t arg2 = next32();
338   trace(90, "run") << "or imm32 0x" << HEXWORD << arg2 << " with EAX" << end();
339   BINARY_BITWISE_OP(|, Reg[EAX].i, arg2);
340   break;
341 }
342 
343 //:
344 
345 :(scenario or_imm32_with_mem_at_r32)
346 % Reg[EBX].i = 0x2000;
347 == 0x01  # code segment
348 # op  ModR/M  SIB   displacement  immediate
349   81  0b                          0a 0b 0c 0d  # or 0x0d0c0b0a with *EBX
350 # ModR/M in binary: 00 (indirect mode) 001 (or imm32) 011 (dest EBX)
351 == 0x2000  # data segment
352 a0 b0 c0 d0  # 0xd0c0b0a0
353 +run: combine imm32 with r/m32
354 +run: effective address is 0x00002000 (EBX)
355 +run: imm32 is 0x0d0c0b0a
356 +run: subop or
357 +run: storing 0xddccbbaa
358 
359 :(before "End Op 81 Subops")
360 case 1: {
361   trace(90, "run") << "subop or" << end();
362   BINARY_BITWISE_OP(|, *arg1, arg2);
363   break;
364 }
365 
366 :(scenario or_imm32_with_r32)
367 % Reg[EBX].i = 0xd0c0b0a0;
368 == 0x1
369 # op  ModR/M  SIB   displacement  immediate
370   81  cb                          0a 0b 0c 0d  # or 0x0d0c0b0a with EBX
371 # ModR/M in binary: 11 (direct mode) 001 (or imm32) 011 (dest EBX)
372 +run: combine imm32 with r/m32
373 +run: r/m32 is EBX
374 +run: imm32 is 0x0d0c0b0a
375 +run: subop or
376 +run: storing 0xddccbbaa
377 
378 //:: xor
379 
380 :(before "End Initialize Op Names")
381 put_new(Name, "35", "EAX = bitwise XOR of imm32 with EAX (xor)");
382 
383 :(scenario xor_imm32_with_eax)
384 % Reg[EAX].i = 0xddccb0a0;
385 == 0x1
386 # op  ModR/M  SIB   displacement  immediate
387   35                              0a 0b 0c 0d  # xor 0x0d0c0b0a with EAX
388 +run: xor imm32 0x0d0c0b0a with EAX
389 +run: storing 0xd0c0bbaa
390 
391 :(before "End Single-Byte Opcodes")
392 case 0x35: {  // xor imm32 with EAX
393   const int32_t arg2 = next32();
394   trace(90, "run") << "xor imm32 0x" << HEXWORD << arg2 << " with EAX" << end();
395   BINARY_BITWISE_OP(^, Reg[EAX].i, arg2);
396   break;
397 }
398 
399 //:
400 
401 :(scenario xor_imm32_with_mem_at_r32)
402 % Reg[EBX].i = 0x2000;
403 == 0x01  # code segment
404 # op  ModR/M  SIB   displacement  immediate
405   81  33                          0a 0b 0c 0d  # xor 0x0d0c0b0a with *EBX
406 # ModR/M in binary: 00 (indirect mode) 110 (xor imm32) 011 (dest EBX)
407 == 0x2000  # data segment
408 a0 b0 c0 d0  # 0xd0c0b0a0
409 +run: combine imm32 with r/m32
410 +run: effective address is 0x00002000 (EBX)
411 +run: imm32 is 0x0d0c0b0a
412 +run: subop xor
413 +run: storing 0xddccbbaa
414 
415 :(before "End Op 81 Subops")
416 case 6: {
417   trace(90, "run") << "subop xor" << end();
418   BINARY_BITWISE_OP(^, *arg1, arg2);
419   break;
420 }
421 
422 :(scenario xor_imm32_with_r32)
423 % Reg[EBX].i = 0xd0c0b0a0;
424 == 0x1
425 # op  ModR/M  SIB   displacement  immediate
426   81  f3                          0a 0b 0c 0d  # xor 0x0d0c0b0a with EBX
427 # ModR/M in binary: 11 (direct mode) 110 (xor imm32) 011 (dest EBX)
428 +run: combine imm32 with r/m32
429 +run: r/m32 is EBX
430 +run: imm32 is 0x0d0c0b0a
431 +run: subop xor
432 +run: storing 0xddccbbaa
433 
434 //:: compare (cmp)
435 
436 :(before "End Initialize Op Names")
437 put_new(Name, "3d", "compare: set SF if EAX < imm32 (cmp)");
438 
439 :(scenario compare_imm32_with_eax_greater)
440 % Reg[EAX].i = 0x0d0c0b0a;
441 == 0x1
442 # op  ModR/M  SIB   displacement  immediate
443   3d                              07 0b 0c 0d  # compare 0x0d0c0b07 with EAX
444 +run: compare EAX and imm32 0x0d0c0b07
445 +run: SF=0; ZF=0; OF=0
446 
447 :(before "End Single-Byte Opcodes")
448 case 0x3d: {  // compare EAX with imm32
449   const int32_t arg1 = Reg[EAX].i;
450   const int32_t arg2 = next32();
451   trace(90, "run") << "compare EAX and imm32 0x" << HEXWORD << arg2 << end();
452   const int32_t tmp1 = arg1 - arg2;
453   SF = (tmp1 < 0);
454   ZF = (tmp1 == 0);
455   const int64_t tmp2 = arg1 - arg2;
456   OF = (tmp1 != tmp2);
457   trace(90, "run") << "SF=" << SF << "; ZF=" << ZF << "; OF=" << OF << end();
458   break;
459 }
460 
461 :(scenario compare_imm32_with_eax_lesser)
462 % Reg[EAX].i = 0x0d0c0b07;
463 == 0x1
464 # op  ModR/M  SIB   displacement  immediate
465   3d                              0a 0b 0c 0d  # compare 0x0d0c0b0a with EAX
466 +run: compare EAX and imm32 0x0d0c0b0a
467 +run: SF=1; ZF=0; OF=0
468 
469 :(scenario compare_imm32_with_eax_equal)
470 % Reg[EAX].i = 0x0d0c0b0a;
471 == 0x1
472 # op  ModR/M  SIB   displacement  immediate
473   3d                              0a 0b 0c 0d  # compare 0x0d0c0b0a with EAX
474 +run: compare EAX and imm32 0x0d0c0b0a
475 +run: SF=0; ZF=1; OF=0
476 
477 //:
478 
479 :(scenario compare_imm32_with_r32_greater)
480 % Reg[EBX].i = 0x0d0c0b0a;
481 == 0x1
482 # op  ModR/M  SIB   displacement  immediate
483   81  fb                          07 0b 0c 0d  # compare 0x0d0c0b07 with EBX
484 # ModR/M in binary: 11 (direct mode) 111 (compare imm32) 011 (dest EBX)
485 +run: combine imm32 with r/m32
486 +run: r/m32 is EBX
487 +run: imm32 is 0x0d0c0b07
488 +run: SF=0; ZF=0; OF=0
489 
490 :(before "End Op 81 Subops")
491 case 7: {
492   trace(90, "run") << "subop compare" << end();
493   const int32_t tmp1 = *arg1 - arg2;
494   SF = (tmp1 < 0);
495   ZF = (tmp1 == 0);
496   const int64_t tmp2 = *arg1 - arg2;
497   OF = (tmp1 != tmp2);
498   trace(90, "run") << "SF=" << SF << "; ZF=" << ZF << "; OF=" << OF << end();
499   break;
500 }
501 
502 :(scenario compare_imm32_with_r32_lesser)
503 % Reg[EBX].i = 0x0d0c0b07;
504 == 0x1
505 # op  ModR/M  SIB   displacement  immediate
506   81  fb                          0a 0b 0c 0d  # compare 0x0d0c0b0a with EBX
507 # ModR/M in binary: 11 (direct mode) 111 (compare imm32) 011 (dest EBX)
508 +run: combine imm32 with r/m32
509 +run: r/m32 is EBX
510 +run: imm32 is 0x0d0c0b0a
511 +run: SF=1; ZF=0; OF=0
512 
513 :(scenario compare_imm32_with_r32_equal)
514 % Reg[EBX].i = 0x0d0c0b0a;
515 == 0x1
516 # op  ModR/M  SIB   displacement  immediate
517   81  fb                          0a 0b 0c 0d  # compare 0x0d0c0b0a with EBX
518 # ModR/M in binary: 11 (direct mode) 111 (compare imm32) 011 (dest EBX)
519 +run: combine imm32 with r/m32
520 +run: r/m32 is EBX
521 +run: imm32 is 0x0d0c0b0a
522 +run: SF=0; ZF=1; OF=0
523 
524 :(scenario compare_imm32_with_mem_at_r32_greater)
525 % Reg[EBX].i = 0x2000;
526 == 0x01  # code segment
527 # op  ModR/M  SIB   displacement  immediate
528   81  3b                          07 0b 0c 0d  # compare 0x0d0c0b07 with *EBX
529 # ModR/M in binary: 00 (indirect mode) 111 (compare imm32) 011 (dest EBX)
530 == 0x2000  # data segment
531 0a 0b 0c 0d  # 0x0d0c0b0a
532 +run: combine imm32 with r/m32
533 +run: effective address is 0x00002000 (EBX)
534 +run: imm32 is 0x0d0c0b07
535 +run: SF=0; ZF=0; OF=0
536 
537 :(scenario compare_imm32_with_mem_at_r32_lesser)
538 % Reg[EBX].i = 0x2000;
539 == 0x01  # code segment
540 # op  ModR/M  SIB   displacement  immediate
541   81  3b                          0a 0b 0c 0d  # compare 0x0d0c0b0a with *EBX
542 # ModR/M in binary: 00 (indirect mode) 111 (compare imm32) 011 (dest EBX)
543 == 0x2000  # data segment
544 07 0b 0c 0d  # 0x0d0c0b07
545 +run: combine imm32 with r/m32
546 +run: effective address is 0x00002000 (EBX)
547 +run: imm32 is 0x0d0c0b0a
548 +run: SF=1; ZF=0; OF=0
549 
550 :(scenario compare_imm32_with_mem_at_r32_equal)
551 % Reg[EBX].i = 0x0d0c0b0a;
552 % Reg[EBX].i = 0x2000;
553 == 0x01  # code segment
554 # op  ModR/M  SIB   displacement  immediate
555   81  3b                          0a 0b 0c 0d  # compare 0x0d0c0b0a with *EBX
556 # ModR/M in binary: 00 (indirect mode) 111 (compare imm32) 011 (dest EBX)
557 == 0x2000  # data segment
558 0a 0b 0c 0d  # 0x0d0c0b0a
559 +run: combine imm32 with r/m32
560 +run: effective address is 0x00002000 (EBX)
561 +run: imm32 is 0x0d0c0b0a
562 +run: SF=0; ZF=1; OF=0
563 
564 //:: copy (mov)
565 
566 :(before "End Initialize Op Names")
567 put_new(Name, "b8", "copy imm32 to EAX (mov)");
568 put_new(Name, "b9", "copy imm32 to ECX (mov)");
569 put_new(Name, "ba", "copy imm32 to EDX (mov)");
570 put_new(Name, "bb", "copy imm32 to EBX (mov)");
571 put_new(Name, "bc", "copy imm32 to ESP (mov)");
572 put_new(Name, "bd", "copy imm32 to EBP (mov)");
573 put_new(Name, "be", "copy imm32 to ESI (mov)");
574 put_new(Name, "bf", "copy imm32 to EDI (mov)");
575 
576 :(scenario copy_imm32_to_r32)
577 == 0x1
578 # op  ModR/M  SIB   displacement  immediate
579   bb                              0a 0b 0c 0d  # copy 0x0d0c0b0a to EBX
580 +run: copy imm32 0x0d0c0b0a to EBX
581 
582 :(before "End Single-Byte Opcodes")
583 case 0xb8:
584 case 0xb9:
585 case 0xba:
586 case 0xbb:
587 case 0xbc:
588 case 0xbd:
589 case 0xbe:
590 case 0xbf: {  // copy imm32 to r32
591   const uint8_t rdest = op & 0x7;
592   const int32_t src = next32();
593   trace(90, "run") << "copy imm32 0x" << HEXWORD << src << " to " << rname(rdest) << end();
594   Reg[rdest].i = src;
595   break;
596 }
597 
598 //:
599 
600 :(before "End Initialize Op Names")
601 put_new(Name, "c7", "copy imm32 to rm32 (mov)");
602 
603 :(scenario copy_imm32_to_mem_at_r32)
604 % Reg[EBX].i = 0x60;
605 == 0x1
606 # op  ModR/M  SIB   displacement  immediate
607   c7  03                          0a 0b 0c 0d  # copy 0x0d0c0b0a to *EBX
608 # ModR/M in binary: 00 (indirect mode) 000 (unused) 011 (dest EBX)
609 +run: copy imm32 to r/m32
610 +run: effective address is 0x00000060 (EBX)
611 +run: imm32 is 0x0d0c0b0a
612 
613 :(before "End Single-Byte Opcodes")
614 case 0xc7: {  // copy imm32 to r32
615   const uint8_t modrm = next();
616   trace(90, "run") << "copy imm32 to r/m32" << end();
617   const uint8_t subop = (modrm>>3)&0x7;  // middle 3 'reg opcode' bits
618   if (subop != 0) {
619     cerr << "unrecognized subop for opcode c7: " << NUM(subop) << " (only 0/copy currently implemented)\n";
620     exit(1);
621   }
622   int32_t* dest = effective_address(modrm);
623   const int32_t src = next32();
624   trace(90, "run") << "imm32 is 0x" << HEXWORD << src << end();
625   *dest = src;
626   break;
627 }
628 
629 //:: push
630 
631 :(before "End Initialize Op Names")
632 put_new(Name, "68", "push imm32 to stack (push)");
633 
634 :(scenario push_imm32)
635 % Reg[ESP].u = 0x14;
636 == 0x1
637 # op  ModR/M  SIB   displacement  immediate
638   68                              af 00 00 00  # push *EAX to stack
639 +run: push imm32 0x000000af
640 +run: ESP is now 0x00000010
641 +run: contents at ESP: 0x000000af
642 
643 :(before "End Single-Byte Opcodes")
644 case 0x68: {
645   const uint32_t val = static_cast<uint32_t>(next32());
646   trace(90, "run") << "push imm32 0x" << HEXWORD << val << end();
647 //?   cerr << "push: " << val << " => " << Reg[ESP].u << '\n';
648   push(val);
649   trace(90, "run") << "ESP is now 0x" << HEXWORD << Reg[ESP].u << end();
650   trace(90, "run") << "contents at ESP: 0x" << HEXWORD << read_mem_u32(Reg[ESP].u) << end();
651   break;
652 }