https://github.com/akkartik/mu/blob/main/linux/bootstrap/015immediate_addressing.cc
1
2
3 :(before "End Initialize Op Names")
4 put_new(Name, "05", "add imm32 to EAX (add)");
5
6 :(before "End Single-Byte Opcodes")
7 case 0x05: {
8 int32_t signed_arg2 = next32();
9 trace(Callstack_depth+1, "run") << "add imm32 0x" << HEXWORD << signed_arg2 << " to EAX" << end();
10 int32_t signed_result = Reg[EAX].i + signed_arg2;
11 SF = (signed_result < 0);
12 ZF = (signed_result == 0);
13 int64_t signed_full_result = static_cast<int64_t>(Reg[EAX].i) + signed_arg2;
14 OF = (signed_result != signed_full_result);
15
16 uint32_t unsigned_arg2 = static_cast<uint32_t>(signed_arg2);
17 uint32_t unsigned_result = Reg[EAX].u + unsigned_arg2;
18 uint64_t unsigned_full_result = static_cast<uint64_t>(Reg[EAX].u) + unsigned_arg2;
19 CF = (unsigned_result != unsigned_full_result);
20 trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
21 Reg[EAX].i = signed_result;
22 trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[EAX].i << end();
23 break;
24 }
25
26 :(code)
27 void test_add_imm32_to_EAX_signed_overflow() {
28 Reg[EAX].i = INT32_MAX;
29 run(
30 "== code 0x1\n"
31
32 " 05 01 00 00 00 \n"
33 );
34 CHECK_TRACE_CONTENTS(
35 "run: add imm32 0x00000001 to EAX\n"
36 "run: SF=1; ZF=0; CF=0; OF=1\n"
37 "run: storing 0x80000000\n"
38 );
39 }
40
41 void test_add_imm32_to_EAX_unsigned_overflow() {
42 Reg[EAX].u = UINT32_MAX;
43 Reg[EBX].u = 1;
44 run(
45 "== code 0x1\n"
46
47 " 05 01 00 00 00 \n"
48 );
49 CHECK_TRACE_CONTENTS(
50 "run: add imm32 0x00000001 to EAX\n"
51 "run: SF=0; ZF=1; CF=1; OF=0\n"
52 "run: storing 0x00000000\n"
53 );
54 }
55
56 void test_add_imm32_to_EAX_unsigned_and_signed_overflow() {
57 Reg[EAX].i = INT32_MIN;
58 run(
59 "== code 0x1\n"
60
61 " 05 00 00 00 80 \n"
62 );
63 CHECK_TRACE_CONTENTS(
64 "run: add imm32 0x80000000 to EAX\n"
65 "run: SF=0; ZF=1; CF=1; OF=1\n"
66 "run: storing 0x00000000\n"
67 );
68 }
69
70
71
72 :(before "End Initialize Op Names")
73 put_new(Name, "81", "combine rm32 with imm32 based on subop (add/sub/and/or/xor/cmp)");
74
75 :(code)
76 void test_add_imm32_to_r32() {
77 Reg[EBX].i = 1;
78 run(
79 "== code 0x1\n"
80
81 " 81 c3 0a 0b 0c 0d\n"
82
83 );
84 CHECK_TRACE_CONTENTS(
85 "run: combine r/m32 with imm32\n"
86 "run: r/m32 is EBX\n"
87 "run: imm32 is 0x0d0c0b0a\n"
88 "run: subop add\n"
89 "run: storing 0x0d0c0b0b\n"
90 );
91 }
92
93 :(before "End Single-Byte Opcodes")
94 case 0x81: {
95 trace(Callstack_depth+1, "run") << "combine r/m32 with imm32" << end();
96 const uint8_t modrm = next();
97 int32_t* signed_arg1 = effective_address(modrm);
98 const int32_t signed_arg2 = next32();
99 trace(Callstack_depth+1, "run") << "imm32 is 0x" << HEXWORD << signed_arg2 << end();
100 const uint8_t subop = (modrm>>3)&0x7;
101 switch (subop) {
102 case 0: {
103 trace(Callstack_depth+1, "run") << "subop add" << end();
104 int32_t signed_result = *signed_arg1 + signed_arg2;
105 SF = (signed_result < 0);
106 ZF = (signed_result == 0);
107 int64_t signed_full_result = static_cast<int64_t>(*signed_arg1) + signed_arg2;
108 OF = (signed_result != signed_full_result);
109
110 uint32_t unsigned_arg1 = static_cast<uint32_t>(*signed_arg1);
111 uint32_t unsigned_arg2 = static_cast<uint32_t>(signed_arg2);
112 uint32_t unsigned_result = unsigned_arg1 + unsigned_arg2;
113 uint64_t unsigned_full_result = static_cast<uint64_t>(unsigned_arg1) + unsigned_arg2;
114 CF = (unsigned_result != unsigned_full_result);
115 trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
116 *signed_arg1 = signed_result;
117 trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *signed_arg1 << end();
118 break;
119 }
120
121 default:
122 cerr << "unrecognized subop for opcode 81: " << NUM(subop) << '\n';
123 exit(1);
124 }
125 break;
126 }
127
128 :(code)
129 void test_add_imm32_to_r32_signed_overflow() {
130 Reg[EBX].i = INT32_MAX;
131 run(
132 "== code 0x1\n"
133
134 " 81 c3 01 00 00 00\n"
135
136 );
137 CHECK_TRACE_CONTENTS(
138 "run: combine r/m32 with imm32\n"
139 "run: r/m32 is EBX\n"
140 "run: imm32 is 0x00000001\n"
141 "run: subop add\n"
142 "run: SF=1; ZF=0; CF=0; OF=1\n"
143 "run: storing 0x80000000\n"
144 );
145 }
146
147 void test_add_imm32_to_r32_unsigned_overflow() {
148 Reg[EBX].u = UINT32_MAX;
149 run(
150 "== code 0x1\n"
151
152 " 81 c3 01 00 00 00\n"
153
154 );
155 CHECK_TRACE_CONTENTS(
156 "run: combine r/m32 with imm32\n"
157 "run: r/m32 is EBX\n"
158 "run: imm32 is 0x00000001\n"
159 "run: subop add\n"
160 "run: SF=0; ZF=1; CF=1; OF=0\n"
161 "run: storing 0x00000000\n"
162 );
163 }
164
165 void test_add_imm32_to_r32_unsigned_and_signed_overflow() {
166 Reg[EBX].i = INT32_MIN;
167 run(
168 "== code 0x1\n"
169
170 " 81 c3 00 00 00 80\n"
171
172 );
173 CHECK_TRACE_CONTENTS(
174 "run: combine r/m32 with imm32\n"
175 "run: r/m32 is EBX\n"
176 "run: imm32 is 0x80000000\n"
177 "run: subop add\n"
178 "run: SF=0; ZF=1; CF=1; OF=1\n"
179 "run: storing 0x00000000\n"
180 );
181 }
182
183
184
185 :(code)
186 void test_add_imm32_to_mem_at_rm32() {
187 Reg[EBX].i = 0x2000;
188 run(
189 "== code 0x1\n"
190
191 " 81 03 0a 0b 0c 0d \n"
192
193 "== data 0x2000\n"
194 "01 00 00 00\n"
195 );
196 CHECK_TRACE_CONTENTS(
197 "run: combine r/m32 with imm32\n"
198 "run: effective address is 0x00002000 (EBX)\n"
199 "run: imm32 is 0x0d0c0b0a\n"
200 "run: subop add\n"
201 "run: storing 0x0d0c0b0b\n"
202 );
203 }
204
205
206
207 :(before "End Initialize Op Names")
208 put_new(Name, "2d", "subtract imm32 from EAX (sub)");
209
210 :(code)
211 void test_subtract_imm32_from_EAX() {
212 Reg[EAX].i = 0x0d0c0baa;
213 run(
214 "== code 0x1\n"
215
216 " 2d 0a 0b 0c 0d \n"
217 );
218 CHECK_TRACE_CONTENTS(
219 "run: subtract imm32 0x0d0c0b0a from EAX\n"
220 "run: storing 0x000000a0\n"
221 );
222 }
223
224 :(before "End Single-Byte Opcodes")
225 case 0x2d: {
226 const int32_t signed_arg2 = next32();
227 trace(Callstack_depth+1, "run") << "subtract imm32 0x" << HEXWORD << signed_arg2 << " from EAX" << end();
228 int32_t signed_result = Reg[EAX].i - signed_arg2;
229 SF = (signed_result < 0);
230 ZF = (signed_result == 0);
231 int64_t signed_full_result = static_cast<int64_t>(Reg[EAX].i) - signed_arg2;
232 OF = (signed_result != signed_full_result);
233
234 uint32_t unsigned_arg2 = static_cast<uint32_t>(signed_arg2);
235 uint32_t unsigned_result = Reg[EAX].u - unsigned_arg2;
236 uint64_t unsigned_full_result = static_cast<uint64_t>(Reg[EAX].u) - unsigned_arg2;
237 CF = (unsigned_result != unsigned_full_result);
238 trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
239 Reg[EAX].i = signed_result;
240 trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[EAX].i << end();
241 break;
242 }
243
244 :(code)
245 void test_subtract_imm32_from_EAX_signed_overflow() {
246 Reg[EAX].i = INT32_MIN;
247 run(
248 "== code 0x1\n"
249
250 " 2d 01 00 00 00 \n"
251 );
252 CHECK_TRACE_CONTENTS(
253 "run: subtract imm32 0x00000001 from EAX\n"
254 "run: SF=0; ZF=0; CF=0; OF=1\n"
255 "run: storing 0x7fffffff\n"
256 );
257 }
258
259 void test_subtract_imm32_from_EAX_unsigned_overflow() {
260 Reg[EAX].i = 0;
261 run(
262 "== code 0x1\n"
263
264 " 2d 01 00 00 00 \n"
265 );
266 CHECK_TRACE_CONTENTS(
267 "run: subtract imm32 0x00000001 from EAX\n"
268 "run: SF=1; ZF=0; CF=1; OF=0\n"
269 "run: storing 0xffffffff\n"
270 );
271 }
272
273 void test_subtract_imm32_from_EAX_signed_and_unsigned_overflow() {
274 Reg[EAX].i = 0;
275 run(
276 "== code 0x1\n"
277
278 " 2d 00 00 00 80 \n"
279 );
280 CHECK_TRACE_CONTENTS(
281 "run: subtract imm32 0x80000000 from EAX\n"
282 "run: SF=1; ZF=0; CF=1; OF=1\n"
283 "run: storing 0x80000000\n"
284 );
285 }
286
287
288
289 void test_subtract_imm32_from_mem_at_rm32() {
290 Reg[EBX].i = 0x2000;
291 run(
292 "== code 0x1\n"
293
294 " 81 2b 01 00 00 00 \n"
295
296 "== data 0x2000\n"
297 "0a 00 00 00\n"
298 );
299 CHECK_TRACE_CONTENTS(
300 "run: combine r/m32 with imm32\n"
301 "run: effective address is 0x00002000 (EBX)\n"
302 "run: imm32 is 0x00000001\n"
303 "run: subop subtract\n"
304 "run: storing 0x00000009\n"
305 );
306 }
307
308 :(before "End Op 81 Subops")
309 case 5: {
310 trace(Callstack_depth+1, "run") << "subop subtract" << end();
311 int32_t signed_result = *signed_arg1 - signed_arg2;
312 SF = (signed_result < 0);
313 ZF = (signed_result == 0);
314 int64_t signed_full_result = static_cast<int64_t>(*signed_arg1) - signed_arg2;
315 OF = (signed_result != signed_full_result);
316
317 uint32_t unsigned_arg1 = static_cast<uint32_t>(*signed_arg1);
318 uint32_t unsigned_arg2 = static_cast<uint32_t>(signed_arg2);
319 uint32_t unsigned_result = unsigned_arg1 - unsigned_arg2;
320 uint64_t unsigned_full_result = static_cast<uint64_t>(unsigned_arg1) - unsigned_arg2;
321 CF = (unsigned_result != unsigned_full_result);
322 trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
323 *signed_arg1 = signed_result;
324 trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *signed_arg1 << end();
325 break;
326 }
327
328 :(code)
329 void test_subtract_imm32_from_mem_at_rm32_signed_overflow() {
330 Reg[EBX].i = 0x2000;
331 run(
332 "== code 0x1\n"
333
334 " 81 2b ff ff ff 7f \n"
335
336 "== data 0x2000\n"
337 "00 00 00 80\n"
338 );
339 CHECK_TRACE_CONTENTS(
340 "run: combine r/m32 with imm32\n"
341 "run: effective address is 0x00002000 (EBX)\n"
342 "run: effective address contains 0x80000000\n"
343 "run: imm32 is 0x7fffffff\n"
344 "run: subop subtract\n"
345 "run: SF=0; ZF=0; CF=0; OF=1\n"
346 "run: storing 0x00000001\n"
347 );
348 }
349
350 void test_subtract_imm32_from_mem_at_rm32_unsigned_overflow() {
351 Reg[EBX].i = 0x2000;
352 run(
353 "== code 0x1\n"
354
355 " 81 2b 01 00 00 00 \n"
356
357 "== data 0x2000\n"
358 "00 00 00 00\n"
359 );
360 CHECK_TRACE_CONTENTS(
361 "run: combine r/m32 with imm32\n"
362 "run: effective address is 0x00002000 (EBX)\n"
363 "run: effective address contains 0x00000000\n"
364 "run: imm32 is 0x00000001\n"
365 "run: subop subtract\n"
366 "run: SF=1; ZF=0; CF=1; OF=0\n"
367 "run: storing 0xffffffff\n"
368 );
369 }
370
371 void test_subtract_imm32_from_mem_at_rm32_signed_and_unsigned_overflow() {
372 Reg[EBX].i = 0x2000;
373 run(
374 "== code 0x1\n"
375
376 " 81 2b 00 00 00 80 \n"
377
378 "== data 0x2000\n"
379 "00 00 00 00\n"
380 );
381 CHECK_TRACE_CONTENTS(
382 "run: combine r/m32 with imm32\n"
383 "run: effective address is 0x00002000 (EBX)\n"
384 "run: effective address contains 0x00000000\n"
385 "run: imm32 is 0x80000000\n"
386 "run: subop subtract\n"
387 "run: SF=1; ZF=0; CF=1; OF=1\n"
388 "run: storing 0x80000000\n"
389 );
390 }
391
392
393
394 void test_subtract_imm32_from_r32() {
395 Reg[EBX].i = 10;
396 run(
397 "== code 0x1\n"
398
399 " 81 eb 01 00 00 00 \n"
400
401 );
402 CHECK_TRACE_CONTENTS(
403 "run: combine r/m32 with imm32\n"
404 "run: r/m32 is EBX\n"
405 "run: imm32 is 0x00000001\n"
406 "run: subop subtract\n"
407 "run: storing 0x00000009\n"
408 );
409 }
410
411
412
413 :(before "End Initialize Op Names")
414 put_new(Name, "c1", "shift rm32 by imm8 bits depending on subop (sal/sar/shl/shr)");
415
416 :(code)
417 void test_shift_left_r32_with_imm8() {
418 Reg[EBX].i = 13;
419 run(
420 "== code 0x1\n"
421
422 " c1 e3 01 \n"
423
424 );
425 CHECK_TRACE_CONTENTS(
426 "run: operate on r/m32\n"
427 "run: r/m32 is EBX\n"
428 "run: subop: shift left by CL bits\n"
429 "run: storing 0x0000001a\n"
430 );
431 }
432
433 :(before "End Single-Byte Opcodes")
434 case 0xc1: {
435 const uint8_t modrm = next();
436 trace(Callstack_depth+1, "run") << "operate on r/m32" << end();
437 int32_t* arg1 = effective_address(modrm);
438 const uint8_t subop = (modrm>>3)&0x7;
439 switch (subop) {
440 case 4: {
441 trace(Callstack_depth+1, "run") << "subop: shift left by CL bits" << end();
442 uint8_t count = next() & 0x1f;
443
444 if (count == 1) {
445 bool msb = (*arg1 & 0x80000000) >> 1;
446 bool pnsb = (*arg1 & 0x40000000);
447 OF = (msb != pnsb);
448 }
449 *arg1 = (*arg1 << count);
450 ZF = (*arg1 == 0);
451 SF = (*arg1 < 0);
452
453 trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
454 trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *arg1 << end();
455 break;
456 }
457
458 default:
459 cerr << "unrecognized subop for opcode c1: " << NUM(subop) << '\n';
460 exit(1);
461 }
462 break;
463 }
464
465
466
467 :(code)
468 void test_shift_right_arithmetic_r32_with_imm8() {
469 Reg[EBX].i = 26;
470 run(
471 "== code 0x1\n"
472
473 " c1 fb 01 \n"
474
475 );
476 CHECK_TRACE_CONTENTS(
477 "run: operate on r/m32\n"
478 "run: r/m32 is EBX\n"
479 "run: subop: shift right by CL bits, while preserving sign\n"
480 "run: storing 0x0000000d\n"
481 );
482 }
483
484 :(before "End Op c1 Subops")
485 case 7: {
486 trace(Callstack_depth+1, "run") << "subop: shift right by CL bits, while preserving sign" << end();
487 uint8_t count = next() & 0x1f;
488 int32_t result = (*arg1 >> count);
489 ZF = (*arg1 == 0);
490 SF = (*arg1 < 0);
491
492 if (count == 1) OF = false;
493
494 CF = ((*arg1 >> (count-1)) & 0x1);
495 trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
496 *arg1 = result;
497 trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *arg1 << end();
498 break;
499 }
500
501 :(code)
502 void test_shift_right_arithmetic_odd_r32_with_imm8() {
503 Reg[EBX].i = 27;
504 run(
505 "== code 0x1\n"
506
507 " c1 fb 01 \n"
508
509 );
510 CHECK_TRACE_CONTENTS(
511 "run: operate on r/m32\n"
512 "run: r/m32 is EBX\n"
513 "run: subop: shift right by CL bits, while preserving sign\n"
514
515 "run: storing 0x0000000d\n"
516 );
517 }
518
519 :(code)
520 void test_shift_right_arithmetic_negative_r32_with_imm8() {
521 Reg[EBX].i = 0xfffffffd;
522 run(
523 "== code 0x1\n"
524
525 " c1 fb 01 \n"
526
527 );
528 CHECK_TRACE_CONTENTS(
529 "run: operate on r/m32\n"
530 "run: r/m32 is EBX\n"
531 "run: subop: shift right by CL bits, while preserving sign\n"
532
533 "run: storing 0xfffffffe\n"
534 );
535 }
536
537
538
539 :(code)
540 void test_shift_right_logical_r32_with_imm8() {
541 Reg[EBX].i = 26;
542 run(
543 "== code 0x1\n"
544
545 " c1 eb 01 \n"
546
547 );
548 CHECK_TRACE_CONTENTS(
549 "run: operate on r/m32\n"
550 "run: r/m32 is EBX\n"
551 "run: subop: shift right by CL bits, while padding zeroes\n"
552 "run: storing 0x0000000d\n"
553 );
554 }
555
556 :(before "End Op c1 Subops")
557 case 5: {
558 trace(Callstack_depth+1, "run") << "subop: shift right by CL bits, while padding zeroes" << end();
559 uint8_t count = next() & 0x1f;
560
561 if (count == 1) {
562 bool msb = (*arg1 & 0x80000000) >> 1;
563 bool pnsb = (*arg1 & 0x40000000);
564 OF = (msb != pnsb);
565 }
566 uint32_t* uarg1 = reinterpret_cast<uint32_t*>(arg1);
567 *uarg1 = (*uarg1 >> count);
568 ZF = (*uarg1 == 0);
569
570 SF = false;
571
572 trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
573 trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *arg1 << end();
574 break;
575 }
576
577 :(code)
578 void test_shift_right_logical_odd_r32_with_imm8() {
579 Reg[EBX].i = 27;
580 run(
581 "== code 0x1\n"
582
583 " c1 eb 01 \n"
584 );
585 CHECK_TRACE_CONTENTS(
586 "run: operate on r/m32\n"
587 "run: r/m32 is EBX\n"
588 "run: subop: shift right by CL bits, while padding zeroes\n"
589
590 "run: storing 0x0000000d\n"
591 );
592 }
593
594 :(code)
595 void test_shift_right_logical_negative_r32_with_imm8() {
596 Reg[EBX].i = 0xfffffffd;
597 run(
598 "== code 0x1\n"
599
600 " c1 eb 01 \n"
601
602 );
603 CHECK_TRACE_CONTENTS(
604 "run: operate on r/m32\n"
605 "run: r/m32 is EBX\n"
606 "run: subop: shift right by CL bits, while padding zeroes\n"
607 "run: storing 0x7ffffffe\n"
608 );
609 }
610
611
612
613 :(before "End Initialize Op Names")
614 put_new(Name, "25", "EAX = bitwise AND of imm32 with EAX (and)");
615
616 :(code)
617 void test_and_EAX_with_imm32() {
618 Reg[EAX].i = 0xff;
619 run(
620 "== code 0x1\n"
621
622 " 25 0a 0b 0c 0d \n"
623 );
624 CHECK_TRACE_CONTENTS(
625 "run: and imm32 0x0d0c0b0a with EAX\n"
626 "run: storing 0x0000000a\n"
627 );
628 }
629
630 :(before "End Single-Byte Opcodes")
631 case 0x25: {
632
633
634 const int32_t signed_arg2 = next32();
635 trace(Callstack_depth+1, "run") << "and imm32 0x" << HEXWORD << signed_arg2 << " with EAX" << end();
636 Reg[EAX].i &= signed_arg2;
637 trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[EAX].i << end();
638 SF = (Reg[EAX].i >> 31);
639 ZF = (Reg[EAX].i == 0);
640 CF = false;
641 OF = false;
642 trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
643 break;
644 }
645
646
647
648 :(code)
649 void test_and_imm32_with_mem_at_rm32() {
650 Reg[EBX].i = 0x2000;
651 run(
652 "== code 0x1\n"
653
654 " 81 23 0a 0b 0c 0d \n"
655
656 "== data 0x2000\n"
657 "ff 00 00 00\n"
658 );
659 CHECK_TRACE_CONTENTS(
660 "run: combine r/m32 with imm32\n"
661 "run: effective address is 0x00002000 (EBX)\n"
662 "run: imm32 is 0x0d0c0b0a\n"
663 "run: subop and\n"
664 "run: storing 0x0000000a\n"
665 );
666 }
667
668 :(before "End Op 81 Subops")
669 case 4: {
670 trace(Callstack_depth+1, "run") << "subop and" << end();
671
672
673 *signed_arg1 &= signed_arg2;
674 trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *signed_arg1 << end();
675 SF = (*signed_arg1 >> 31);
676 ZF = (*signed_arg1 == 0);
677 CF = false;
678 OF = false;
679 trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
680 break;
681 }
682
683
684
685 :(code)
686 void test_and_imm32_with_r32() {
687 Reg[EBX].i = 0xff;
688 run(
689 "== code 0x1\n"
690
691 " 81 e3 0a 0b 0c 0d \n"
692
693 );
694 CHECK_TRACE_CONTENTS(
695 "run: combine r/m32 with imm32\n"
696 "run: r/m32 is EBX\n"
697 "run: imm32 is 0x0d0c0b0a\n"
698 "run: subop and\n"
699 "run: storing 0x0000000a\n"
700 );
701 }
702
703
704
705 :(before "End Initialize Op Names")
706 put_new(Name, "0d", "EAX = bitwise OR of imm32 with EAX (or)");
707
708 :(code)
709 void test_or_EAX_with_imm32() {
710 Reg[EAX].i = 0xd0c0b0a0;
711 run(
712 "== code 0x1\n"
713
714 " 0d 0a 0b 0c 0d \n"
715 );
716 CHECK_TRACE_CONTENTS(
717 "run: or imm32 0x0d0c0b0a with EAX\n"
718 "run: storing 0xddccbbaa\n"
719 );
720 }
721
722 :(before "End Single-Byte Opcodes")
723 case 0x0d: {
724
725
726 const int32_t signed_arg2 = next32();
727 trace(Callstack_depth+1, "run") << "or imm32 0x" << HEXWORD << signed_arg2 << " with EAX" << end();
728 Reg[EAX].i |= signed_arg2;
729 trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[EAX].i << end();
730 SF = (Reg[EAX].i >> 31);
731 ZF = (Reg[EAX].i == 0);
732 CF = false;
733 OF = false;
734 trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
735 break;
736 }
737
738
739
740 :(code)
741 void test_or_imm32_with_mem_at_rm32() {
742 Reg[EBX].i = 0x2000;
743 run(
744 "== code 0x1\n"
745
746 " 81 0b 0a 0b 0c 0d \n"
747
748 "== data 0x2000\n"
749 "a0 b0 c0 d0\n"
750 );
751 CHECK_TRACE_CONTENTS(
752 "run: combine r/m32 with imm32\n"
753 "run: effective address is 0x00002000 (EBX)\n"
754 "run: imm32 is 0x0d0c0b0a\n"
755 "run: subop or\n"
756 "run: storing 0xddccbbaa\n"
757 );
758 }
759
760 :(before "End Op 81 Subops")
761 case 1: {
762 trace(Callstack_depth+1, "run") << "subop or" << end();
763
764
765 *signed_arg1 |= signed_arg2;
766 trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *signed_arg1 << end();
767 SF = (*signed_arg1 >> 31);
768 ZF = (*signed_arg1 == 0);
769 CF = false;
770 OF = false;
771 trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
772 break;
773 }
774
775 :(code)
776 void test_or_imm32_with_r32() {
777 Reg[EBX].i = 0xd0c0b0a0;
778 run(
779 "== code 0x1\n"
780
781 " 81 cb 0a 0b 0c 0d \n"
782
783 );
784 CHECK_TRACE_CONTENTS(
785 "run: combine r/m32 with imm32\n"
786 "run: r/m32 is EBX\n"
787 "run: imm32 is 0x0d0c0b0a\n"
788 "run: subop or\n"
789 "run: storing 0xddccbbaa\n"
790 );
791 }
792
793
794
795 :(before "End Initialize Op Names")
796 put_new(Name, "35", "EAX = bitwise XOR of imm32 with EAX (xor)");
797
798 :(code)
799 void test_xor_EAX_with_imm32() {
800 Reg[EAX].i = 0xddccb0a0;
801 run(
802 "== code 0x1\n"
803
804 " 35 0a 0b 0c 0d \n"
805 );
806 CHECK_TRACE_CONTENTS(
807 "run: xor imm32 0x0d0c0b0a with EAX\n"
808 "run: storing 0xd0c0bbaa\n"
809 );
810 }
811
812 :(before "End Single-Byte Opcodes")
813 case 0x35: {
814
815
816 const int32_t signed_arg2 = next32();
817 trace(Callstack_depth+1, "run") << "xor imm32 0x" << HEXWORD << signed_arg2 << " with EAX" << end();
818 Reg[EAX].i ^= signed_arg2;
819 trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[EAX].i << end();
820 SF = (Reg[EAX].i >> 31);
821 ZF = (Reg[EAX].i == 0);
822 CF = false;
823 OF = false;
824 trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
825 break;
826 }
827
828
829
830 :(code)
831 void test_xor_imm32_with_mem_at_rm32() {
832 Reg[EBX].i = 0x2000;
833 run(
834 "== code 0x1\n"
835
836 " 81 33 0a 0b 0c 0d \n"
837
838 "== data 0x2000\n"
839 "a0 b0 c0 d0\n"
840 );
841 CHECK_TRACE_CONTENTS(
842 "run: combine r/m32 with imm32\n"
843 "run: effective address is 0x00002000 (EBX)\n"
844 "run: imm32 is 0x0d0c0b0a\n"
845 "run: subop xor\n"
846 "run: storing 0xddccbbaa\n"
847 );
848 }
849
850 :(before "End Op 81 Subops")
851 case 6: {
852 trace(Callstack_depth+1, "run") << "subop xor" << end();
853
854
855 *signed_arg1 ^= signed_arg2;
856 trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *signed_arg1 << end();
857 SF = (*signed_arg1 >> 31);
858 ZF = (*signed_arg1 == 0);
859 CF = false;
860 OF = false;
861 trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
862 break;
863 }
864
865 :(code)
866 void test_xor_imm32_with_r32() {
867 Reg[EBX].i = 0xd0c0b0a0;
868 run(
869 "== code 0x1\n"
870
871 " 81 f3 0a 0b 0c 0d \n"
872
873 );
874 CHECK_TRACE_CONTENTS(
875 "run: combine r/m32 with imm32\n"
876 "run: r/m32 is EBX\n"
877 "run: imm32 is 0x0d0c0b0a\n"
878 "run: subop xor\n"
879 "run: storing 0xddccbbaa\n"
880 );
881 }
882
883
884
885 :(before "End Initialize Op Names")
886 put_new(Name, "3d", "compare: set SF if EAX < imm32 (cmp)");
887
888 :(code)
889 void test_compare_EAX_with_imm32_greater() {
890 Reg[EAX].i = 0x0d0c0b0a;
891 run(
892 "== code 0x1\n"
893
894 " 3d 07 0b 0c 0d \n"
895 );
896 CHECK_TRACE_CONTENTS(
897 "run: compare EAX with imm32 0x0d0c0b07\n"
898 "run: SF=0; ZF=0; CF=0; OF=0\n"
899 );
900 }
901
902 :(before "End Single-Byte Opcodes")
903 case 0x3d: {
904 const int32_t signed_arg1 = Reg[EAX].i;
905 const int32_t signed_arg2 = next32();
906 trace(Callstack_depth+1, "run") << "compare EAX with imm32 0x" << HEXWORD << signed_arg2 << end();
907 const int32_t signed_difference = signed_arg1 - signed_arg2;
908 SF = (signed_difference < 0);
909 ZF = (signed_difference == 0);
910 const int64_t full_signed_difference = static_cast<int64_t>(signed_arg1) - signed_arg2;
911 OF = (signed_difference != full_signed_difference);
912 const uint32_t unsigned_arg1 = static_cast<uint32_t>(signed_arg1);
913 const uint32_t unsigned_arg2 = static_cast<uint32_t>(signed_arg2);
914 const uint32_t unsigned_difference = unsigned_arg1 - unsigned_arg2;
915 const uint64_t full_unsigned_difference = static_cast<uint64_t>(unsigned_arg1) - unsigned_arg2;
916 CF = (unsigned_difference != full_unsigned_difference);
917 trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
918 break;
919 }
920
921 :(code)
922 void test_compare_EAX_with_imm32_lesser_unsigned_and_signed() {
923 Reg[EAX].i = 0x0a0b0c07;
924 run(
925 "== code 0x1\n"
926
927 " 3d 0d 0c 0b 0a \n"
928 );
929 CHECK_TRACE_CONTENTS(
930 "run: compare EAX with imm32 0x0a0b0c0d\n"
931 "run: SF=1; ZF=0; CF=1; OF=0\n"
932 );
933 }
934
935 void test_compare_EAX_with_imm32_lesser_unsigned_and_signed_due_to_overflow() {
936 Reg[EAX].i = INT32_MAX;
937 run(
938 "== code 0x1\n"
939
940 " 3d 00 00 00 80\n"
941 );
942 CHECK_TRACE_CONTENTS(
943 "run: compare EAX with imm32 0x80000000\n"
944 "run: SF=1; ZF=0; CF=1; OF=1\n"
945 );
946 }
947
948 void test_compare_EAX_with_imm32_lesser_signed() {
949 Reg[EAX].i = -1;
950 run(
951 "== code 0x1\n"
952
953 " 3d 01 00 00 00\n"
954 );
955 CHECK_TRACE_CONTENTS(
956 "run: compare EAX with imm32 0x00000001\n"
957 "run: SF=1; ZF=0; CF=0; OF=0\n"
958 );
959 }
960
961 void test_compare_EAX_with_imm32_lesser_unsigned() {
962 Reg[EAX].i = 1;
963 run(
964 "== code 0x1\n"
965
966 " 3d ff ff ff ff\n"
967 );
968 CHECK_TRACE_CONTENTS(
969 "run: compare EAX with imm32 0xffffffff\n"
970 "run: SF=0; ZF=0; CF=1; OF=0\n"
971 );
972 }
973
974 void test_compare_EAX_with_imm32_equal() {
975 Reg[EAX].i = 0x0d0c0b0a;
976 run(
977 "== code 0x1\n"
978
979 " 3d 0a 0b 0c 0d \n"
980 );
981 CHECK_TRACE_CONTENTS(
982 "run: compare EAX with imm32 0x0d0c0b0a\n"
983 "run: SF=0; ZF=1; CF=0; OF=0\n"
984 );
985 }
986
987
988
989 void test_compare_imm32_with_r32_greater() {
990 Reg[EBX].i = 0x0d0c0b0a;
991 run(
992 "== code 0x1\n"
993
994 " 81 fb 07 0b 0c 0d \n"
995
996 );
997 CHECK_TRACE_CONTENTS(
998 "run: combine r/m32 with imm32\n"
999 "run: r/m32 is EBX\n"
1000 "run: imm32 is 0x0d0c0b07\n"
1001 "run: SF=0; ZF=0; CF=0; OF=0\n"
1002 );
1003 }
1004
1005 :(before "End Op 81 Subops")
1006 case 7: {
1007 trace(Callstack_depth+1, "run") << "subop compare" << end();
1008 const int32_t tmp1 = *signed_arg1 - signed_arg2;
1009 SF = (tmp1 < 0);
1010 ZF = (tmp1 == 0);
1011 const int64_t tmp2 = static_cast<int64_t>(*signed_arg1) - signed_arg2;
1012 OF = (tmp1 != tmp2);
1013 const uint32_t unsigned_arg1 = static_cast<uint32_t>(*signed_arg1);
1014 const uint32_t unsigned_arg2 = static_cast<uint32_t>(signed_arg2);
1015 const uint32_t tmp3 = unsigned_arg1 - unsigned_arg2;
1016 const uint64_t tmp4 = static_cast<uint64_t>(unsigned_arg1) - unsigned_arg2;
1017 CF = (tmp3 != tmp4);
1018 trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
1019 break;
1020 }
1021
1022 :(code)
1023 void test_compare_rm32_with_imm32_lesser_unsigned_and_signed() {
1024 Reg[EAX].i = 0x0a0b0c07;
1025 run(
1026 "== code 0x1\n"
1027
1028 " 81 f8 0d 0c 0b 0a \n"
1029
1030 );
1031 CHECK_TRACE_CONTENTS(
1032 "run: combine r/m32 with imm32\n"
1033 "run: r/m32 is EAX\n"
1034 "run: imm32 is 0x0a0b0c0d\n"
1035 "run: subop compare\n"
1036 "run: SF=1; ZF=0; CF=1; OF=0\n"
1037 );
1038 }
1039
1040 void test_compare_rm32_with_imm32_lesser_unsigned_and_signed_due_to_overflow() {
1041 Reg[EAX].i = INT32_MAX;
1042 run(
1043 "== code 0x1\n"
1044
1045 " 81 f8 00 00 00 80\n"
1046
1047 );
1048 CHECK_TRACE_CONTENTS(
1049 "run: combine r/m32 with imm32\n"
1050 "run: r/m32 is EAX\n"
1051 "run: imm32 is 0x80000000\n"
1052 "run: subop compare\n"
1053 "run: SF=1; ZF=0; CF=1; OF=1\n"
1054 );
1055 }
1056
1057 void test_compare_rm32_with_imm32_lesser_signed() {
1058 Reg[EAX].i = -1;
1059 run(
1060 "== code 0x1\n"
1061
1062 " 81 f8 01 00 00 00\n"
1063
1064 );
1065 CHECK_TRACE_CONTENTS(
1066 "run: combine r/m32 with imm32\n"
1067 "run: r/m32 is EAX\n"
1068 "run: imm32 is 0x00000001\n"
1069 "run: subop compare\n"
1070 "run: SF=1; ZF=0; CF=0; OF=0\n"
1071 );
1072 }
1073
1074 void test_compare_rm32_with_imm32_lesser_unsigned() {
1075 Reg[EAX].i = 1;
1076 run(
1077 "== code 0x1\n"
1078
1079 " 81 f8 ff ff ff ff\n"
1080
1081 );
1082 CHECK_TRACE_CONTENTS(
1083 "run: combine r/m32 with imm32\n"
1084 "run: r/m32 is EAX\n"
1085 "run: imm32 is 0xffffffff\n"
1086 "run: subop compare\n"
1087 "run: SF=0; ZF=0; CF=1; OF=0\n"
1088 );
1089 }
1090
1091 :(code)
1092 void test_compare_imm32_with_r32_equal() {
1093 Reg[EBX].i = 0x0d0c0b0a;
1094 run(
1095 "== code 0x1\n"
1096
1097 " 81 fb 0a 0b 0c 0d \n"
1098
1099 );
1100 CHECK_TRACE_CONTENTS(
1101 "run: combine r/m32 with imm32\n"
1102 "run: r/m32 is EBX\n"
1103 "run: imm32 is 0x0d0c0b0a\n"
1104 "run: SF=0; ZF=1; CF=0; OF=0\n"
1105 );
1106 }
1107
1108 :(code)
1109 void test_compare_imm32_with_mem_at_rm32_greater() {
1110 Reg[EBX].i = 0x2000;
1111 run(
1112 "== code 0x1\n"
1113
1114 " 81 3b 07 0b 0c 0d \n"
1115
1116 "== data 0x2000\n"
1117 "0a 0b 0c 0d\n"
1118 );
1119 CHECK_TRACE_CONTENTS(
1120 "run: combine r/m32 with imm32\n"
1121 "run: effective address is 0x00002000 (EBX)\n"
1122 "run: imm32 is 0x0d0c0b07\n"
1123 "run: SF=0; ZF=0; CF=0; OF=0\n"
1124 );
1125 }
1126
1127 :(code)
1128 void test_compare_imm32_with_mem_at_rm32_lesser() {
1129 Reg[EAX].i = 0x2000;
1130 run(
1131 "== code 0x1\n"
1132
1133 " 81 38 0a 0b 0c 0d \n"
1134
1135 "== data 0x2000\n"
1136 "07 0b 0c 0d\n"
1137 );
1138 CHECK_TRACE_CONTENTS(
1139 "run: combine r/m32 with imm32\n"
1140 "run: effective address is 0x00002000 (EAX)\n"
1141 "run: imm32 is 0x0d0c0b0a\n"
1142 "run: SF=1; ZF=0; CF=1; OF=0\n"
1143 );
1144 }
1145
1146 :(code)
1147 void test_compare_imm32_with_mem_at_rm32_equal() {
1148 Reg[EBX].i = 0x0d0c0b0a;
1149 Reg[EBX].i = 0x2000;
1150 run(
1151 "== code 0x1\n"
1152
1153 " 81 3b 0a 0b 0c 0d \n"
1154
1155 "== data 0x2000\n"
1156 "0a 0b 0c 0d\n"
1157 );
1158 CHECK_TRACE_CONTENTS(
1159 "run: combine r/m32 with imm32\n"
1160 "run: effective address is 0x00002000 (EBX)\n"
1161 "run: imm32 is 0x0d0c0b0a\n"
1162 "run: SF=0; ZF=1; CF=0; OF=0\n"
1163 );
1164 }
1165
1166
1167
1168 :(before "End Initialize Op Names")
1169
1170 put_new(Name, "b9", "copy imm32 to ECX (mov)");
1171 put_new(Name, "ba", "copy imm32 to EDX (mov)");
1172 put_new(Name, "bb", "copy imm32 to EBX (mov)");
1173 put_new(Name, "bc", "copy imm32 to ESP (mov)");
1174 put_new(Name, "bd", "copy imm32 to EBP (mov)");
1175 put_new(Name, "be", "copy imm32 to ESI (mov)");
1176 put_new(Name, "bf", "copy imm32 to EDI (mov)");
1177
1178 :(code)
1179 void test_copy_imm32_to_r32() {
1180 run(
1181 "== code 0x1\n"
1182
1183 " bb 0a 0b 0c 0d \n"
1184 );
1185 CHECK_TRACE_CONTENTS(
1186 "run: copy imm32 0x0d0c0b0a to EBX\n"
1187 );
1188 }
1189
1190 :(before "End Single-Byte Opcodes")
1191 case 0xb9:
1192 case 0xba:
1193 case 0xbb:
1194 case 0xbc:
1195 case 0xbd:
1196 case 0xbe:
1197 case 0xbf: {
1198 const uint8_t rdest = op & 0x7;
1199 const int32_t src = next32();
1200 trace(Callstack_depth+1, "run") << "copy imm32 0x" << HEXWORD << src << " to " << rname(rdest) << end();
1201 Reg[rdest].i = src;
1202 break;
1203 }
1204
1205
1206
1207 :(before "End Initialize Op Names")
1208 put_new(Name, "c7", "copy imm32 to rm32 with subop 0 (mov)");
1209
1210 :(code)
1211 void test_copy_imm32_to_mem_at_rm32() {
1212 Reg[EBX].i = 0x60;
1213 run(
1214 "== code 0x1\n"
1215
1216 " c7 03 0a 0b 0c 0d \n"
1217
1218 );
1219 CHECK_TRACE_CONTENTS(
1220 "run: copy imm32 to r/m32\n"
1221 "run: effective address is 0x00000060 (EBX)\n"
1222 "run: imm32 is 0x0d0c0b0a\n"
1223 );
1224 }
1225
1226 :(before "End Single-Byte Opcodes")
1227 case 0xc7: {
1228 const uint8_t modrm = next();
1229 trace(Callstack_depth+1, "run") << "copy imm32 to r/m32" << end();
1230 const uint8_t subop = (modrm>>3)&0x7;
1231 if (subop != 0) {
1232 cerr << "unrecognized subop for opcode c7: " << NUM(subop) << " (only 0/copy currently implemented)\n";
1233 exit(1);
1234 }
1235 int32_t* dest = effective_address(modrm);
1236 const int32_t src = next32();
1237 trace(Callstack_depth+1, "run") << "imm32 is 0x" << HEXWORD << src << end();
1238 *dest = src;
1239 break;
1240 }
1241
1242
1243
1244 :(before "End Initialize Op Names")
1245 put_new(Name, "68", "push imm32 to stack (push)");
1246
1247 :(code)
1248 void test_push_imm32() {
1249 Mem.push_back(vma(0xbd000000));
1250 Reg[ESP].u = 0xbd000014;
1251 run(
1252 "== code 0x1\n"
1253
1254 " 68 af 00 00 00 \n"
1255 );
1256 CHECK_TRACE_CONTENTS(
1257 "run: push imm32 0x000000af\n"
1258 "run: ESP is now 0xbd000010\n"
1259 "run: contents at ESP: 0x000000af\n"
1260 );
1261 }
1262
1263 :(before "End Single-Byte Opcodes")
1264 case 0x68: {
1265 const uint32_t val = static_cast<uint32_t>(next32());
1266 trace(Callstack_depth+1, "run") << "push imm32 0x" << HEXWORD << val << end();
1267
1268 push(val);
1269 trace(Callstack_depth+1, "run") << "ESP is now 0x" << HEXWORD << Reg[ESP].u << end();
1270 trace(Callstack_depth+1, "run") << "contents at ESP: 0x" << HEXWORD << read_mem_u32(Reg[ESP].u) << end();
1271 break;
1272 }
1273
1274
1275
1276 :(before "End Initialize Op Names")
1277 put_new(Name, "69", "multiply rm32 by imm32 and store result in r32 (imul)");
1278
1279 :(code)
1280 void test_multiply_imm32() {
1281 Reg[EAX].i = 2;
1282 Reg[EBX].i = 3;
1283 run(
1284 "== code 0x1\n"
1285
1286 " 69 c3 04 00 00 00 \n"
1287
1288 );
1289 CHECK_TRACE_CONTENTS(
1290 "run: multiply r/m32 by 0x00000004 and store result in EAX\n"
1291 "run: r/m32 is EBX\n"
1292 "run: storing 0x0000000c\n"
1293 );
1294 }
1295
1296 :(before "End Single-Byte Opcodes")
1297 case 0x69: {
1298 const uint8_t modrm = next();
1299 const uint8_t rdest = (modrm>>3)&0x7;
1300 const int32_t val = next32();
1301 trace(Callstack_depth+1, "run") << "multiply r/m32 by 0x" << HEXWORD << val << " and store result in " << rname(rdest) << end();
1302 const int32_t* signed_arg1 = effective_address(modrm);
1303 int32_t result = *signed_arg1 * val;
1304 int64_t full_result = static_cast<int64_t>(*signed_arg1) * val;
1305 OF = (result != full_result);
1306 CF = OF;
1307 trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
1308 Reg[rdest].i = result;
1309 trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[rdest].i << end();
1310 break;
1311 }