https://github.com/akkartik/mu/blob/master/subx/014indirect_addressing.cc
  1 //: operating on memory at the address provided by some register
  2 //: we'll now start providing data in a separate segment
  3 
  4 void test_add_r32_to_mem_at_r32() {
  5   Reg[EBX].i = 0x10;
  6   Reg[EAX].i = 0x2000;
  7   run(
  8       "== code 0x1\n"
  9       // op     ModR/M  SIB   displacement  immediate
 10       "  01     18                                    \n"  // add EBX to *EAX
 11       // ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX)
 12       "== data 0x2000\n"
 13       "01 00 00 00\n"  // 0x00000001
 14   );
 15   CHECK_TRACE_CONTENTS(
 16       "run: add EBX to r/m32\n"
 17       "run: effective address is 0x00002000 (EAX)\n"
 18       "run: storing 0x00000011\n"
 19   );
 20 }
 21 
 22 :(before "End Mod Special-cases(addr)")
 23 case 0:  // indirect addressing
 24   switch (rm) {
 25   default:  // address in register
 26     trace(Callstack_depth+1, "run") << "effective address is 0x" << HEXWORD << Reg[rm].u << " (" << rname(rm) << ")" << end();
 27     addr = Reg[rm].u;
 28     break;
 29   // End Mod 0 Special-cases(addr)
 30   }
 31   break;
 32 
 33 //:
 34 
 35 :(before "End Initialize Op Names")
 36 put_new(Name, "03", "add rm32 to r32 (add)");
 37 
 38 :(code)
 39 void test_add_mem_at_r32_to_r32() {
 40   Reg[EAX].i = 0x2000;
 41   Reg[EBX].i = 0x10;
 42   run(
 43       "== code 0x1\n"
 44       // op     ModR/M  SIB   displacement  immediate
 45       "  03     18                                    \n"  // add *EAX to EBX
 46       // ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX)
 47       "== data 0x2000\n"
 48       "01 00 00 00\n"  // 0x00000001
 49   );
 50   CHECK_TRACE_CONTENTS(
 51       "run: add r/m32 to EBX\n"
 52       "run: effective address is 0x00002000 (EAX)\n"
 53       "run: storing 0x00000011\n"
 54   );
 55 }
 56 
 57 :(before "End Single-Byte Opcodes")
 58 case 0x03: {  // add r/m32 to r32
 59   const uint8_t modrm = next();
 60   const uint8_t arg1 = (modrm>>3)&0x7;
 61   trace(Callstack_depth+1, "run") << "add r/m32 to " << rname(arg1) << end();
 62   const int32_t* signed_arg2 = effective_address(modrm);
 63   int32_t signed_result = Reg[arg1].i + *signed_arg2;
 64   SF = (signed_result < 0);
 65   ZF = (signed_result == 0);
 66   int64_t signed_full_result = static_cast<int64_t>(Reg[arg1].i) + *signed_arg2;
 67   OF = (signed_result != signed_full_result);
 68   // set CF
 69   uint32_t unsigned_arg2 = static_cast<uint32_t>(*signed_arg2);
 70   uint32_t unsigned_result = Reg[arg1].u + unsigned_arg2;
 71   uint64_t unsigned_full_result = static_cast<uint64_t>(Reg[arg1].u) + unsigned_arg2;
 72   CF = (unsigned_result != unsigned_full_result);
 73   trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
 74   Reg[arg1].i = signed_result;
 75   trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[arg1].i << end();
 76   break;
 77 }
 78 
 79 :(code)
 80 void test_add_mem_at_r32_to_r32_signed_overflow() {
 81   Reg[EAX].i = 0x2000;
 82   Reg[EBX].i = 0x7fffffff;  // largest positive signed integer
 83   run(
 84       "== code 0x1\n"
 85       // op     ModR/M  SIB   displacement  immediate
 86       "  03     18                                    \n" // add *EAX to EBX
 87       // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
 88       "== data 0x2000\n"
 89       "01 00 00 00\n"  // 1
 90   );
 91   CHECK_TRACE_CONTENTS(
 92       "run: add r/m32 to EBX\n"
 93       "run: effective address is 0x00002000 (EAX)\n"
 94       "run: effective address contains 1\n"
 95       "run: SF=1; ZF=0; CF=0; OF=1\n"
 96       "run: storing 0x80000000\n"
 97   );
 98 }
 99 
