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 sub-opcode after 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 //:: and
114 
115 :(before "End Initialize Op Names")
116 put_new(Name, "25", "EAX = bitwise AND of imm32 with EAX (and)");
117 
118 :(scenario and_imm32_with_eax)
119 % Reg[EAX].i = 0xff;
120 == 0x1
121 # op  ModR/M  SIB   displacement  immediate
122   25                              0a 0b 0c 0d  # and 0x0d0c0b0a with EAX
123 +run: and imm32 0x0d0c0b0a with EAX
124 +run: storing 0x0000000a
125 
126 :(before "End Single-Byte Opcodes")
127 case 0x25: {  // and imm32 with EAX
128   const int32_t arg2 = next32();
129   trace(90, "run") << "and imm32 0x" << HEXWORD << arg2 << " with EAX" << end();
130   BINARY_BITWISE_OP(&, Reg[EAX].i, arg2);
131   break;
132 }
133 
134 //:
135 
136 :(scenario and_imm32_with_mem_at_r32)
137 % Reg[EBX].i = 0x2000;
138 == 0x01  # code segment
139 # op  ModR/M  SIB   displacement  immediate
140   81  23                          0a 0b 0c 0d  # and 0x0d0c0b0a with *EBX
141 # ModR/M in binary: 00 (indirect mode) 100 (and imm32) 011 (dest EBX)
142 == 0x2000  # data segment
143 ff 00 00 00  # 0xff
144 +run: combine imm32 with r/m32
145 +run: effective address is 0x00002000 (EBX)
146 +run: imm32 is 0x0d0c0b0a
147 +run: subop and
148 +run: storing 0x0000000a
149 
150 :(before "End Op 81 Subops")
151 case 4: {
152   trace(90, "run") << "subop and" << end();
153   BINARY_BITWISE_OP(&, *arg1, arg2);
154   break;
155 }
156 
157 //:
158 
159 :(scenario and_imm32_with_r32)
160 % Reg[EBX].i = 0xff;
161 == 0x1
162 # op  ModR/M  SIB   displacement  immediate
163   81  e3                          0a 0b 0c 0d  # and 0x0d0c0b0a with EBX
164 # ModR/M in binary: 11 (direct mode) 100 (and imm32) 011 (dest EBX)
165 +run: combine imm32 with r/m32
166 +run: r/m32 is EBX
167 +run: imm32 is 0x0d0c0b0a
168 +run: subop and
169 +run: storing 0x0000000a
170 
171 //:: or
172 
173 :(before "End Initialize Op Names")
174 put_new(Name, "0d", "EAX = bitwise OR of imm32 with EAX (or)");
175 
176 :(scenario or_imm32_with_eax)
177 % Reg[EAX].i = 0xd0c0b0a0;
178 == 0x1
179 # op  ModR/M  SIB   displacement  immediate
180   0d                              0a 0b 0c 0d  # or 0x0d0c0b0a with EAX
181 +run: or imm32 0x0d0c0b0a with EAX
182 +run: storing 0xddccbbaa
183 
184 :(before "End Single-Byte Opcodes")
185 case 0x0d: {  // or imm32 with EAX
186   const int32_t arg2 = next32();
187   trace(90, "run") << "or imm32 0x" << HEXWORD << arg2 << " with EAX" << end();
188   BINARY_BITWISE_OP(|, Reg[EAX].i, arg2);
189   break;
190 }
191 
192 //:
193 
194 :(scenario or_imm32_with_mem_at_r32)
195 % Reg[EBX].i = 0x2000;
196 == 0x01  # code segment
197 # op  ModR/M  SIB   displacement  immediate
198   81  0b                          0a 0b 0c 0d  # or 0x0d0c0b0a with *EBX
199 # ModR/M in binary: 00 (indirect mode) 001 (or imm32) 011 (dest EBX)
200 == 0x2000  # data segment
201 a0 b0 c0 d0  # 0xd0c0b0a0
202 +run: combine imm32 with r/m32
203 +run: effective address is 0x00002000 (EBX)
204 +run: imm32 is 0x0d0c0b0a
205 +run: subop or
206 +run: storing 0xddccbbaa
207 
208 :(before "End Op 81 Subops")
209 case 1: {
210   trace(90, "run") << "subop or" << end();
211   BINARY_BITWISE_OP(|, *arg1, arg2);
212   break;
213 }
214 
215 :(scenario or_imm32_with_r32)
216 % Reg[EBX].i = 0xd0c0b0a0;
217 == 0x1
218 # op  ModR/M  SIB   displacement  immediate
219   81  cb                          0a 0b 0c 0d  # or 0x0d0c0b0a with EBX
220 # ModR/M in binary: 11 (direct mode) 001 (or imm32) 011 (dest EBX)
221 +run: combine imm32 with r/m32
222 +run: r/m32 is EBX
223 +run: imm32 is 0x0d0c0b0a
224 +run: subop or
225 +run: storing 0xddccbbaa
226 
227 //:: xor
228 
229 :(before "End Initialize Op Names")
230 put_new(Name, "35", "EAX = bitwise XOR of imm32 with EAX (xor)");
231 
232 :(scenario xor_imm32_with_eax)
233 % Reg[EAX].i = 0xddccb0a0;
234 == 0x1
235 # op  ModR/M  SIB   displacement  immediate
236   35                              0a 0b 0c 0d  # xor 0x0d0c0b0a with EAX
237 +run: xor imm32 0x0d0c0b0a with EAX
238 +run: storing 0xd0c0bbaa
239 
240 :(before "End Single-Byte Opcodes")
241 case 0x35: {  // xor imm32 with EAX
242   const int32_t arg2 = next32();
243   trace(90, "run") << "xor imm32 0x" << HEXWORD << arg2 << " with EAX" << end();
244   BINARY_BITWISE_OP(^, Reg[EAX].i, arg2);
245   break;
246 }
247 
248 //:
249 
250 :(scenario xor_imm32_with_mem_at_r32)
251 % Reg[EBX].i = 0x2000;
252 == 0x01  # code segment
253 # op  ModR/M  SIB   displacement  immediate
254   81  33                          0a 0b 0c 0d  # xor 0x0d0c0b0a with *EBX
255 # ModR/M in binary: 00 (indirect mode) 110 (xor imm32) 011 (dest EBX)
256 == 0x2000  # data segment
257 a0 b0 c0 d0  # 0xd0c0b0a0
258 +run: combine imm32 with r/m32
259 +run: effective address is 0x00002000 (EBX)
260 +run: imm32 is 0x0d0c0b0a
261 +run: subop xor
262 +run: storing 0xddccbbaa
263 
264 :(before "End Op 81 Subops")
265 case 6: {
266   trace(90, "run") << "subop xor" << end();
267   BINARY_BITWISE_OP(^, *arg1, arg2);
268   break;
269 }
270 
271 :(scenario xor_imm32_with_r32)
272 % Reg[EBX].i = 0xd0c0b0a0;
273 == 0x1
274 # op  ModR/M  SIB   displacement  immediate
275   81  f3                          0a 0b 0c 0d  # xor 0x0d0c0b0a with EBX
276 # ModR/M in binary: 11 (direct mode) 110 (xor imm32) 011 (dest EBX)
277 +run: combine imm32 with r/m32
278 +run: r/m32 is EBX
279 +run: imm32 is 0x0d0c0b0a
280 +run: subop xor
281 +run: storing 0xddccbbaa
282 
283 //:: compare (cmp)
284 
285 :(before "End Initialize Op Names")
286 put_new(Name, "3d", "compare: set SF if EAX < imm32 (cmp)");
287 
288 :(scenario compare_imm32_with_eax_greater)
289 % Reg[EAX].i = 0x0d0c0b0a;
290 == 0x1
291 # op  ModR/M  SIB   displacement  immediate
292   3d                              07 0b 0c 0d  # compare 0x0d0c0b07 with EAX
293 +run: compare EAX and imm32 0x0d0c0b07
294 +run: SF=0; ZF=0; OF=0
295 
296 :(before "End Single-Byte Opcodes")
297 case 0x3d: {  // compare EAX with imm32
298   const int32_t arg1 = Reg[EAX].i;
299   const int32_t arg2 = next32();
300   trace(90, "run") << "compare EAX and imm32 0x" << HEXWORD << arg2 << end();
301   const int32_t tmp1 = arg1 - arg2;
302   SF = (tmp1 < 0);
303   ZF = (tmp1 == 0);
304   const int64_t tmp2 = arg1 - arg2;
305   OF = (tmp1 != tmp2);
306   trace(90, "run") << "SF=" << SF << "; ZF=" << ZF << "; OF=" << OF << end();
307   break;
308 }
309 
310 :(scenario compare_imm32_with_eax_lesser)
311 % Reg[EAX].i = 0x0d0c0b07;
312 == 0x1
313 # op  ModR/M  SIB   displacement  immediate
314   3d                              0a 0b 0c 0d  # compare 0x0d0c0b0a with EAX
315 +run: compare EAX and imm32 0x0d0c0b0a
316 +run: SF=1; ZF=0; OF=0
317 
318 :(scenario compare_imm32_with_eax_equal)
319 % Reg[EAX].i = 0x0d0c0b0a;
320 == 0x1
321 # op  ModR/M  SIB   displacement  immediate
322   3d                              0a 0b 0c 0d  # compare 0x0d0c0b0a with EAX
323 +run: compare EAX and imm32 0x0d0c0b0a
324 +run: SF=0; ZF=1; OF=0
325 
326 //:
327 
328 :(scenario compare_imm32_with_r32_greater)
329 % Reg[EBX].i = 0x0d0c0b0a;
330 == 0x1
331 # op  ModR/M  SIB   displacement  immediate
332   81  fb                          07 0b 0c 0d  # compare 0x0d0c0b07 with EBX
333 # ModR/M in binary: 11 (direct mode) 111 (compare imm32) 011 (dest EBX)
334 +run: combine imm32 with r/m32
335 +run: r/m32 is EBX
336 +run: imm32 is 0x0d0c0b07
337 +run: SF=0; ZF=0; OF=0
338 
339 :(before "End Op 81 Subops")
340 case 7: {
341   trace(90, "run") << "subop compare" << end();
342   const int32_t tmp1 = *arg1 - arg2;
343   SF = (tmp1 < 0);
344   ZF = (tmp1 == 0);
345   const int64_t tmp2 = *arg1 - arg2;
346   OF = (tmp1 != tmp2);
347   trace(90, "run") << "SF=" << SF << "; ZF=" << ZF << "; OF=" << OF << end();
348   break;
349 }
350 
351 :(scenario compare_imm32_with_r32_lesser)
352 % Reg[EBX].i = 0x0d0c0b07;
353 == 0x1
354 # op  ModR/M  SIB   displacement  immediate
355   81  fb                          0a 0b 0c 0d  # compare 0x0d0c0b0a with EBX
356 # ModR/M in binary: 11 (direct mode) 111 (compare imm32) 011 (dest EBX)
357 +run: combine imm32 with r/m32
358 +run: r/m32 is EBX
359 +run: imm32 is 0x0d0c0b0a
360 +run: SF=1; ZF=0; OF=0
361 
362 :(scenario compare_imm32_with_r32_equal)
363 % Reg[EBX].i = 0x0d0c0b0a;
364 == 0x1
365 # op  ModR/M  SIB   displacement  immediate
366   81  fb                          0a 0b 0c 0d  # compare 0x0d0c0b0a with EBX
367 # ModR/M in binary: 11 (direct mode) 111 (compare imm32) 011 (dest EBX)
368 +run: combine imm32 with r/m32
369 +run: r/m32 is EBX
370 +run: imm32 is 0x0d0c0b0a
371 +run: SF=0; ZF=1; OF=0
372 
373 :(scenario compare_imm32_with_mem_at_r32_greater)
374 % Reg[EBX].i = 0x2000;
375 == 0x01  # code segment
376 # op  ModR/M  SIB   displacement  immediate
377   81  3b                          07 0b 0c 0d  # compare 0x0d0c0b07 with *EBX
378 # ModR/M in binary: 00 (indirect mode) 111 (compare imm32) 011 (dest EBX)
379 == 0x2000  # data segment
380 0a 0b 0c 0d  # 0x0d0c0b0a
381 +run: combine imm32 with r/m32
382 +run: effective address is 0x00002000 (EBX)
383 +run: imm32 is 0x0d0c0b07
384 +run: SF=0; ZF=0; OF=0
385 
386 :(scenario compare_imm32_with_mem_at_r32_lesser)
387 % Reg[EBX].i = 0x2000;
388 == 0x01  # code segment
389 # op  ModR/M  SIB   displacement  immediate
390   81  3b                          0a 0b 0c 0d  # compare 0x0d0c0b0a with *EBX
391 # ModR/M in binary: 00 (indirect mode) 111 (compare imm32) 011 (dest EBX)
392 == 0x2000  # data segment
393 07 0b 0c 0d  # 0x0d0c0b07
394 +run: combine imm32 with r/m32
395 +run: effective address is 0x00002000 (EBX)
396 +run: imm32 is 0x0d0c0b0a
397 +run: SF=1; ZF=0; OF=0
398 
399 :(scenario compare_imm32_with_mem_at_r32_equal)
400 % Reg[EBX].i = 0x0d0c0b0a;
401 % Reg[EBX].i = 0x2000;
402 == 0x01  # code segment
403 # op  ModR/M  SIB   displacement  immediate
404   81  3b                          0a 0b 0c 0d  # compare 0x0d0c0b0a with *EBX
405 # ModR/M in binary: 00 (indirect mode) 111 (compare imm32) 011 (dest EBX)
406 == 0x2000  # data segment
407 0a 0b 0c 0d  # 0x0d0c0b0a
408 +run: combine imm32 with r/m32
409 +run: effective address is 0x00002000 (EBX)
410 +run: imm32 is 0x0d0c0b0a
411 +run: SF=0; ZF=1; OF=0
412 
413 //:: copy (mov)
414 
415 :(before "End Initialize Op Names")
416 put_new(Name, "b8", "copy imm32 to EAX (mov)");
417 put_new(Name, "b9", "copy imm32 to ECX (mov)");
418 put_new(Name, "ba", "copy imm32 to EDX (mov)");
419 put_new(Name, "bb", "copy imm32 to EBX (mov)");
420 put_new(Name, "bc", "copy imm32 to ESP (mov)");
421 put_new(Name, "bd", "copy imm32 to EBP (mov)");
422 put_new(Name, "be", "copy imm32 to ESI (mov)");
423 put_new(Name, "bf", "copy imm32 to EDI (mov)");
424 
425 :(scenario copy_imm32_to_r32)
426 == 0x1
427 # op  ModR/M  SIB   displacement  immediate
428   bb                              0a 0b 0c 0d  # copy 0x0d0c0b0a to EBX
429 +run: copy imm32 0x0d0c0b0a to EBX
430 
431 :(before "End Single-Byte Opcodes")
432 case 0xb8:
433 case 0xb9:
434 case 0xba:
435 case 0xbb:
436 case 0xbc:
437 case 0xbd:
438 case 0xbe:
439 case 0xbf: {  // copy imm32 to r32
440   const uint8_t rdest = op & 0x7;
441   const int32_t src = next32();
442   trace(90, "run") << "copy imm32 0x" << HEXWORD << src << " to " << rname(rdest) << end();
443   Reg[rdest].i = src;
444   break;
445 }
446 
447 //:
448 
449 :(before "End Initialize Op Names")
450 put_new(Name, "c7", "copy imm32 to rm32 (mov)");
451 
452 :(scenario copy_imm32_to_mem_at_r32)
453 % Reg[EBX].i = 0x60;
454 == 0x1
455 # op  ModR/M  SIB   displacement  immediate
456   c7  03                          0a 0b 0c 0d  # copy 0x0d0c0b0a to *EBX
457 # ModR/M in binary: 00 (indirect mode) 000 (unused) 011 (dest EBX)
458 +run: copy imm32 to r/m32
459 +run: effective address is 0x00000060 (EBX)
460 +run: imm32 is 0x0d0c0b0a
461 
462 :(before "End Single-Byte Opcodes")
463 case 0xc7: {  // copy imm32 to r32
464   const uint8_t modrm = next();
465   trace(90, "run") << "copy imm32 to r/m32" << end();
466   int32_t* dest = effective_address(modrm);
467   const int32_t src = next32();
468   trace(90, "run") << "imm32 is 0x" << HEXWORD << src << end();
469   *dest = src;
470   break;
471 }
472 
473 //:: push
474 
475 :(before "End Initialize Op Names")
476 put_new(Name, "68", "push imm32 to stack (push)");
477 
478 :(scenario push_imm32)
479 % Reg[ESP].u = 0x14;
480 == 0x1
481 # op  ModR/M  SIB   displacement  immediate
482   68                              af 00 00 00  # push *EAX to stack
483 +run: push imm32 0x000000af
484 +run: ESP is now 0x00000010
485 +run: contents at ESP: 0x000000af
486 
487 :(before "End Single-Byte Opcodes")
488 case 0x68: {
489   const uint32_t val = static_cast<uint32_t>(next32());
490   trace(90, "run") << "push imm32 0x" << HEXWORD << val << end();
491 //?   cerr << "push: " << val << " => " << Reg[ESP].u << '\n';
492   push(val);
493   trace(90, "run") << "ESP is now 0x" << HEXWORD << Reg[ESP].u << end();
494   trace(90, "run") << "contents at ESP: 0x" << HEXWORD << read_mem_u32(Reg[ESP].u) << end();
495   break;
496 }