https://github.com/akkartik/mu/blob/master/subx/015immediate_addressing.cc
1
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
10 81 c3 0a 0b 0c 0d
11
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: {
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;
26 switch (subop) {
27 case 0:
28 trace(90, "run") << "subop add" << end();
29 BINARY_ARITHMETIC_OP(+, *arg1, arg2);
30 break;
31
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
44
45 81 03 0a 0b 0c 0d
46
47 == 0x2000
48 01 00 00 00
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
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
64 2d 0a 0b 0c 0d
65 +run: subtract imm32 0x0d0c0b0a from EAX
66 +run: storing 0x000000a0
67
68 :(before "End Single-Byte Opcodes")
69 case 0x2d: {
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
81
82 81 2b 01 00 00 00
83
84 == 0x2000
85 0a 00 00 00
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
105 81 eb 01 00 00 00
106
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
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
122 25 0a 0b 0c 0d
123 +run: and imm32 0x0d0c0b0a with EAX
124 +run: storing 0x0000000a
125
126 :(before "End Single-Byte Opcodes")
127 case 0x25: {
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
139
140 81 23 0a 0b 0c 0d
141
142 == 0x2000
143 ff 00 00 00
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
163 81 e3 0a 0b 0c 0d
164
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
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
180 0d 0a 0b 0c 0d
181 +run: or imm32 0x0d0c0b0a with EAX
182 +run: storing 0xddccbbaa
183
184 :(before "End Single-Byte Opcodes")
185 case 0x0d: {
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
197
198 81 0b 0a 0b 0c 0d
199
200 == 0x2000
201 a0 b0 c0 d0
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
219 81 cb 0a 0b 0c 0d
220
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
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
236 35 0a 0b 0c 0d
237 +run: xor imm32 0x0d0c0b0a with EAX
238 +run: storing 0xd0c0bbaa
239
240 :(before "End Single-Byte Opcodes")
241 case 0x35: {
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
253
254 81 33 0a 0b 0c 0d
255
256 == 0x2000
257 a0 b0 c0 d0
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
275 81 f3 0a 0b 0c 0d
276
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
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
292 3d 07 0b 0c 0d
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: {
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
314 3d 0a 0b 0c 0d
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
322 3d 0a 0b 0c 0d
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
332 81 fb 07 0b 0c 0d
333
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
355 81 fb 0a 0b 0c 0d
356
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
366 81 fb 0a 0b 0c 0d
367
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
376
377 81 3b 07 0b 0c 0d
378
379 == 0x2000
380 0a 0b 0c 0d
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
389
390 81 3b 0a 0b 0c 0d
391
392 == 0x2000
393 07 0b 0c 0d
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
403
404 81 3b 0a 0b 0c 0d
405
406 == 0x2000
407 0a 0b 0c 0d
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
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
428 bb 0a 0b 0c 0d
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: {
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
456 c7 03 0a 0b 0c 0d
457
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: {
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
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
482 68 af 00 00 00
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
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 }