100 void test_add_mem_at_r32_to_r32_unsigned_overflow() {
101   Reg[EAX].u = 0x2000;
102   Reg[EBX].u = 0xffffffff;  // largest unsigned number
103   run(
104       "== code 0x1\n"
105       // op     ModR/M  SIB   displacement  immediate
106       "  03     18                                    \n" // add *EAX to EBX
107       // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
108       "== data 0x2000\n"
109       "01 00 00 00\n"
110   );
111   CHECK_TRACE_CONTENTS(
112       "run: add r/m32 to EBX\n"
113       "run: effective address is 0x00002000 (EAX)\n"
114       "run: effective address contains 1\n"
115       "run: SF=0; ZF=1; CF=1; OF=0\n"
116       "run: storing 0x00000000\n"
117   );
118 }
119 
120 void test_add_mem_at_r32_to_r32_unsigned_and_signed_overflow() {
121   Reg[EAX].u = 0x2000;
122   Reg[EBX].u = 0x80000000;  // smallest negative signed integer
123   run(
124       "== code 0x1\n"
125       // op     ModR/M  SIB   displacement  immediate
126       "  03     18                                    \n" // add *EAX to EBX
127       // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
128       "== data 0x2000\n"
129       "00 00 00 80\n"  // smallest negative signed integer
130   );
131   CHECK_TRACE_CONTENTS(
132       "run: add r/m32 to EBX\n"
133       "run: effective address is 0x00002000 (EAX)\n"
134       "run: effective address contains 80000000\n"
135       "run: SF=0; ZF=1; CF=1; OF=1\n"
136       "run: storing 0x00000000\n"
137   );
138 }
139 
140 //:: subtract
141 
142 :(code)
143 void test_subtract_r32_from_mem_at_r32() {
144   Reg[EAX].i = 0x2000;
145   Reg[EBX].i = 1;
146   run(
147       "== code 0x1\n"
148       // op     ModR/M  SIB   displacement  immediate
149       "  29     18                                    \n"  // subtract EBX from *EAX
150       // ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX)
151       "== data 0x2000\n"
152       "0a 00 00 00\n"  // 0x0000000a
153   );
154   CHECK_TRACE_CONTENTS(
155       "run: subtract EBX from r/m32\n"
156       "run: effective address is 0x00002000 (EAX)\n"
157       "run: storing 0x00000009\n"
158   );
159 }
160 
161 //:
162 
163 :(before "End Initialize Op Names")
164 put_new(Name, "2b", "subtract rm32 from r32 (sub)");
165 
166 :(code)
167 void test_subtract_mem_at_r32_from_r32() {
168   Reg[EAX].i = 0x2000;
169   Reg[EBX].i = 10;
170   run(
171       "== code 0x1\n"
172       // op     ModR/M  SIB   displacement  immediate
173       "  2b     18                                    \n"  // subtract *EAX from EBX
174       // ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX)
175       "== data 0x2000\n"
176       "01 00 00 00\n"  // 0x00000001
177   );
178   CHECK_TRACE_CONTENTS(
179       "run: subtract r/m32 from EBX\n"
180       "run: effective address is 0x00002000 (EAX)\n"
181       "run: storing 0x00000009\n"
182   );
183 }
184 
185 :(before "End Single-Byte Opcodes")
186 case 0x2b: {  // subtract r/m32 from r32
187   const uint8_t modrm = next();
188   const uint8_t arg1 = (modrm>>3)&0x7;
189   trace(Callstack_depth+1, "run") << "subtract r/m32 from " << rname(arg1) << end();
190   const int32_t* signed_arg2 = effective_address(modrm);
191   const int32_t signed_result = Reg[arg1].i - *signed_arg2;
192   SF = (signed_result < 0);
193   ZF = (signed_result == 0);
194   int64_t signed_full_result = static_cast<int64_t>(Reg[arg1].i) - *signed_arg2;
195   OF = (signed_result != signed_full_result);
196   // set CF
197   uint32_t unsigned_arg2 = static_cast<uint32_t>(*signed_arg2);
198   uint32_t unsigned_result = Reg[arg1].u - unsigned_arg2;
199   uint64_t unsigned_full_result = static_cast<uint64_t>(Reg[arg1].u) - unsigned_arg2;
200   CF = (unsigned_result != unsigned_full_result);
201   trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
202   Reg[arg1].i = signed_result;
203   trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[arg1].i << end();
204   break;
205 }
206 
207 :(code)
208 void test_subtract_mem_at_r32_from_r32_signed_overflow() {
209   Reg[EAX].i = 0x2000;
210   Reg[EBX].i = 0x80000000;  // smallest negative signed integer
211   run(
212       "== code 0x1\n"
213       // op     ModR/M  SIB   displacement  immediate
214       "  2b     18                                    \n"  // subtract *EAX from EBX
215       // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
216       "== data 0x2000\n"
217       "ff ff ff 7f\n"  // largest positive signed integer
218   );
219   CHECK_TRACE_CONTENTS(
220       "run: subtract r/m32 from EBX\n"
221       "run: effective address is 0x00002000 (EAX)\n"
222       "run: effective address contains 7fffffff\n"
223       "run: SF=0; ZF=0; CF=0; OF=1\n"
224       "run: storing 0x00000001\n"
225   );
226 }
227 
228 void test_subtract_mem_at_r32_from_r32_unsigned_overflow() {
229   Reg[EAX].i = 0x2000;
230   Reg[EBX].i = 0;
231   run(
232       "== code 0x1\n"
233       // op     ModR/M  SIB   displacement  immediate
234       "  2b     18                                    \n"  // subtract *EAX from EBX
235       // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
236       "== data 0x2000\n"
237       "01 00 00 00\n"  // 1
238   );
239   CHECK_TRACE_CONTENTS(
240       "run: subtract r/m32 from EBX\n"
241       "run: effective address is 0x00002000 (EAX)\n"
242       "run: effective address contains 1\n"
243       "run: SF=1; ZF=0; CF=1; OF=0\n"
244       "run: storing 0xffffffff\n"
245   );
246 }
247 
248 void test_subtract_mem_at_r32_from_r32_signed_and_unsigned_overflow() {
249   Reg[EAX].i = 0x2000;
250   Reg[EBX].i = 0;
251   run(
252       "== code 0x1\n"
253       // op     ModR/M  SIB   displacement  immediate
254       "  2b     18                                    \n"  // subtract *EAX from EBX
255       // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
256       "== data 0x2000\n"
257       "00 00 00 80\n"  // smallest negative signed integer
258   );
259   CHECK_TRACE_CONTENTS(
260       "run: subtract r/m32 from EBX\n"
261       "run: effective address is 0x00002000 (EAX)\n"
262       "run: effective address contains 80000000\n"
263       "run: SF=1; ZF=0; CF=1; OF=1\n"
264       "run: storing 0x80000000\n"
265   );
266 }
267 
268 //:: and
269 :(code)
270 void test_and_r32_with_mem_at_r32() {
271   Reg[EAX].i = 0x2000;
272   Reg[EBX].i = 0xff;
273   run(
274       "== code 0x1\n"
275       // op     ModR/M  SIB   displacement  immediate
276       "  21     18                                    \n"  // and EBX with *EAX
277       // ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX)
278       "== data 0x2000\n"
279       "0d 0c 0b 0a\n"  // 0x0a0b0c0d
280   );
281   CHECK_TRACE_CONTENTS(
282       "run: and EBX with r/m32\n"
283       "run: effective address is 0x00002000 (EAX)\n"
284       "run: storing 0x0000000d\n"
285   );
286 }
287 
288 //:
289 
290 :(before "End Initialize Op Names")
291 put_new(Name, "23", "r32 = bitwise AND of r32 with rm32 (and)");
292 
293 :(code)
294 void test_and_mem_at_r32_with_r32() {
295   Reg[EAX].i = 0x2000;
296   Reg[EBX].i = 0x0a0b0c0d;
297   run(
298       "== code 0x1\n"
299       // op     ModR/M  SIB   displacement  immediate
300       "  23     18                                    \n"  // and *EAX with EBX
301       // ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX)
302       "== data 0x2000\n"
303       "ff 00 00 00\n"  // 0x000000ff
304   );
305   CHECK_TRACE_CONTENTS(
306       "run: and r/m32 with EBX\n"
307       "run: effective address is 0x00002000 (EAX)\n"
308       "run: storing 0x0000000d\n"
309   );
310 }
311 
312 :(before "End Single-Byte Opcodes")
313 case 0x23: {  // and r/m32 with r32
314   const uint8_t modrm = next();
315   const uint8_t arg1 = (modrm>>3)&0x7;
316   trace(Callstack_depth+1, "run") << "and r/m32 with " << rname(arg1) << end();
317   // bitwise ops technically operate on unsigned numbers, but it makes no
318   // difference
319   const int32_t* signed_arg2 = effective_address(modrm);
320   Reg[arg1].i &= *signed_arg2;
321   trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[arg1].i << end();
322   SF = (Reg[arg1].i >> 31);
323   ZF = (Reg[arg1].i == 0);
324   CF = false;
325   OF = false;
326   trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
327   break;
328 }
329 
330 //:: or
331 
332 :(code)
333 void test_or_r32_with_mem_at_r32() {
334   Reg[EAX].i = 0x2000;
335   Reg[EBX].i = 0xa0b0c0d0;
336   run(
337       "== code 0x1\n"
338       // op     ModR/M  SIB   displacement  immediate
339       "  09     18                                   #\n"  // EBX with *EAX
340       // ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX)
341       "== data 0x2000\n"
342       "0d 0c 0b 0a\n"  // 0x0a0b0c0d
343   );
344   CHECK_TRACE_CONTENTS(
345       "run: or EBX with r/m32\n"
346       "run: effective address is 0x00002000 (EAX)\n"
347       "run: storing 0xaabbccdd\n"
348   );
349 }
350 
351 //:
352 
353 :(before "End Initialize Op Names")
354 put_new(Name, "0b", "r32 = bitwise OR of r32 with rm32 (or)");
355 
356 :(code)
357 void test_or_mem_at_r32_with_r32() {
358   Reg[EAX].i = 0x2000;
359   Reg[EBX].i = 0xa0b0c0d0;
360   run(
361       "== code 0x1\n"
362       // op     ModR/M  SIB   displacement  immediate
363       "  0b     18                                    \n"  // or *EAX with EBX
364       // ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX)
365       "== data 0x2000\n"
366       "0d 0c 0b 0a\n"  // 0x0a0b0c0d
367   );
368   CHECK_TRACE_CONTENTS(
369       "run: or r/m32 with EBX\n"
370       "run: effective address is 0x00002000 (EAX)\n"
371       "run: storing 0xaabbccdd\n"
372   );
373 }
374 
375 :(before "End Single-Byte Opcodes")
376 case 0x0b: {  // or r/m32 with r32
377   const uint8_t modrm = next();
378   const uint8_t arg1 = (modrm>>3)&0x7;
379   trace(Callstack_depth+1, "run") << "or r/m32 with " << rname(arg1) << end();
380   // bitwise ops technically operate on unsigned numbers, but it makes no
381   // difference
382   const int32_t* signed_arg2 = effective_address(modrm);
383   Reg[arg1].i |= *signed_arg2;
384   trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[arg1].i << end();
385   SF = (Reg[arg1].i >> 31);
386   ZF = (Reg[arg1].i == 0);
387   CF = false;
388   OF = false;
389   trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
390   break;
391 }
392 
393 //:: xor
394 
395 :(code)
396 void test_xor_r32_with_mem_at_r32() {
397   Reg[EAX].i = 0x2000;
398   Reg[EBX].i = 0xa0b0c0d0;
399   run(
400       "== code 0x1\n"
401       // op     ModR/M  SIB   displacement  immediate
402       "  31     18                                    \n"  // xor EBX with *EAX
403       "== data 0x2000\n"
404       "0d 0c bb aa\n"  // 0xaabb0c0d
405   );
406   CHECK_TRACE_CONTENTS(
407       "run: xor EBX with r/m32\n"
408       "run: effective address is 0x00002000 (EAX)\n"
409       "run: storing 0x0a0bccdd\n"
410   );
411 }
412 
413 //:
414 
415 :(before "End Initialize Op Names")
416 put_new(Name, "33", "r32 = bitwise XOR of r32 with rm32 (xor)");
417 
418 :(code)
419 void test_xor_mem_at_r32_with_r32() {
420   Reg[EAX].i = 0x2000;
421   Reg[EBX].i = 0xa0b0c0d0;
422   run(
423       "== code 0x1\n"
424       // op     ModR/M  SIB   displacement  immediate
425       "  33     18                                    \n"  // xor *EAX with EBX
426       // ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX)
427       "== data 0x2000\n"
428       "0d 0c 0b 0a\n"  // 0x0a0b0c0d
429   );
430   CHECK_TRACE_CONTENTS(
431       "run: xor r/m32 with EBX\n"
432       "run: effective address is 0x00002000 (EAX)\n"
433       "run: storing 0xaabbccdd\n"
434   );
435 }
436 
437 :(before "End Single-Byte Opcodes")
438 case 0x33: {  // xor r/m32 with r32
439   const uint8_t modrm = next();
440   const uint8_t arg1 = (modrm>>3)&0x7;
441   trace(Callstack_depth+1, "run") << "xor r/m32 with " << rname(arg1) << end();
442   // bitwise ops technically operate on unsigned numbers, but it makes no
443   // difference
444   const int32_t* signed_arg2 = effective_address(modrm);
445   Reg[arg1].i |= *signed_arg2;
446   trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[arg1].i << end();
447   SF = (Reg[arg1].i >> 31);
448   ZF = (Reg[arg1].i == 0);
449   CF = false;
450   OF = false;
451   trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
452   break;
453 }
454 
455 //:: not
456 
457 :(code)
458 void test_not_of_mem_at_r32() {
459   Reg[EBX].i = 0x2000;
460   run(
461       "== code 0x1\n"
462       // op     ModR/M  SIB   displacement  immediate
463       "  f7     13                                    \n"  // not *EBX
464       // ModR/M in binary: 00 (indirect mode) 010 (subop not) 011 (dest EBX)
465       "== data 0x2000\n"
466       "ff 00 0f 0f\n"  // 0x0f0f00ff
467   );
468   CHECK_TRACE_CONTENTS(
469       "run: operate on r/m32\n"
470       "run: effective address is 0x00002000 (EBX)\n"
471       "run: subop: not\n"
472       "run: storing 0xf0f0ff00\n"
473   );
474 }
475 
476 //:: compare (cmp)
477 
478 :(code)
479 void test_compare_mem_at_r32_with_r32_greater() {
480   Reg[EAX].i = 0x2000;
481   Reg[EBX].i = 0x0a0b0c07;
482   run(
483       "== code 0x1\n"
484       // op     ModR/M  SIB   displacement  immediate
485       "  39     18                                    \n"  // compare *EAX with EBX
486       // ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX)
487       "== data 0x2000\n"
488       "0d 0c 0b 0a\n"  // 0x0a0b0c0d
489   );
490   CHECK_TRACE_CONTENTS(
491       "run: compare r/m32 with EBX\n"
492       "run: effective address is 0x00002000 (EAX)\n"
493       "run: SF=0; ZF=0; CF=0; OF=0\n"
494   );
495 }
496 
497 :(code)
498 void test_compare_mem_at_r32_with_r32_lesser() {
499   Reg[EAX].i = 0x2000;
500   Reg[EBX].i = 0x0a0b0c0d;
501   run(
502       "== code 0x1\n"
503       // op     ModR/M  SIB   displacement  immediate
504       "  39     18                                    \n"  // compare *EAX with EBX
505       // ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX)
506       "== data 0x2000\n"
507       "07 0c 0b 0a\n"  // 0x0a0b0c0d
508   );
509   CHECK_TRACE_CONTENTS(
510       "run: compare r/m32 with EBX\n"
511       "run: effective address is 0x00002000 (EAX)\n"
512       "run: SF=1; ZF=0; CF=1; OF=0\n"
513   );
514 }
515 
516 :(code)
517 void test_compare_mem_at_r32_with_r32_equal() {
518   Reg[EAX].i = 0x2000;
519   Reg[EBX].i = 0x0a0b0c0d;
520   run(
521       "== code 0x1\n"
522       // op     ModR/M  SIB   displacement  immediate
523       "  39     18                                    \n"  // compare *EAX and EBX
524       // ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX)
525       "== data 0x2000\n"
526       "0d 0c 0b 0a\n"  // 0x0a0b0c0d
527   );
528   CHECK_TRACE_CONTENTS(
529       "run: compare r/m32 with EBX\n"
530       "run: effective address is 0x00002000 (EAX)\n"
531       "run: SF=0; ZF=1; CF=0; OF=0\n"
532   );
533 }
534 
535 //:
536 
537 :(before "End Initialize Op Names")
538 put_new(Name, "3b", "compare: set SF if r32 < rm32 (cmp)");
539 
540 :(code)
541 void test_compare_r32_with_mem_at_r32_greater() {
542   Reg[EAX].i = 0x2000;
543   Reg[EBX].i = 0x0a0b0c0d;
544   run(
545       "== code 0x1\n"
546       // op     ModR/M  SIB   displacement  immediate
547       "  3b     18                                    \n"  // compare EBX with *EAX
548       // ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX)
549       "== data 0x2000\n"
550       "07 0c 0b 0a\n"  // 0x0a0b0c07
551   );
552   CHECK_TRACE_CONTENTS(
553       "run: compare EBX with r/m32\n"
554       "run: effective address is 0x00002000 (EAX)\n"
555       "run: SF=0; ZF=0; CF=0; OF=0\n"
556   );
557 }
558 
559 :(before "End Single-Byte Opcodes")
560 case 0x3b: {  // set SF if r32 < r/m32
561   const uint8_t modrm = next();
562   const uint8_t reg1 = (modrm>>3)&0x7;
563   trace(Callstack_depth+1, "run") << "compare " << rname(reg1) << " with r/m32" << end();
564   const int32_t* signed_arg2 = effective_address(modrm);
565   const int32_t signed_difference = Reg[reg1].i - *signed_arg2;
566   SF = (signed_difference < 0);
567   ZF = (signed_difference == 0);
568   int64_t full_signed_difference = static_cast<int64_t>(Reg[reg1].i) - *signed_arg2;
569   OF = (signed_difference != full_signed_difference);
570   const uint32_t unsigned_arg2 = static_cast<uint32_t>(*signed_arg2);
571   const uint32_t unsigned_difference = Reg[reg1].u - unsigned_arg2;
572   const uint64_t full_unsigned_difference = static_cast<uint64_t>(Reg[reg1].u) - unsigned_arg2;
573   CF = (unsigned_difference != full_unsigned_difference);
574   trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
575   break;
576 }
577 
578 :(code)
579 void test_compare_r32_with_mem_at_r32_lesser_unsigned_and_signed() {
580   Reg[EAX].i = 0x2000;
581   Reg[EBX].i = 0x0a0b0c07;
582   run(
583       "== code 0x1\n"
584       // op     ModR/M  SIB   displacement  immediate
585       "  3b     18                                    \n"  // compare EBX with *EAX
586       // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
587       "== data 0x2000\n"
588       "0d 0c 0b 0a\n"  // 0x0a0b0c0d
589   );
590   CHECK_TRACE_CONTENTS(
591       "run: compare EBX with r/m32\n"
592       "run: effective address is 0x00002000 (EAX)\n"
593       "run: effective address contains a0b0c0d\n"
594       "run: SF=1; ZF=0; CF=1; OF=0\n"
595   );
596 }
597 
598 void test_compare_r32_with_mem_at_r32_lesser_unsigned_and_signed_due_to_overflow() {
599   Reg[EAX].i = 0x2000;
600   Reg[EBX].i = 0x7fffffff;  // largest positive signed integer
601   run(
602       "== code 0x1\n"
603       // op     ModR/M  SIB   displacement  immediate
604       "  3b     18                                    \n"  // compare EBX with *EAX
605       // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
606       "== data 0x2000\n"
607       "00 00 00 80\n"  // smallest negative signed integer
608   );
609   CHECK_TRACE_CONTENTS(
610       "run: compare EBX with r/m32\n"
611       "run: effective address is 0x00002000 (EAX)\n"
612       "run: effective address contains 80000000\n"
613       "run: SF=1; ZF=0; CF=1; OF=1\n"
614   );
615 }
616 
617 void test_compare_r32_with_mem_at_r32_lesser_signed() {
618   Reg[EAX].i = 0x2000;
619   Reg[EBX].i = 0xffffffff;  // -1
620   run(
621       "== code 0x1\n"
622       // op     ModR/M  SIB   displacement  immediate
623       "  3b     18                                    \n"  // compare EBX with *EAX
624       // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
625       "== data 0x2000\n"
626       "01 00 00 00\n"  // 1
627   );
628   CHECK_TRACE_CONTENTS(
629       "run: compare EBX with r/m32\n"
630       "run: effective address is 0x00002000 (EAX)\n"
631       "run: effective address contains 1\n"
632       "run: SF=1; ZF=0; CF=0; OF=0\n"
633   );
634 }
635 
636 void test_compare_r32_with_mem_at_r32_lesser_unsigned() {
637   Reg[EAX].i = 0x2000;
638   Reg[EBX].i = 0x00000001;  // 1
639   run(
640       "== code 0x1\n"
641       // op     ModR/M  SIB   displacement  immediate
642       "  3b     18                                    \n"  // compare EBX with *EAX
643       // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
644       "== data 0x2000\n"
645       "ff ff ff ff\n"  // -1
646   );
647   CHECK_TRACE_CONTENTS(
648       "run: compare EBX with r/m32\n"
649       "run: effective address is 0x00002000 (EAX)\n"
650       "run: effective address contains ffffffff\n"
651       "run: SF=0; ZF=0; CF=1; OF=0\n"
652   );
653 }
654 
655 void test_compare_r32_with_mem_at_r32_equal() {
656   Reg[EAX].i = 0x2000;
657   Reg[EBX].i = 0x0a0b0c0d;
658   run(
659       "== code 0x1\n"
660       // op     ModR/M  SIB   displacement  immediate
661       "  3b     18                                    \n"  // compare EBX with *EAX
662       // ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX)
663       "== data 0x2000\n"
664       "0d 0c 0b 0a\n"  // 0x0a0b0c0d
665   );
666   CHECK_TRACE_CONTENTS(
667       "run: compare EBX with r/m32\n"
668       "run: effective address is 0x00002000 (EAX)\n"
669       "run: SF=0; ZF=1; CF=0; OF=0\n"
670   );
671 }
672 
673 //:: copy (mov)
674 
675 void test_copy_r32_to_mem_at_r32() {
676   Reg[EBX].i = 0xaf;
677   Reg[EAX].i = 0x60;
678   run(
679       "== code 0x1\n"
680       // op     ModR/M  SIB   displacement  immediate
681       "  89     18                                    \n"  // copy EBX to *EAX
682       // ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX)
683   );
684   CHECK_TRACE_CONTENTS(
685       "run: copy EBX to r/m32\n"
686       "run: effective address is 0x00000060 (EAX)\n"
687       "run: storing 0x000000af\n"
688   );
689 }
690 
691 //:
692 
693 :(before "End Initialize Op Names")
694 put_new(Name, "8b", "copy rm32 to r32 (mov)");
695 
696 :(code)
697 void test_copy_mem_at_r32_to_r32() {
698   Reg[EAX].i = 0x2000;
699   run(
700       "== code 0x1\n"
701       // op     ModR/M  SIB   displacement  immediate
702       "  8b     18                                    \n"  // copy *EAX to EBX
703       "== data 0x2000\n"
704       "af 00 00 00\n"  // 0x000000af
705   );
706   CHECK_TRACE_CONTENTS(
707       "run: copy r/m32 to EBX\n"
708       "run: effective address is 0x00002000 (EAX)\n"
709       "run: storing 0x000000af\n"
710   );
711 }
712 
713 :(before "End Single-Byte Opcodes")
714 case 0x8b: {  // copy r32 to r/m32
715   const uint8_t modrm = next();
716   const uint8_t rdest = (modrm>>3)&0x7;
717   trace(Callstack_depth+1, "run") << "copy r/m32 to " << rname(rdest) << end();
718   const int32_t* src = effective_address(modrm);
719   Reg[rdest].i = *src;
720   trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *src << end();
721   break;
722 }
723 
724 //:: jump
725 
726 :(code)
727 void test_jump_mem_at_r32() {
728   Reg[EAX].i = 0x2000;
729   run(
730       "== code 0x1\n"
731       // op     ModR/M  SIB   displacement  immediate
732       "  ff     20                                    \n"  // jump to *EAX
733       // ModR/M in binary: 00 (indirect mode) 100 (jump to r/m32) 000 (src EAX)
734       "  b8                                 00 00 00 01\n"
735       "  b8                                 00 00 00 02\n"
736       "== data 0x2000\n"
737       "08 00 00 00\n"  // 0x00000008
738   );
739   CHECK_TRACE_CONTENTS(
740       "run: 0x00000001 opcode: ff\n"
741       "run: jump to r/m32\n"
742       "run: effective address is 0x00002000 (EAX)\n"
743       "run: jumping to 0x00000008\n"
744       "run: 0x00000008 opcode: b8\n"
745   );
746   CHECK_TRACE_DOESNT_CONTAIN("run: 0x00000003 opcode: b8");
747 }
748 
749 :(before "End Op ff Subops")
750 case 4: {  // jump to r/m32
751   trace(Callstack_depth+1, "run") << "jump to r/m32" << end();
752   const int32_t* arg2 = effective_address(modrm);
753   EIP = *arg2;
754   trace(Callstack_depth+1, "run") << "jumping to 0x" << HEXWORD << EIP << end();
755   break;
756 }
757 
758 //:: push
759 
760 :(code)
761 void test_push_mem_at_r32() {
762   Reg[EAX].i = 0x2000;
763   Mem.push_back(vma(0xbd000000));  // manually allocate memory
764   Reg[ESP].u = 0xbd000014;
765   run(
766       "== code 0x1\n"
767       // op     ModR/M  SIB   displacement  immediate
768       "  ff     30                                    \n"  // push *EAX to stack
769       "== data 0x2000\n"
770       "af 00 00 00\n"  // 0x000000af
771   );
772   CHECK_TRACE_CONTENTS(
773       "run: push r/m32\n"
774       "run: effective address is 0x00002000 (EAX)\n"
775       "run: decrementing ESP to 0xbd000010\n"
776       "run: pushing value 0x000000af\n"
777   );
778 }
779 
780 :(before "End Op ff Subops")
781 case 6: {  // push r/m32 to stack
782   trace(Callstack_depth+1, "run") << "push r/m32" << end();
783   const int32_t* val = effective_address(modrm);
784   push(*val);
785   break;
786 }
787 
788 //:: pop
789 
790 :(before "End Initialize Op Names")
791 put_new(Name, "8f", "pop top of stack to rm32 (pop)");
792 
793 :(code)
794 void test_pop_mem_at_r32() {
795   Reg[EAX].i = 0x60;
796   Mem.push_back(vma(0xbd000000));  // manually allocate memory
797   Reg[ESP].u = 0xbd000000;
798   write_mem_i32(0xbd000000, 0x00000030);
799   run(
800       "== code 0x1\n"
801       // op     ModR/M  SIB   displacement  immediate
802       "  8f     00                                    \n"  // pop stack into *EAX
803       // ModR/M in binary: 00 (indirect mode) 000 (pop r/m32) 000 (dest EAX)
804   );
805   CHECK_TRACE_CONTENTS(
806       "run: pop into r/m32\n"
807       "run: effective address is 0x00000060 (EAX)\n"
808       "run: popping value 0x00000030\n"
809       "run: incrementing ESP to 0xbd000004\n"
810   );
811 }
812 
813 :(before "End Single-Byte Opcodes")
814 case 0x8f: {  // pop stack into r/m32
815   const uint8_t modrm = next();
816   const uint8_t subop = (modrm>>3)&0x7;
817   switch (subop) {
818     case 0: {
819       trace(Callstack_depth+1, "run") << "pop into r/m32" << end();
820       int32_t* dest = effective_address(modrm);
821       *dest = pop();
822       break;
823     }
824   }
825   break;
826 }
827 
828 //:: special-case for loading address from disp32 rather than register
829 
830 :(code)
831 void test_add_r32_to_mem_at_displacement() {
832   Reg[EBX].i = 0x10;  // source
833   run(
834       "== code 0x1\n"
835       // op     ModR/M  SIB   displacement  immediate
836       "  01     1d            00 20 00 00             \n"  // add EBX to *0x2000
837       // ModR/M in binary: 00 (indirect mode) 011 (src EBX) 101 (dest in disp32)
838       "== data 0x2000\n"
839       "01 00 00 00\n"  // 0x00000001
840   );
841   CHECK_TRACE_CONTENTS(
842       "run: add EBX to r/m32\n"
843       "run: effective address is 0x00002000 (disp32)\n"
844       "run: storing 0x00000011\n"
845   );
846 }
847 
848 :(before "End Mod 0 Special-cases(addr)")
849 case 5:  // exception: mod 0b00 rm 0b101 => incoming disp32
850   addr = next32();
851   trace(Callstack_depth+1, "run") << "effective address is 0x" << HEXWORD << addr << " (disp32)" << end();
852   break;
853 
854 //:
855 
856 :(code)
857 void test_add_r32_to_mem_at_r32_plus_disp8() {
858   Reg[EBX].i = 0x10;  // source
859   Reg[EAX].i = 0x1ffe;  // dest
860   run(
861       "== code 0x1\n"
862       // op     ModR/M  SIB   displacement  immediate
863       "  01     58            02                      \n"  // add EBX to *(EAX+2)
864       // ModR/M in binary: 01 (indirect+disp8 mode) 011 (src EBX) 000 (dest EAX)
865       "== data 0x2000\n"
866       "01 00 00 00\n"  // 0x00000001
867   );
868   CHECK_TRACE_CONTENTS(
869       "run: add EBX to r/m32\n"
870       "run: effective address is initially 0x00001ffe (EAX)\n"
871       "run: effective address is 0x00002000 (after adding disp8)\n"
872       "run: storing 0x00000011\n"
873   );
874 }
875 
876 :(before "End Mod Special-cases(addr)")
877 case 1:  // indirect + disp8 addressing
878   switch (rm) {
879   default:
880     addr = Reg[rm].u;
881     trace(Callstack_depth+1, "run") << "effective address is initially 0x" << HEXWORD << addr << " (" << rname(rm) << ")" << end();
882     break;
883   // End Mod 1 Special-cases(addr)
884   }
885   if (addr > 0) {
886     addr += static_cast<int8_t>(next());
887     trace(Callstack_depth+1, "run") << "effective address is 0x" << HEXWORD << addr << " (after adding disp8)" << end();
888   }
889   break;
890 
891 :(code)
892 void test_add_r32_to_mem_at_r32_plus_negative_disp8() {
893   Reg[EBX].i = 0x10;  // source
894   Reg[EAX].i = 0x2001;  // dest
895   run(
896       "== code 0x1\n"
897       // op     ModR/M  SIB   displacement  immediate
898       "  01     58            ff                      \n"  // add EBX to *(EAX-1)
899       // ModR/M in binary: 01 (indirect+disp8 mode) 011 (src EBX) 000 (dest EAX)
900       "== data 0x2000\n"
901       "01 00 00 00\n"  // 0x00000001
902   );
903   CHECK_TRACE_CONTENTS(
904       "run: add EBX to r/m32\n"
905       "run: effective address is initially 0x00002001 (EAX)\n"
906       "run: effective address is 0x00002000 (after adding disp8)\n"
907       "run: storing 0x00000011\n"
908   );
909 }
910 
911 //:
912 
913 :(code)
914 void test_add_r32_to_mem_at_r32_plus_disp32() {
915   Reg[EBX].i = 0x10;  // source
916   Reg[EAX].i = 0x1ffe;  // dest
917   run(
918       "== code 0x1\n"
919       // op     ModR/M  SIB   displacement  immediate
920       "  01     98            02 00 00 00             \n"  // add EBX to *(EAX+2)
921       // ModR/M in binary: 10 (indirect+disp32 mode) 011 (src EBX) 000 (dest EAX)
922       "== data 0x2000\n"
923       "01 00 00 00\n"  // 0x00000001
924   );
925   CHECK_TRACE_CONTENTS(
926       "run: add EBX to r/m32\n"
927       "run: effective address is initially 0x00001ffe (EAX)\n"
928       "run: effective address is 0x00002000 (after adding disp32)\n"
929       "run: storing 0x00000011\n"
930   );
931 }
932 
933 :(before "End Mod Special-cases(addr)")
934 case 2:  // indirect + disp32 addressing
935   switch (rm) {
936   default:
937     addr = Reg[rm].u;
938     trace(Callstack_depth+1, "run") << "effective address is initially 0x" << HEXWORD << addr << " (" << rname(rm) << ")" << end();
939     break;
940   // End Mod 2 Special-cases(addr)
941   }
942   if (addr > 0) {
943     addr += next32();
944     trace(Callstack_depth+1, "run") << "effective address is 0x" << HEXWORD << addr << " (after adding disp32)" << end();
945   }
946   break;
947 
948 :(code)
949 void test_add_r32_to_mem_at_r32_plus_negative_disp32() {
950   Reg[EBX].i = 0x10;  // source
951   Reg[EAX].i = 0x2001;  // dest
952   run(
953       "== code 0x1\n"
954       // op     ModR/M  SIB   displacement  immediate
955       "  01     98            ff ff ff ff             \n"  // add EBX to *(EAX-1)
956       // ModR/M in binary: 10 (indirect+disp32 mode) 011 (src EBX) 000 (dest EAX)
957       "== data 0x2000\n"
958       "01 00 00 00\n"  // 0x00000001
959   );
960   CHECK_TRACE_CONTENTS(
961       "run: add EBX to r/m32\n"
962       "run: effective address is initially 0x00002001 (EAX)\n"
963       "run: effective address is 0x00002000 (after adding disp32)\n"
964       "run: storing 0x00000011\n"
965   );
966 }
967 
968 //:: copy address (lea)
969 
970 :(before "End Initialize Op Names")
971 put_new(Name, "8d", "copy address in rm32 into r32 (lea)");
972 
973 :(code)
974 void test_copy_address() {
975   Reg[EAX].u = 0x2000;
976   run(
977       "== code 0x1\n"
978       // op     ModR/M  SIB   displacement  immediate
979       "  8d     18                                    \n"  // copy address in EAX into EBX
980       // ModR/M in binary: 00 (indirect mode) 011 (dest EBX) 000 (src EAX)
981   );
982   CHECK_TRACE_CONTENTS(
983       "run: copy address into EBX\n"
984       "run: effective address is 0x00002000 (EAX)\n"
985   );
986 }
987 
988 :(before "End Single-Byte Opcodes")
989 case 0x8d: {  // copy address of m32 to r32
990   const uint8_t modrm = next();
991   const uint8_t arg1 = (modrm>>3)&0x7;
992   trace(Callstack_depth+1, "run") << "copy address into " << rname(arg1) << end();
993   Reg[arg1].u = effective_address_number(modrm);
994   break;
995 }