diff options
author | Kartik Agaram <vc@akkartik.com> | 2019-03-12 18:56:55 -0700 |
---|---|---|
committer | Kartik Agaram <vc@akkartik.com> | 2019-03-12 19:14:12 -0700 |
commit | 4a943d4ed313eff001504c2b5c472266e86a38af (patch) | |
tree | a5757233a8c81b303a808f251180c7344071ed51 /subx/014indirect_addressing.cc | |
parent | 43711b0e9f18e0225ce14687fb6ea0902aa6fc61 (diff) | |
download | mu-4a943d4ed313eff001504c2b5c472266e86a38af.tar.gz |
5001 - drop the :(scenario) DSL
I've been saying for a while[1][2][3] that adding extra abstractions makes things harder for newcomers, and adding new notations doubly so. And then I notice this DSL in my own backyard. Makes me feel like a hypocrite. [1] https://news.ycombinator.com/item?id=13565743#13570092 [2] https://lobste.rs/s/to8wpr/configuration_files_are_canary_warning [3] https://lobste.rs/s/mdmcdi/little_languages_by_jon_bentley_1986#c_3miuf2 The implementation of the DSL was also highly hacky: a) It was happening in the tangle/ tool, but was utterly unrelated to tangling layers. b) There were several persnickety constraints on the different kinds of lines and the specific order they were expected in. I kept finding bugs where the translator would silently do the wrong thing. Or the error messages sucked, and readers may be stuck looking at the generated code to figure out what happened. Fixing error messages would require a lot more code, which is one of my arguments against DSLs in the first place: they may be easy to implement, but they're hard to design to go with the grain of the underlying platform. They require lots of iteration. Is that effort worth prioritizing in this project? On the other hand, the DSL did make at least some readers' life easier, the ones who weren't immediately put off by having to learn a strange syntax. There were fewer quotes to parse, fewer backslash escapes. Anyway, since there are also people who dislike having to put up with strange syntaxes, we'll call that consideration a wash and tear this DSL out. --- This commit was sheer drudgery. Hopefully it won't need to be redone with a new DSL because I grow sick of backslashes.
Diffstat (limited to 'subx/014indirect_addressing.cc')
-rw-r--r-- | subx/014indirect_addressing.cc | 847 |
1 files changed, 505 insertions, 342 deletions
diff --git a/subx/014indirect_addressing.cc b/subx/014indirect_addressing.cc index 448f4231..f591f0cf 100644 --- a/subx/014indirect_addressing.cc +++ b/subx/014indirect_addressing.cc @@ -1,18 +1,23 @@ //: operating on memory at the address provided by some register //: we'll now start providing data in a separate segment -:(scenario add_r32_to_mem_at_r32) -% Reg[EBX].i = 0x10; -% Reg[EAX].i = 0x2000; -== 0x1 # code segment -# op ModR/M SIB displacement immediate - 01 18 # add EBX to *EAX -# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) -== 0x2000 # data segment -01 00 00 00 # 1 -+run: add EBX to r/m32 -+run: effective address is 0x00002000 (EAX) -+run: storing 0x00000011 +void test_add_r32_to_mem_at_r32() { + Reg[EBX].i = 0x10; + Reg[EAX].i = 0x2000; + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " 01 18 \n" // add EBX to *EAX + // ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) + "== 0x2000\n" // data segment + "01 00 00 00\n" // 0x00000001 + ); + CHECK_TRACE_CONTENTS( + "run: add EBX to r/m32\n" + "run: effective address is 0x00002000 (EAX)\n" + "run: storing 0x00000011\n" + ); +} :(before "End Mod Special-cases(addr)") case 0: // indirect addressing @@ -30,18 +35,24 @@ case 0: // indirect addressing :(before "End Initialize Op Names") put_new(Name, "03", "add rm32 to r32 (add)"); -:(scenario add_mem_at_r32_to_r32) -% Reg[EAX].i = 0x2000; -% Reg[EBX].i = 0x10; -== 0x1 # code segment -# op ModR/M SIB displacement immediate - 03 18 # add *EAX to EBX -# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) -== 0x2000 # data segment -01 00 00 00 # 1 -+run: add r/m32 to EBX -+run: effective address is 0x00002000 (EAX) -+run: storing 0x00000011 +:(code) +void test_add_mem_at_r32_to_r32() { + Reg[EAX].i = 0x2000; + Reg[EBX].i = 0x10; + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " 03 18 \n" // add *EAX to EBX + // ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) + "== 0x2000\n" // data segment + "01 00 00 00\n" // 0x00000001 + ); + CHECK_TRACE_CONTENTS( + "run: add r/m32 to EBX\n" + "run: effective address is 0x00002000 (EAX)\n" + "run: storing 0x00000011\n" + ); +} :(before "End Single-Byte Opcodes") case 0x03: { // add r/m32 to r32 @@ -55,36 +66,48 @@ case 0x03: { // add r/m32 to r32 //:: subtract -:(scenario subtract_r32_from_mem_at_r32) -% Reg[EAX].i = 0x2000; -% Reg[EBX].i = 1; -== 0x1 # code segment -# op ModR/M SIB displacement immediate - 29 18 # subtract EBX from *EAX -# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) -== 0x2000 # data segment -0a 00 00 00 # 10 -+run: subtract EBX from r/m32 -+run: effective address is 0x00002000 (EAX) -+run: storing 0x00000009 +:(code) +void test_subtract_r32_from_mem_at_r32() { + Reg[EAX].i = 0x2000; + Reg[EBX].i = 1; + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " 29 18 \n" // subtract EBX from *EAX + // ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) + "== 0x2000\n" // data segment + "0a 00 00 00\n" // 0x0000000a + ); + CHECK_TRACE_CONTENTS( + "run: subtract EBX from r/m32\n" + "run: effective address is 0x00002000 (EAX)\n" + "run: storing 0x00000009\n" + ); +} //: :(before "End Initialize Op Names") put_new(Name, "2b", "subtract rm32 from r32 (sub)"); -:(scenario subtract_mem_at_r32_from_r32) -% Reg[EAX].i = 0x2000; -% Reg[EBX].i = 10; -== 0x1 # code segment -# op ModR/M SIB displacement immediate - 2b 18 # subtract *EAX from EBX -# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) -== 0x2000 # data segment -01 00 00 00 # 1 -+run: subtract r/m32 from EBX -+run: effective address is 0x00002000 (EAX) -+run: storing 0x00000009 +:(code) +void test_subtract_mem_at_r32_from_r32() { + Reg[EAX].i = 0x2000; + Reg[EBX].i = 10; + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " 2b 18 \n" // subtract *EAX from EBX + // ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) + "== 0x2000\n" // data segment + "01 00 00 00\n" // 0x00000001 + ); + CHECK_TRACE_CONTENTS( + "run: subtract r/m32 from EBX\n" + "run: effective address is 0x00002000 (EAX)\n" + "run: storing 0x00000009\n" + ); +} :(before "End Single-Byte Opcodes") case 0x2b: { // subtract r/m32 from r32 @@ -97,37 +120,48 @@ case 0x2b: { // subtract r/m32 from r32 } //:: and - -:(scenario and_r32_with_mem_at_r32) -% Reg[EAX].i = 0x2000; -% Reg[EBX].i = 0xff; -== 0x1 # code segment -# op ModR/M SIB displacement immediate - 21 18 # and EBX with *EAX -# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) -== 0x2000 # data segment -0d 0c 0b 0a # 0x0a0b0c0d -+run: and EBX with r/m32 -+run: effective address is 0x00002000 (EAX) -+run: storing 0x0000000d +:(code) +void test_and_r32_with_mem_at_r32() { + Reg[EAX].i = 0x2000; + Reg[EBX].i = 0xff; + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " 21 18 \n" // and EBX with *EAX + // ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) + "== 0x2000\n" // data segment + "0d 0c 0b 0a\n" // 0x0a0b0c0d + ); + CHECK_TRACE_CONTENTS( + "run: and EBX with r/m32\n" + "run: effective address is 0x00002000 (EAX)\n" + "run: storing 0x0000000d\n" + ); +} //: :(before "End Initialize Op Names") put_new(Name, "23", "r32 = bitwise AND of r32 with rm32 (and)"); -:(scenario and_mem_at_r32_with_r32) -% Reg[EAX].i = 0x2000; -% Reg[EBX].i = 0x0a0b0c0d; -== 0x1 # code segment -# op ModR/M SIB displacement immediate - 23 18 # and *EAX with EBX -# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) -== 0x2000 # data segment -ff 00 00 00 # 0xff -+run: and r/m32 with EBX -+run: effective address is 0x00002000 (EAX) -+run: storing 0x0000000d +:(code) +void test_and_mem_at_r32_with_r32() { + Reg[EAX].i = 0x2000; + Reg[EBX].i = 0x0a0b0c0d; + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " 23 18 \n" // and *EAX with EBX + // ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) + "== 0x2000\n" // data segment + "ff 00 00 00\n" // 0x000000ff + ); + CHECK_TRACE_CONTENTS( + "run: and r/m32 with EBX\n" + "run: effective address is 0x00002000 (EAX)\n" + "run: storing 0x0000000d\n" + ); +} :(before "End Single-Byte Opcodes") case 0x23: { // and r/m32 with r32 @@ -141,36 +175,48 @@ case 0x23: { // and r/m32 with r32 //:: or -:(scenario or_r32_with_mem_at_r32) -% Reg[EAX].i = 0x2000; -% Reg[EBX].i = 0xa0b0c0d0; -== 0x1 # code segment -# op ModR/M SIB displacement immediate - 09 18 # or EBX with *EAX -# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) -== 0x2000 # data segment -0d 0c 0b 0a # 0x0a0b0c0d -+run: or EBX with r/m32 -+run: effective address is 0x00002000 (EAX) -+run: storing 0xaabbccdd +:(code) +void test_or_r32_with_mem_at_r32() { + Reg[EAX].i = 0x2000; + Reg[EBX].i = 0xa0b0c0d0; + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " 09 18 #\n" // EBX with *EAX + // ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) + "== 0x2000\n" // data segment + "0d 0c 0b 0a\n" // 0x0a0b0c0d + ); + CHECK_TRACE_CONTENTS( + "run: or EBX with r/m32\n" + "run: effective address is 0x00002000 (EAX)\n" + "run: storing 0xaabbccdd\n" + ); +} //: :(before "End Initialize Op Names") put_new(Name, "0b", "r32 = bitwise OR of r32 with rm32 (or)"); -:(scenario or_mem_at_r32_with_r32) -% Reg[EAX].i = 0x2000; -% Reg[EBX].i = 0xa0b0c0d0; -== 0x1 # code segment -# op ModR/M SIB displacement immediate - 0b 18 # or *EAX with EBX -# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) -== 0x2000 # data segment -0d 0c 0b 0a # 0x0a0b0c0d -+run: or r/m32 with EBX -+run: effective address is 0x00002000 (EAX) -+run: storing 0xaabbccdd +:(code) +void test_or_mem_at_r32_with_r32() { + Reg[EAX].i = 0x2000; + Reg[EBX].i = 0xa0b0c0d0; + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " 0b 18 \n" // or *EAX with EBX + // ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) + "== 0x2000\n" // data segment + "0d 0c 0b 0a\n" // 0x0a0b0c0d + ); + CHECK_TRACE_CONTENTS( + "run: or r/m32 with EBX\n" + "run: effective address is 0x00002000 (EAX)\n" + "run: storing 0xaabbccdd\n" + ); +} :(before "End Single-Byte Opcodes") case 0x0b: { // or r/m32 with r32 @@ -184,36 +230,47 @@ case 0x0b: { // or r/m32 with r32 //:: xor -:(scenario xor_r32_with_mem_at_r32) -% Reg[EAX].i = 0x2000; -% Reg[EBX].i = 0xa0b0c0d0; -== 0x1 # code segment -# op ModR/M SIB displacement immediate - 31 18 # xor EBX with *EAX -# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) -== 0x2000 # data segment -0d 0c bb aa # 0xaabb0c0d -+run: xor EBX with r/m32 -+run: effective address is 0x00002000 (EAX) -+run: storing 0x0a0bccdd +:(code) +void test_xor_r32_with_mem_at_r32() { + Reg[EAX].i = 0x2000; + Reg[EBX].i = 0xa0b0c0d0; + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " 31 18 \n" // xor EBX with *EAX + "== 0x2000\n" // data segment + "0d 0c bb aa\n" // 0xaabb0c0d + ); + CHECK_TRACE_CONTENTS( + "run: xor EBX with r/m32\n" + "run: effective address is 0x00002000 (EAX)\n" + "run: storing 0x0a0bccdd\n" + ); +} //: :(before "End Initialize Op Names") put_new(Name, "33", "r32 = bitwise XOR of r32 with rm32 (xor)"); -:(scenario xor_mem_at_r32_with_r32) -% Reg[EAX].i = 0x2000; -% Reg[EBX].i = 0xa0b0c0d0; -== 0x1 # code segment -# op ModR/M SIB displacement immediate - 33 18 # xor *EAX with EBX -# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) -== 0x2000 # data segment -0d 0c 0b 0a # 0x0a0b0c0d -+run: xor r/m32 with EBX -+run: effective address is 0x00002000 (EAX) -+run: storing 0xaabbccdd +:(code) +void test_xor_mem_at_r32_with_r32() { + Reg[EAX].i = 0x2000; + Reg[EBX].i = 0xa0b0c0d0; + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " 33 18 \n" // xor *EAX with EBX + // ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) + "== 0x2000\n" // data segment + "0d 0c 0b 0a\n" // 0x0a0b0c0d + ); + CHECK_TRACE_CONTENTS( + "run: xor r/m32 with EBX\n" + "run: effective address is 0x00002000 (EAX)\n" + "run: storing 0xaabbccdd\n" + ); +} :(before "End Single-Byte Opcodes") case 0x33: { // xor r/m32 with r32 @@ -227,77 +284,107 @@ case 0x33: { // xor r/m32 with r32 //:: not -:(scenario not_of_mem_at_r32) -% Reg[EBX].i = 0x2000; -== 0x1 # code segment -# op ModR/M SIB displacement immediate - f7 13 # not *EBX -# ModR/M in binary: 00 (indirect mode) 010 (subop not) 011 (dest EBX) -== 0x2000 # data segment -ff 00 0f 0f # 0x0f0f00ff -+run: operate on r/m32 -+run: effective address is 0x00002000 (EBX) -+run: subop: not -+run: storing 0xf0f0ff00 +:(code) +void test_not_of_mem_at_r32() { + Reg[EBX].i = 0x2000; + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " f7 13 \n" // not *EBX + // ModR/M in binary: 00 (indirect mode) 010 (subop not) 011 (dest EBX) + "== 0x2000\n" // data segment + "ff 00 0f 0f\n" // 0x0f0f00ff + ); + CHECK_TRACE_CONTENTS( + "run: operate on r/m32\n" + "run: effective address is 0x00002000 (EBX)\n" + "run: subop: not\n" + "run: storing 0xf0f0ff00\n" + ); +} //:: compare (cmp) -:(scenario compare_mem_at_r32_with_r32_greater) -% Reg[EAX].i = 0x2000; -% Reg[EBX].i = 0x0a0b0c07; -== 0x1 # code segment -# op ModR/M SIB displacement immediate - 39 18 # compare EBX with *EAX -# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) -== 0x2000 # data segment -0d 0c 0b 0a # 0x0a0b0c0d -+run: compare EBX with r/m32 -+run: effective address is 0x00002000 (EAX) -+run: SF=0; ZF=0; OF=0 - -:(scenario compare_mem_at_r32_with_r32_lesser) -% Reg[EAX].i = 0x2000; -% Reg[EBX].i = 0x0a0b0c0d; -== 0x1 # code segment -# op ModR/M SIB displacement immediate - 39 18 # compare EBX with *EAX -# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) -== 0x2000 # data segment -07 0c 0b 0a # 0x0a0b0c0d -+run: compare EBX with r/m32 -+run: effective address is 0x00002000 (EAX) -+run: SF=1; ZF=0; OF=0 - -:(scenario compare_mem_at_r32_with_r32_equal) -% Reg[EAX].i = 0x2000; -% Reg[EBX].i = 0x0a0b0c0d; -== 0x1 # code segment -# op ModR/M SIB displacement immediate - 39 18 # compare EBX with *EAX -# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) -== 0x2000 # data segment -0d 0c 0b 0a # 0x0a0b0c0d -+run: compare EBX with r/m32 -+run: effective address is 0x00002000 (EAX) -+run: SF=0; ZF=1; OF=0 +:(code) +void test_compare_mem_at_r32_with_r32_greater() { + Reg[EAX].i = 0x2000; + Reg[EBX].i = 0x0a0b0c07; + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " 39 18 \n" // compare EBX with *EAX + // ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) + "== 0x2000\n" // data segment + "0d 0c 0b 0a\n" // 0x0a0b0c0d + ); + CHECK_TRACE_CONTENTS( + "run: compare EBX with r/m32\n" + "run: effective address is 0x00002000 (EAX)\n" + "run: SF=0; ZF=0; OF=0\n" + ); +} + +:(code) +void test_compare_mem_at_r32_with_r32_lesser() { + Reg[EAX].i = 0x2000; + Reg[EBX].i = 0x0a0b0c0d; + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " 39 18 \n" // compare EBX with *EAX + // ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) + "== 0x2000\n" // data segment + "07 0c 0b 0a\n" // 0x0a0b0c0d + ); + CHECK_TRACE_CONTENTS( + "run: compare EBX with r/m32\n" + "run: effective address is 0x00002000 (EAX)\n" + "run: SF=1; ZF=0; OF=0\n" + ); +} + +:(code) +void test_compare_mem_at_r32_with_r32_equal() { + Reg[EAX].i = 0x2000; + Reg[EBX].i = 0x0a0b0c0d; + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " 39 18 \n" // compare EBX with *EAX + // ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) + "== 0x2000\n" // data segment + "0d 0c 0b 0a\n" // 0x0a0b0c0d + ); + CHECK_TRACE_CONTENTS( + "run: compare EBX with r/m32\n" + "run: effective address is 0x00002000 (EAX)\n" + "run: SF=0; ZF=1; OF=0\n" + ); +} //: :(before "End Initialize Op Names") put_new(Name, "3b", "compare: set SF if r32 < rm32 (cmp)"); -:(scenario compare_r32_with_mem_at_r32_greater) -% Reg[EAX].i = 0x2000; -% Reg[EBX].i = 0x0a0b0c0d; -== 0x1 # code segment -# op ModR/M SIB displacement immediate - 3b 18 # compare *EAX with EBX -# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) -== 0x2000 # data segment -07 0c 0b 0a # 0x0a0b0c0d -+run: compare r/m32 with EBX -+run: effective address is 0x00002000 (EAX) -+run: SF=0; ZF=0; OF=0 +:(code) +void test_compare_r32_with_mem_at_r32_greater() { + Reg[EAX].i = 0x2000; + Reg[EBX].i = 0x0a0b0c0d; + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " 3b 18 \n" // compare *EAX with EBX + // ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) + "== 0x2000\n" // data segment + "07 0c 0b 0a\n" // 0x0a0b0c0d + ); + CHECK_TRACE_CONTENTS( + "run: compare r/m32 with EBX\n" + "run: effective address is 0x00002000 (EAX)\n" + "run: SF=0; ZF=0; OF=0\n" + ); +} :(before "End Single-Byte Opcodes") case 0x3b: { // set SF if r32 < r/m32 @@ -315,61 +402,84 @@ case 0x3b: { // set SF if r32 < r/m32 break; } -:(scenario compare_r32_with_mem_at_r32_lesser) -% Reg[EAX].i = 0x2000; -% Reg[EBX].i = 0x0a0b0c07; -== 0x1 # code segment -# op ModR/M SIB displacement immediate - 3b 18 # compare *EAX with EBX -# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) -== 0x2000 # data segment -0d 0c 0b 0a # 0x0a0b0c0d -+run: compare r/m32 with EBX -+run: effective address is 0x00002000 (EAX) -+run: SF=1; ZF=0; OF=0 - -:(scenario compare_r32_with_mem_at_r32_equal) -% Reg[EAX].i = 0x2000; -% Reg[EBX].i = 0x0a0b0c0d; -== 0x1 # code segment -# op ModR/M SIB displacement immediate - 3b 18 # compare *EAX with EBX -# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) -== 0x2000 # data segment -0d 0c 0b 0a # 0x0a0b0c0d -+run: compare r/m32 with EBX -+run: effective address is 0x00002000 (EAX) -+run: SF=0; ZF=1; OF=0 +:(code) +void test_compare_r32_with_mem_at_r32_lesser() { + Reg[EAX].i = 0x2000; + Reg[EBX].i = 0x0a0b0c07; + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " 3b 18 \n" // compare *EAX with EBX + // ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) + "== 0x2000\n" // data segment + "0d 0c 0b 0a\n" // 0x0a0b0c0d + ); + CHECK_TRACE_CONTENTS( + "run: compare r/m32 with EBX\n" + "run: effective address is 0x00002000 (EAX)\n" + "run: SF=1; ZF=0; OF=0\n" + ); +} + +:(code) +void test_compare_r32_with_mem_at_r32_equal() { + Reg[EAX].i = 0x2000; + Reg[EBX].i = 0x0a0b0c0d; + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " 3b 18 \n" // compare *EAX with EBX + // ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) + "== 0x2000\n" // data segment + "0d 0c 0b 0a\n" // 0x0a0b0c0d + ); + CHECK_TRACE_CONTENTS( + "run: compare r/m32 with EBX\n" + "run: effective address is 0x00002000 (EAX)\n" + "run: SF=0; ZF=1; OF=0\n" + ); +} //:: copy (mov) -:(scenario copy_r32_to_mem_at_r32) -% Reg[EBX].i = 0xaf; -% Reg[EAX].i = 0x60; -== 0x1 -# op ModR/M SIB displacement immediate - 89 18 # copy EBX to *EAX -# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) -+run: copy EBX to r/m32 -+run: effective address is 0x00000060 (EAX) -+run: storing 0x000000af +:(code) +void test_copy_r32_to_mem_at_r32() { + Reg[EBX].i = 0xaf; + Reg[EAX].i = 0x60; + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " 89 18 \n" // copy EBX to *EAX + // ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) + ); + CHECK_TRACE_CONTENTS( + "run: copy EBX to r/m32\n" + "run: effective address is 0x00000060 (EAX)\n" + "run: storing 0x000000af\n" + ); +} //: :(before "End Initialize Op Names") put_new(Name, "8b", "copy rm32 to r32 (mov)"); -:(scenario copy_mem_at_r32_to_r32) -% Reg[EAX].i = 0x2000; -== 0x1 # code segment -# op ModR/M SIB displacement immediate - 8b 18 # copy *EAX to EBX -# ModR/M in binary: 00 (indirect mode) 011 (src EBX) 000 (dest EAX) -== 0x2000 # data segment -af 00 00 00 # 0xaf -+run: copy r/m32 to EBX -+run: effective address is 0x00002000 (EAX) -+run: storing 0x000000af +:(code) +void test_copy_mem_at_r32_to_r32() { + Reg[EAX].i = 0x2000; + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " 8b 18 \n" // copy *EAX to EBX + "== 0x2000\n" // data segment + "af 00 00 00\n" // 0x000000af + ); + CHECK_TRACE_CONTENTS( + "run: copy r/m32 to EBX\n" + "run: effective address is 0x00002000 (EAX)\n" + "run: storing 0x000000af\n" + ); +} :(before "End Single-Byte Opcodes") case 0x8b: { // copy r32 to r/m32 @@ -384,22 +494,28 @@ case 0x8b: { // copy r32 to r/m32 //:: jump -:(scenario jump_mem_at_r32) -% Reg[EAX].i = 0x2000; -== 0x1 # code segment -# op ModR/M SIB displacement immediate - ff 20 # jump to *EAX -# ModR/M in binary: 00 (indirect mode) 100 (jump to r/m32) 000 (src EAX) - 05 00 00 00 01 - 05 00 00 00 02 -== 0x2000 # data segment -08 00 00 00 # 8 -+run: 0x00000001 opcode: ff -+run: jump to r/m32 -+run: effective address is 0x00002000 (EAX) -+run: jumping to 0x00000008 -+run: 0x00000008 opcode: 05 --run: 0x00000003 opcode: 05 +:(code) +void test_jump_mem_at_r32() { + Reg[EAX].i = 0x2000; + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " ff 20 \n" // jump to *EAX + // ModR/M in binary: 00 (indirect mode) 100 (jump to r/m32) 000 (src EAX) + " 05 00 00 00 01\n" + " 05 00 00 00 02\n" + "== 0x2000\n" // data segment + "08 00 00 00\n" // 0x00000008 + ); + CHECK_TRACE_CONTENTS( + "run: 0x00000001 opcode: ff\n" + "run: jump to r/m32\n" + "run: effective address is 0x00002000 (EAX)\n" + "run: jumping to 0x00000008\n" + "run: 0x00000008 opcode: 05\n" + ); + CHECK_TRACE_DOESNT_CONTAIN("run: 0x00000003 opcode: 05"); +} :(before "End Op ff Subops") case 4: { // jump to r/m32 @@ -412,19 +528,24 @@ case 4: { // jump to r/m32 //:: push -:(scenario push_mem_at_r32) -% Reg[EAX].i = 0x2000; -% Reg[ESP].u = 0x14; -== 0x1 # code segment -# op ModR/M SIB displacement immediate - ff 30 # push *EAX to stack -# ModR/M in binary: 00 (indirect mode) 110 (push r/m32) 000 (src EAX) -== 0x2000 # data segment -af 00 00 00 # 0xaf -+run: push r/m32 -+run: effective address is 0x00002000 (EAX) -+run: decrementing ESP to 0x00000010 -+run: pushing value 0x000000af +:(code) +void test_push_mem_at_r32() { + Reg[EAX].i = 0x2000; + Reg[ESP].u = 0x14; + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " ff 30 \n" // push *EAX to stack + "== 0x2000\n" // data segment + "af 00 00 00\n" // 0x000000af + ); + CHECK_TRACE_CONTENTS( + "run: push r/m32\n" + "run: effective address is 0x00002000 (EAX)\n" + "run: decrementing ESP to 0x00000010\n" + "run: pushing value 0x000000af\n" + ); +} :(before "End Op ff Subops") case 6: { // push r/m32 to stack @@ -439,19 +560,25 @@ case 6: { // push r/m32 to stack :(before "End Initialize Op Names") put_new(Name, "8f", "pop top of stack to rm32 (pop)"); -:(scenario pop_mem_at_r32) -% Reg[EAX].i = 0x60; -% Reg[ESP].u = 0x2000; -== 0x1 # code segment -# op ModR/M SIB displacement immediate - 8f 00 # pop stack into *EAX -# ModR/M in binary: 00 (indirect mode) 000 (pop r/m32) 000 (dest EAX) -== 0x2000 # data segment -30 00 00 00 # 0x30 -+run: pop into r/m32 -+run: effective address is 0x00000060 (EAX) -+run: popping value 0x00000030 -+run: incrementing ESP to 0x00002004 +:(code) +void test_pop_mem_at_r32() { + Reg[EAX].i = 0x60; + Reg[ESP].u = 0x2000; + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " 8f 00 \n" // pop stack into *EAX + // ModR/M in binary: 00 (indirect mode) 000 (pop r/m32) 000 (dest EAX) + "== 0x2000\n" // data segment + "30 00 00 00\n" // 0x00000030 + ); + CHECK_TRACE_CONTENTS( + "run: pop into r/m32\n" + "run: effective address is 0x00000060 (EAX)\n" + "run: popping value 0x00000030\n" + "run: incrementing ESP to 0x00002004\n" + ); +} :(before "End Single-Byte Opcodes") case 0x8f: { // pop stack into r/m32 @@ -470,17 +597,23 @@ case 0x8f: { // pop stack into r/m32 //:: special-case for loading address from disp32 rather than register -:(scenario add_r32_to_mem_at_displacement) -% Reg[EBX].i = 0x10; // source -== 0x1 # code segment -# op ModR/M SIB displacement immediate - 01 1d 00 20 00 00 # add EBX to *0x2000 -# ModR/M in binary: 00 (indirect mode) 011 (src EBX) 101 (dest in disp32) -== 0x2000 # data segment -01 00 00 00 # 1 -+run: add EBX to r/m32 -+run: effective address is 0x00002000 (disp32) -+run: storing 0x00000011 +:(code) +void test_add_r32_to_mem_at_displacement() { + Reg[EBX].i = 0x10; // source + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " 01 1d 00 20 00 00 \n" // add EBX to *0x2000 + // ModR/M in binary: 00 (indirect mode) 011 (src EBX) 101 (dest in disp32) + "== 0x2000\n" // data segment + "01 00 00 00\n" // 0x00000001 + ); + CHECK_TRACE_CONTENTS( + "run: add EBX to r/m32\n" + "run: effective address is 0x00002000 (disp32)\n" + "run: storing 0x00000011\n" + ); +} :(before "End Mod 0 Special-cases(addr)") case 5: // exception: mod 0b00 rm 0b101 => incoming disp32 @@ -490,19 +623,25 @@ case 5: // exception: mod 0b00 rm 0b101 => incoming disp32 //: -:(scenario add_r32_to_mem_at_r32_plus_disp8) -% Reg[EBX].i = 0x10; // source -% Reg[EAX].i = 0x1ffe; // dest -== 0x1 # code segment -# op ModR/M SIB displacement immediate - 01 58 02 # add EBX to *(EAX+2) -# ModR/M in binary: 01 (indirect+disp8 mode) 011 (src EBX) 000 (dest EAX) -== 0x2000 # data segment -01 00 00 00 # 1 -+run: add EBX to r/m32 -+run: effective address is initially 0x00001ffe (EAX) -+run: effective address is 0x00002000 (after adding disp8) -+run: storing 0x00000011 +:(code) +void test_add_r32_to_mem_at_r32_plus_disp8() { + Reg[EBX].i = 0x10; // source + Reg[EAX].i = 0x1ffe; // dest + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " 01 58 02 \n" // add EBX to *(EAX+2) + // ModR/M in binary: 01 (indirect+disp8 mode) 011 (src EBX) 000 (dest EAX) + "== 0x2000\n" // data segment + "01 00 00 00\n" // 0x00000001 + ); + CHECK_TRACE_CONTENTS( + "run: add EBX to r/m32\n" + "run: effective address is initially 0x00001ffe (EAX)\n" + "run: effective address is 0x00002000 (after adding disp8)\n" + "run: storing 0x00000011\n" + ); +} :(before "End Mod Special-cases(addr)") case 1: // indirect + disp8 addressing @@ -519,35 +658,47 @@ case 1: // indirect + disp8 addressing } break; -:(scenario add_r32_to_mem_at_r32_plus_negative_disp8) -% Reg[EBX].i = 0x10; // source -% Reg[EAX].i = 0x2001; // dest -== 0x1 # code segment -# op ModR/M SIB displacement immediate - 01 58 ff # add EBX to *(EAX-1) -# ModR/M in binary: 01 (indirect+disp8 mode) 011 (src EBX) 000 (dest EAX) -== 0x2000 # data segment -01 00 00 00 # 1 -+run: add EBX to r/m32 -+run: effective address is initially 0x00002001 (EAX) -+run: effective address is 0x00002000 (after adding disp8) -+run: storing 0x00000011 +:(code) +void test_add_r32_to_mem_at_r32_plus_negative_disp8() { + Reg[EBX].i = 0x10; // source + Reg[EAX].i = 0x2001; // dest + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " 01 58 ff \n" // add EBX to *(EAX-1) + // ModR/M in binary: 01 (indirect+disp8 mode) 011 (src EBX) 000 (dest EAX) + "== 0x2000\n" // data segment + "01 00 00 00\n" // 0x00000001 + ); + CHECK_TRACE_CONTENTS( + "run: add EBX to r/m32\n" + "run: effective address is initially 0x00002001 (EAX)\n" + "run: effective address is 0x00002000 (after adding disp8)\n" + "run: storing 0x00000011\n" + ); +} //: -:(scenario add_r32_to_mem_at_r32_plus_disp32) -% Reg[EBX].i = 0x10; // source -% Reg[EAX].i = 0x1ffe; // dest -== 0x1 # code segment -# op ModR/M SIB displacement immediate - 01 98 02 00 00 00 # add EBX to *(EAX+2) -# ModR/M in binary: 10 (indirect+disp32 mode) 011 (src EBX) 000 (dest EAX) -== 0x2000 # data segment -01 00 00 00 # 1 -+run: add EBX to r/m32 -+run: effective address is initially 0x00001ffe (EAX) -+run: effective address is 0x00002000 (after adding disp32) -+run: storing 0x00000011 +:(code) +void test_add_r32_to_mem_at_r32_plus_disp32() { + Reg[EBX].i = 0x10; // source + Reg[EAX].i = 0x1ffe; // dest + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " 01 98 02 00 00 00 \n" // add EBX to *(EAX+2) + // ModR/M in binary: 10 (indirect+disp32 mode) 011 (src EBX) 000 (dest EAX) + "== 0x2000\n" // data segment + "01 00 00 00\n" // 0x00000001 + ); + CHECK_TRACE_CONTENTS( + "run: add EBX to r/m32\n" + "run: effective address is initially 0x00001ffe (EAX)\n" + "run: effective address is 0x00002000 (after adding disp32)\n" + "run: storing 0x00000011\n" + ); +} :(before "End Mod Special-cases(addr)") case 2: // indirect + disp32 addressing @@ -564,33 +715,45 @@ case 2: // indirect + disp32 addressing } break; -:(scenario add_r32_to_mem_at_r32_plus_negative_disp32) -% Reg[EBX].i = 0x10; // source -% Reg[EAX].i = 0x2001; // dest -== 0x1 # code segment -# op ModR/M SIB displacement immediate - 01 98 ff ff ff ff # add EBX to *(EAX-1) -# ModR/M in binary: 10 (indirect+disp32 mode) 011 (src EBX) 000 (dest EAX) -== 0x2000 # data segment -01 00 00 00 # 1 -+run: add EBX to r/m32 -+run: effective address is initially 0x00002001 (EAX) -+run: effective address is 0x00002000 (after adding disp32) -+run: storing 0x00000011 +:(code) +void test_add_r32_to_mem_at_r32_plus_negative_disp32() { + Reg[EBX].i = 0x10; // source + Reg[EAX].i = 0x2001; // dest + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " 01 98 ff ff ff ff \n" // add EBX to *(EAX-1) + // ModR/M in binary: 10 (indirect+disp32 mode) 011 (src EBX) 000 (dest EAX) + "== 0x2000\n" // data segment + "01 00 00 00\n" // 0x00000001 + ); + CHECK_TRACE_CONTENTS( + "run: add EBX to r/m32\n" + "run: effective address is initially 0x00002001 (EAX)\n" + "run: effective address is 0x00002000 (after adding disp32)\n" + "run: storing 0x00000011\n" + ); +} //:: copy address (lea) :(before "End Initialize Op Names") put_new(Name, "8d", "copy address in rm32 into r32 (lea)"); -:(scenario copy_address) -% Reg[EAX].u = 0x2000; -== 0x1 -# op ModR/M SIB displacement immediate - 8d 18 -# ModR/M in binary: 00 (indirect mode) 011 (dest EBX) 000 (src EAX) -+run: copy address into EBX -+run: effective address is 0x00002000 (EAX) +:(code) +void test_copy_address() { + Reg[EAX].u = 0x2000; + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " 8d 18 \n" // copy address in EAX into EBX + // ModR/M in binary: 00 (indirect mode) 011 (dest EBX) 000 (src EAX) + ); + CHECK_TRACE_CONTENTS( + "run: copy address into EBX\n" + "run: effective address is 0x00002000 (EAX)\n" + ); +} :(before "End Single-Byte Opcodes") case 0x8d: { // copy address of m32 to r32 |