From 36c745f8e0cb24b781a5cb6bb7e829937dabec46 Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Sat, 11 May 2019 00:30:31 -0700 Subject: 5152 - check for stack underflow/overflow in VM --- subx/015immediate_addressing.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'subx/015immediate_addressing.cc') diff --git a/subx/015immediate_addressing.cc b/subx/015immediate_addressing.cc index 18cd5334..16d886e8 100644 --- a/subx/015immediate_addressing.cc +++ b/subx/015immediate_addressing.cc @@ -824,7 +824,8 @@ put_new(Name, "68", "push imm32 to stack (push)"); :(code) void test_push_imm32() { - Reg[ESP].u = 0x14; + Mem.push_back(vma(0x7d000000)); // manually allocate memory + Reg[ESP].u = 0x7d000014; run( "== 0x1\n" // code segment // op ModR/M SIB displacement immediate @@ -832,7 +833,7 @@ void test_push_imm32() { ); CHECK_TRACE_CONTENTS( "run: push imm32 0x000000af\n" - "run: ESP is now 0x00000010\n" + "run: ESP is now 0x7d000010\n" "run: contents at ESP: 0x000000af\n" ); } -- cgit 1.4.1-2-gfad0 From 8c1a69089bcb0be8ee869a3f83c3151a7083e27c Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Sun, 12 May 2019 07:36:18 -0700 Subject: snapshot of carry flag implementation Tests failing. This approach seems wrong. I'm not sure even the tests are correct. Also, some open questions: 1. Should setting the overflow flag always set the carry flag? 2. Should the carry flag only be set on add/subtract/compare, or by all arithmetic ops? 3. Had to turn off the -ftrapv flag in `build`. Is there a way to detect overflow without actually causing overflow? Once we start setting CF correctly we have to implement jump above/below instructions (8- and 32-bit displacement variants). https://github.com/akkartik/mu/issues/30 --- subx/010---vm.cc | 48 +++++++++++++++--------- subx/013direct_addressing.cc | 83 +++++++++++++++++++++++++++++++++++------ subx/014indirect_addressing.cc | 33 +++++++++------- subx/015immediate_addressing.cc | 43 +++++++++++---------- subx/build | 2 +- 5 files changed, 147 insertions(+), 62 deletions(-) (limited to 'subx/015immediate_addressing.cc') diff --git a/subx/010---vm.cc b/subx/010---vm.cc index 31e5608f..00a2dee4 100644 --- a/subx/010---vm.cc +++ b/subx/010---vm.cc @@ -62,7 +62,10 @@ put_new(Help, "registers", "- the sign flag (SF): usually set if an arithmetic result is negative, or\n" " reset if not.\n" "- the zero flag (ZF): usually set if a result is zero, or reset if not.\n" - "- the overflow flag (OF): usually set if an arithmetic result overflows.\n" + "- the carry flag (CF): usually set if an arithmetic result overflows by just one bit.\n" + " Useful for operating on unsigned numbers.\n" + "- the overflow flag (OF): usually set if an arithmetic result overflows by more than one bit.\n" + " Useful for operating on signed numbers.\n" "The flag bits are read by conditional jumps.\n" "\n" "For complete details on how different instructions update the flags, consult the IA-32\n" @@ -78,9 +81,10 @@ put_new(Help, "registers", // the subset of x86 flag registers we care about bool SF = false; // sign flag bool ZF = false; // zero flag +bool CF = false; // carry flag bool OF = false; // overflow flag :(before "End Reset") -SF = ZF = OF = false; +SF = ZF = CF = OF = false; //: how the flag registers are updated after each instruction @@ -88,25 +92,35 @@ SF = ZF = OF = false; // Combine 'arg1' and 'arg2' with arithmetic operation 'op' and store the // result in 'arg1', then update flags. // beware: no side-effects in args -#define BINARY_ARITHMETIC_OP(op, arg1, arg2) { \ - /* arg1 and arg2 must be signed */ \ - int64_t tmp = arg1 op arg2; \ - arg1 = arg1 op arg2; \ - trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << arg1 << end(); \ - SF = (arg1 < 0); \ - ZF = (arg1 == 0); \ - OF = (arg1 != tmp); \ +#define BINARY_ARITHMETIC_OP(op, signed_arg1, signed_arg2) { \ + cerr << signed_arg1 << " vs " << signed_arg2 << '\n'; \ + int64_t signed_full_result = signed_arg1 op signed_arg2; \ + signed_arg1 = signed_arg1 op signed_arg2; \ + trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << signed_arg1 << end(); \ + SF = (signed_arg1 < 0); \ + ZF = (signed_arg1 == 0); \ + OF = (signed_arg1 != signed_full_result); \ + /* CF is more complex */ \ + uint32_t unsigned_arg1 = static_cast(signed_arg1); \ + uint32_t unsigned_arg2 = static_cast(signed_arg2); \ + cerr << unsigned_arg1 << " vs " << unsigned_arg2 << '\n'; \ + uint32_t unsigned_result = unsigned_arg1 op unsigned_arg2; \ + cerr << "result: " << unsigned_result << '\n'; \ + uint64_t unsigned_full_result = unsigned_arg1 op unsigned_arg2; \ + CF = (unsigned_result != unsigned_full_result); \ + trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); \ } // Combine 'arg1' and 'arg2' with bitwise operation 'op' and store the result // in 'arg1', then update flags. -#define BINARY_BITWISE_OP(op, arg1, arg2) { \ - /* arg1 and arg2 must be unsigned */ \ - arg1 = arg1 op arg2; \ - trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << arg1 << end(); \ - SF = (arg1 >> 31); \ - ZF = (arg1 == 0); \ +#define BINARY_BITWISE_OP(op, unsigned_arg1, unsigned_arg2) { \ + unsigned_arg1 = unsigned_arg1 op unsigned_arg2; \ + trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << unsigned_arg1 << end(); \ + SF = (unsigned_arg1 >> 31); \ + ZF = (unsigned_arg1 == 0); \ + CF = false; \ OF = false; \ + trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); \ } //:: simulated RAM @@ -374,7 +388,7 @@ void dump_registers() { if (i > 0) out << "; "; out << " " << i << ": " << std::hex << std::setw(8) << std::setfill('_') << Reg[i].u; } - out << " -- SF: " << SF << "; ZF: " << ZF << "; OF: " << OF; + out << " -- SF: " << SF << "; ZF: " << ZF << "; CF: " << CF << "; OF: " << OF; trace(Callstack_depth+1, "run") << out.str() << end(); } diff --git a/subx/013direct_addressing.cc b/subx/013direct_addressing.cc index 160ce6d6..ef5ac752 100644 --- a/subx/013direct_addressing.cc +++ b/subx/013direct_addressing.cc @@ -30,6 +30,24 @@ case 0x01: { // add r32 to r/m32 break; } +:(code) +void test_add_r32_to_r32_unsigned() { + Reg[EAX].i = 0x7fffffff; // largest positive signed number + Reg[EBX].i = 1; + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " 01 d8 \n" // add EBX to EAX + // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) + ); + CHECK_TRACE_CONTENTS( + "run: add EBX to r/m32\n" + "run: r/m32 is EAX\n" + "run: storing 0x80000000\n" + "run: SF=1; ZF=0; CF=1; OF=0\n" // carry flag set + ); +} + :(code) // Implement tables 2-2 and 2-3 in the Intel manual, Volume 2. // We return a pointer so that instructions can write to multiple bytes in @@ -116,6 +134,24 @@ case 0x29: { // subtract r32 from r/m32 break; } +:(code) +void test_subtract_r32_from_r32_unsigned() { + Reg[EAX].i = 0x7ffffffd; + Reg[EBX].i = 0x7fffffff; + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " 29 d8 \n" // subtract EBX from EAX + // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) + ); + CHECK_TRACE_CONTENTS( + "run: subtract EBX from r/m32\n" + "run: r/m32 is EAX\n" + "run: storing 0xfffffffe\n" + "run: SF=1; ZF=0; CF=1; OF=0\n" + ); +} + //:: multiply :(before "End Initialize Op Names") @@ -686,7 +722,7 @@ void test_compare_r32_with_r32_greater() { CHECK_TRACE_CONTENTS( "run: compare EBX with r/m32\n" "run: r/m32 is EAX\n" - "run: SF=0; ZF=0; OF=0\n" + "run: SF=0; ZF=0; CF=0; OF=0\n" ); } @@ -695,14 +731,23 @@ case 0x39: { // set SF if r/m32 < r32 const uint8_t modrm = next(); const uint8_t reg2 = (modrm>>3)&0x7; trace(Callstack_depth+1, "run") << "compare " << rname(reg2) << " with r/m32" << end(); - const int32_t* arg1 = effective_address(modrm); - const int32_t arg2 = Reg[reg2].i; - const int32_t tmp1 = *arg1 - arg2; - SF = (tmp1 < 0); - ZF = (tmp1 == 0); - const int64_t tmp2 = *arg1 - arg2; - OF = (tmp1 != tmp2); - trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; OF=" << OF << end(); + const int32_t* signed_arg1 = effective_address(modrm); + const int32_t signed_arg2 = Reg[reg2].i; + cerr << *signed_arg1 << " vs " << signed_arg2 << '\n'; + const int32_t signed_difference = *signed_arg1 - signed_arg2; + SF = (signed_difference < 0); + ZF = (signed_difference == 0); + const int64_t signed_full_difference = *signed_arg1 - signed_arg2; + OF = (signed_difference != signed_full_difference); + const uint32_t unsigned_arg1 = static_cast(*signed_arg1); + const uint32_t unsigned_arg2 = static_cast(signed_arg2); + cerr << unsigned_arg1 << " vs " << unsigned_arg2 << '\n'; + const uint32_t unsigned_difference = unsigned_arg1 - unsigned_arg2; + cerr << "result: " << unsigned_difference << '\n'; + const uint64_t unsigned_full_difference = unsigned_arg1 - unsigned_arg2; + cerr << "full result: " << unsigned_full_difference << '\n'; + CF = (unsigned_difference != unsigned_full_difference); + trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); break; } @@ -719,7 +764,23 @@ void test_compare_r32_with_r32_lesser() { CHECK_TRACE_CONTENTS( "run: compare EBX with r/m32\n" "run: r/m32 is EAX\n" - "run: SF=1; ZF=0; OF=0\n" + "run: SF=1; ZF=0; CF=0; OF=0\n" + ); +} + +void test_compare_r32_with_r32_lesser_unsigned() { + Reg[EAX].i = 0x7ffffffd; + Reg[EBX].i = 0x7fffffff; + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " 39 d8 \n" // compare EBX with EAX + // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) + ); + CHECK_TRACE_CONTENTS( + "run: compare EBX with r/m32\n" + "run: r/m32 is EAX\n" + "run: SF=1; ZF=0; CF=1; OF=0\n" ); } @@ -735,7 +796,7 @@ void test_compare_r32_with_r32_equal() { CHECK_TRACE_CONTENTS( "run: compare EBX with r/m32\n" "run: r/m32 is EAX\n" - "run: SF=0; ZF=1; OF=0\n" + "run: SF=0; ZF=1; CF=0; OF=0\n" ); } diff --git a/subx/014indirect_addressing.cc b/subx/014indirect_addressing.cc index 8f0d3325..b8b3d6ce 100644 --- a/subx/014indirect_addressing.cc +++ b/subx/014indirect_addressing.cc @@ -320,7 +320,7 @@ void test_compare_mem_at_r32_with_r32_greater() { 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" + "run: SF=0; ZF=0; CF=0; OF=0\n" ); } @@ -339,7 +339,7 @@ void test_compare_mem_at_r32_with_r32_lesser() { 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" + "run: SF=1; ZF=0; CF=0; OF=0\n" ); } @@ -358,7 +358,7 @@ void test_compare_mem_at_r32_with_r32_equal() { 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" + "run: SF=0; ZF=1; CF=0; OF=0\n" ); } @@ -382,7 +382,7 @@ void test_compare_r32_with_mem_at_r32_greater() { 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" + "run: SF=0; ZF=0; CF=0; OF=0\n" ); } @@ -391,14 +391,19 @@ case 0x3b: { // set SF if r32 < r/m32 const uint8_t modrm = next(); const uint8_t reg1 = (modrm>>3)&0x7; trace(Callstack_depth+1, "run") << "compare r/m32 with " << rname(reg1) << end(); - const int32_t arg1 = Reg[reg1].i; - const int32_t* arg2 = effective_address(modrm); - const int32_t tmp1 = arg1 - *arg2; - SF = (tmp1 < 0); - ZF = (tmp1 == 0); - int64_t tmp2 = arg1 - *arg2; - OF = (tmp1 != tmp2); - trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; OF=" << OF << end(); + const int32_t signed_arg1 = Reg[reg1].i; + const int32_t* signed_arg2 = effective_address(modrm); + const int32_t signed_difference = signed_arg1 - *signed_arg2; + SF = (signed_difference < 0); + ZF = (signed_difference == 0); + int64_t full_signed_difference = signed_arg1 - *signed_arg2; + OF = (signed_difference != full_signed_difference); + const uint32_t unsigned_arg1 = static_cast(signed_arg1); + const uint32_t unsigned_arg2 = static_cast(*signed_arg2); + const uint32_t unsigned_difference = unsigned_arg1 - unsigned_arg2; + const uint64_t full_unsigned_difference = unsigned_arg1 - unsigned_arg2; + CF = (unsigned_difference != full_unsigned_difference); + trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); break; } @@ -417,7 +422,7 @@ void test_compare_r32_with_mem_at_r32_lesser() { 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" + "run: SF=1; ZF=0; CF=0; OF=0\n" ); } @@ -436,7 +441,7 @@ void test_compare_r32_with_mem_at_r32_equal() { 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" + "run: SF=0; ZF=1; CF=0; OF=0\n" ); } diff --git a/subx/015immediate_addressing.cc b/subx/015immediate_addressing.cc index 16d886e8..97c868bd 100644 --- a/subx/015immediate_addressing.cc +++ b/subx/015immediate_addressing.cc @@ -571,21 +571,26 @@ void test_compare_imm32_with_eax_greater() { ); CHECK_TRACE_CONTENTS( "run: compare EAX and imm32 0x0d0c0b07\n" - "run: SF=0; ZF=0; OF=0\n" + "run: SF=0; ZF=0; CF=0; OF=0\n" ); } :(before "End Single-Byte Opcodes") case 0x3d: { // compare EAX with imm32 - const int32_t arg1 = Reg[EAX].i; - const int32_t arg2 = next32(); - trace(Callstack_depth+1, "run") << "compare EAX and imm32 0x" << HEXWORD << arg2 << end(); - const int32_t tmp1 = arg1 - arg2; - SF = (tmp1 < 0); - ZF = (tmp1 == 0); - const int64_t tmp2 = arg1 - arg2; - OF = (tmp1 != tmp2); - trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; OF=" << OF << end(); + const int32_t signed_arg1 = Reg[EAX].i; + const int32_t signed_arg2 = next32(); + trace(Callstack_depth+1, "run") << "compare EAX and imm32 0x" << HEXWORD << signed_arg2 << end(); + const int32_t signed_difference = signed_arg1 - signed_arg2; + SF = (signed_difference < 0); + ZF = (signed_difference == 0); + const int64_t full_signed_difference = signed_arg1 - signed_arg2; + OF = (signed_difference != full_signed_difference); + const uint32_t unsigned_arg1 = static_cast(signed_arg1); + const uint32_t unsigned_arg2 = static_cast(signed_arg2); + const uint32_t unsigned_difference = unsigned_arg1 - unsigned_arg2; + const uint64_t full_unsigned_difference = unsigned_arg1 - unsigned_arg2; + CF = (unsigned_difference != full_unsigned_difference); + trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); break; } @@ -599,7 +604,7 @@ void test_compare_imm32_with_eax_lesser() { ); CHECK_TRACE_CONTENTS( "run: compare EAX and imm32 0x0d0c0b0a\n" - "run: SF=1; ZF=0; OF=0\n" + "run: SF=1; ZF=0; CF=0; OF=0\n" ); } @@ -613,7 +618,7 @@ void test_compare_imm32_with_eax_equal() { ); CHECK_TRACE_CONTENTS( "run: compare EAX and imm32 0x0d0c0b0a\n" - "run: SF=0; ZF=1; OF=0\n" + "run: SF=0; ZF=1; CF=0; OF=0\n" ); } @@ -632,7 +637,7 @@ void test_compare_imm32_with_r32_greater() { "run: combine imm32 with r/m32\n" "run: r/m32 is EBX\n" "run: imm32 is 0x0d0c0b07\n" - "run: SF=0; ZF=0; OF=0\n" + "run: SF=0; ZF=0; CF=0; OF=0\n" ); } @@ -644,7 +649,7 @@ case 7: { ZF = (tmp1 == 0); const int64_t tmp2 = *arg1 - arg2; OF = (tmp1 != tmp2); - trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; OF=" << OF << end(); + trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); break; } @@ -661,7 +666,7 @@ void test_compare_imm32_with_r32_lesser() { "run: combine imm32 with r/m32\n" "run: r/m32 is EBX\n" "run: imm32 is 0x0d0c0b0a\n" - "run: SF=1; ZF=0; OF=0\n" + "run: SF=1; ZF=0; CF=0; OF=0\n" ); } @@ -678,7 +683,7 @@ void test_compare_imm32_with_r32_equal() { "run: combine imm32 with r/m32\n" "run: r/m32 is EBX\n" "run: imm32 is 0x0d0c0b0a\n" - "run: SF=0; ZF=1; OF=0\n" + "run: SF=0; ZF=1; CF=0; OF=0\n" ); } @@ -697,7 +702,7 @@ void test_compare_imm32_with_mem_at_r32_greater() { "run: combine imm32 with r/m32\n" "run: effective address is 0x00002000 (EBX)\n" "run: imm32 is 0x0d0c0b07\n" - "run: SF=0; ZF=0; OF=0\n" + "run: SF=0; ZF=0; CF=0; OF=0\n" ); } @@ -716,7 +721,7 @@ void test_compare_imm32_with_mem_at_r32_lesser() { "run: combine imm32 with r/m32\n" "run: effective address is 0x00002000 (EBX)\n" "run: imm32 is 0x0d0c0b0a\n" - "run: SF=1; ZF=0; OF=0\n" + "run: SF=1; ZF=0; CF=0; OF=0\n" ); } @@ -736,7 +741,7 @@ void test_compare_imm32_with_mem_at_r32_equal() { "run: combine imm32 with r/m32\n" "run: effective address is 0x00002000 (EBX)\n" "run: imm32 is 0x0d0c0b0a\n" - "run: SF=0; ZF=1; OF=0\n" + "run: SF=0; ZF=1; CF=0; OF=0\n" ); } diff --git a/subx/build b/subx/build index 614b07d8..f29518ac 100755 --- a/subx/build +++ b/subx/build @@ -22,7 +22,7 @@ UNTIL_LAYER=${2:-zzz} test "$CXX" || export CXX=c++ test "$CC" || export CC=cc test "$CFLAGS" || export CFLAGS="-g -O3" -export CFLAGS="$CFLAGS -Wall -Wextra -ftrapv -fno-strict-aliasing" +export CFLAGS="$CFLAGS -Wall -Wextra -fno-strict-aliasing" # return 1 if $1 is older than _any_ of the remaining args older_than() { -- cgit 1.4.1-2-gfad0 From 82fb58e6068f3718fe7cedd1cde1b405308bbbab Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Sun, 12 May 2019 22:41:19 -0700 Subject: CF needs special handling for some arithmetic ops Inline some macro definitions. --- subx/010---vm.cc | 34 ----------- subx/011run.cc | 18 +++++- subx/013direct_addressing.cc | 86 +++++++++++++++++++++----- subx/014indirect_addressing.cc | 66 ++++++++++++++++---- subx/015immediate_addressing.cc | 130 +++++++++++++++++++++++++++++++++------- 5 files changed, 248 insertions(+), 86 deletions(-) (limited to 'subx/015immediate_addressing.cc') diff --git a/subx/010---vm.cc b/subx/010---vm.cc index 379c441d..18f69035 100644 --- a/subx/010---vm.cc +++ b/subx/010---vm.cc @@ -86,40 +86,6 @@ bool OF = false; // overflow flag :(before "End Reset") SF = ZF = CF = OF = false; -//: how the flag registers are updated after each instruction - -:(before "End Includes") -// Combine 'arg1' and 'arg2' with arithmetic operation 'op' and store the -// result in 'arg1', then update flags. -// beware: no side-effects in args -#define BINARY_ARITHMETIC_OP(op, signed_arg1, signed_arg2) { \ - int64_t signed_full_result = signed_arg1 op signed_arg2; \ - signed_arg1 = signed_arg1 op signed_arg2; \ - trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << signed_arg1 << end(); \ - SF = (signed_arg1 < 0); \ - ZF = (signed_arg1 == 0); \ - OF = (signed_arg1 != signed_full_result); \ - /* CF is more complex */ \ - uint32_t unsigned_arg1 = static_cast(signed_arg1); \ - uint32_t unsigned_arg2 = static_cast(signed_arg2); \ - uint32_t unsigned_result = unsigned_arg1 op unsigned_arg2; \ - uint64_t unsigned_full_result = unsigned_arg1 op unsigned_arg2; \ - CF = (unsigned_result != unsigned_full_result); \ - trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); \ -} - -// Combine 'arg1' and 'arg2' with bitwise operation 'op' and store the result -// in 'arg1', then update flags. -#define BINARY_BITWISE_OP(op, unsigned_arg1, unsigned_arg2) { \ - unsigned_arg1 = unsigned_arg1 op unsigned_arg2; \ - trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << unsigned_arg1 << end(); \ - SF = (unsigned_arg1 >> 31); \ - ZF = (unsigned_arg1 == 0); \ - CF = false; \ - OF = false; \ - trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); \ -} - //:: simulated RAM :(before "End Types") diff --git a/subx/011run.cc b/subx/011run.cc index 6b18ca06..ccc891c3 100644 --- a/subx/011run.cc +++ b/subx/011run.cc @@ -355,9 +355,21 @@ put_new(Name, "05", "add imm32 to EAX (add)"); //: our first opcode :(before "End Single-Byte Opcodes") case 0x05: { // add imm32 to EAX - int32_t arg2 = next32(); - trace(Callstack_depth+1, "run") << "add imm32 0x" << HEXWORD << arg2 << " to reg EAX" << end(); - BINARY_ARITHMETIC_OP(+, Reg[EAX].i, arg2); + int32_t signed_arg2 = next32(); + trace(Callstack_depth+1, "run") << "add imm32 0x" << HEXWORD << signed_arg2 << " to reg EAX" << end(); + int64_t signed_full_result = Reg[EAX].i + signed_arg2; + Reg[EAX].i += signed_arg2; + trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[EAX].i << end(); + SF = (Reg[EAX].i < 0); + ZF = (Reg[EAX].i == 0); + OF = (Reg[EAX].i != signed_full_result); + // set CF + uint32_t unsigned_arg1 = static_cast(Reg[EAX].i); + uint32_t unsigned_arg2 = static_cast(signed_arg2); + uint32_t unsigned_result = unsigned_arg1 + unsigned_arg2; + uint64_t unsigned_full_result = unsigned_arg1 + unsigned_arg2; + CF = (unsigned_result != unsigned_full_result); + trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); break; } diff --git a/subx/013direct_addressing.cc b/subx/013direct_addressing.cc index c94a152d..87983e3d 100644 --- a/subx/013direct_addressing.cc +++ b/subx/013direct_addressing.cc @@ -25,8 +25,19 @@ case 0x01: { // add r32 to r/m32 uint8_t modrm = next(); uint8_t arg2 = (modrm>>3)&0x7; trace(Callstack_depth+1, "run") << "add " << rname(arg2) << " to r/m32" << end(); - int32_t* arg1 = effective_address(modrm); - BINARY_ARITHMETIC_OP(+, *arg1, Reg[arg2].i); + int32_t* signed_arg1 = effective_address(modrm); + int64_t signed_full_result = *signed_arg1 + Reg[arg2].i; + *signed_arg1 += Reg[arg2].i; + trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *signed_arg1 << end(); + SF = (*signed_arg1 < 0); + ZF = (*signed_arg1 == 0); + OF = (*signed_arg1 != signed_full_result); + // set CF + uint32_t unsigned_arg1 = static_cast(*signed_arg1); + uint32_t unsigned_result = unsigned_arg1 + Reg[arg2].u; + uint64_t unsigned_full_result = unsigned_arg1 + Reg[arg2].u; + CF = (unsigned_result != unsigned_full_result); + trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); break; } @@ -129,8 +140,19 @@ case 0x29: { // subtract r32 from r/m32 const uint8_t modrm = next(); const uint8_t arg2 = (modrm>>3)&0x7; trace(Callstack_depth+1, "run") << "subtract " << rname(arg2) << " from r/m32" << end(); - int32_t* arg1 = effective_address(modrm); - BINARY_ARITHMETIC_OP(-, *arg1, Reg[arg2].i); + int32_t* signed_arg1 = effective_address(modrm); + int64_t signed_full_result = *signed_arg1 - Reg[arg2].i; + *signed_arg1 -= Reg[arg2].i; + trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *signed_arg1 << end(); + SF = (*signed_arg1 < 0); + ZF = (*signed_arg1 == 0); + OF = (*signed_arg1 != signed_full_result); + // set CF + uint32_t unsigned_arg1 = static_cast(*signed_arg1); + uint32_t unsigned_result = unsigned_arg1 - Reg[arg2].u; + uint64_t unsigned_full_result = unsigned_arg1 - Reg[arg2].u; + CF = (unsigned_result != unsigned_full_result); + trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); break; } @@ -215,19 +237,26 @@ void test_multiply_r32_into_r32() { // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) ); CHECK_TRACE_CONTENTS( - "run: multiply r/m32 into EBX\n" + "run: multiply EBX by r/m32\n" "run: r/m32 is EAX\n" "run: storing 0x00000008\n" ); } :(before "End Two-Byte Opcodes Starting With 0f") -case 0xaf: { // multiply r32 into r/m32 +case 0xaf: { // multiply r32 by r/m32 const uint8_t modrm = next(); - const uint8_t arg2 = (modrm>>3)&0x7; - trace(Callstack_depth+1, "run") << "multiply r/m32 into " << rname(arg2) << end(); - const int32_t* arg1 = effective_address(modrm); - BINARY_ARITHMETIC_OP(*, Reg[arg2].i, *arg1); + const uint8_t arg1 = (modrm>>3)&0x7; + trace(Callstack_depth+1, "run") << "multiply " << rname(arg1) << " by r/m32" << end(); + const int32_t* arg2 = effective_address(modrm); + int64_t full_result = Reg[arg1].i * (*arg2); + Reg[arg1].i *= (*arg2); + trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[arg1].i << end(); + SF = (Reg[arg1].i < 0); + ZF = (Reg[arg1].i == 0); + OF = (Reg[arg1].i != full_result); + CF = OF; + trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); break; } @@ -316,6 +345,7 @@ case 7: { // divide EDX:EAX by r/m32, storing quotient in EAX and remainder in assert(divisor != 0); Reg[EAX].i = dividend/divisor; // quotient Reg[EDX].i = dividend%divisor; // remainder + // flag state undefined trace(Callstack_depth+1, "run") << "quotient: 0x" << HEXWORD << Reg[EAX].i << end(); trace(Callstack_depth+1, "run") << "remainder: 0x" << HEXWORD << Reg[EDX].i << end(); break; @@ -605,8 +635,16 @@ case 0x21: { // and r32 with r/m32 const uint8_t modrm = next(); const uint8_t arg2 = (modrm>>3)&0x7; trace(Callstack_depth+1, "run") << "and " << rname(arg2) << " with r/m32" << end(); - int32_t* arg1 = effective_address(modrm); - BINARY_BITWISE_OP(&, *arg1, Reg[arg2].u); + // bitwise ops technically operate on unsigned numbers, but it makes no + // difference + int32_t* signed_arg1 = effective_address(modrm); + *signed_arg1 &= Reg[arg2].i; + trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *signed_arg1 << end(); + SF = (*signed_arg1 >> 31); + ZF = (*signed_arg1 == 0); + CF = false; + OF = false; + trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); break; } @@ -637,8 +675,16 @@ case 0x09: { // or r32 with r/m32 const uint8_t modrm = next(); const uint8_t arg2 = (modrm>>3)&0x7; trace(Callstack_depth+1, "run") << "or " << rname(arg2) << " with r/m32" << end(); - int32_t* arg1 = effective_address(modrm); - BINARY_BITWISE_OP(|, *arg1, Reg[arg2].u); + // bitwise ops technically operate on unsigned numbers, but it makes no + // difference + int32_t* signed_arg1 = effective_address(modrm); + *signed_arg1 |= Reg[arg2].i; + trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *signed_arg1 << end(); + SF = (*signed_arg1 >> 31); + ZF = (*signed_arg1 == 0); + CF = false; + OF = false; + trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); break; } @@ -669,8 +715,16 @@ case 0x31: { // xor r32 with r/m32 const uint8_t modrm = next(); const uint8_t arg2 = (modrm>>3)&0x7; trace(Callstack_depth+1, "run") << "xor " << rname(arg2) << " with r/m32" << end(); - int32_t* arg1 = effective_address(modrm); - BINARY_BITWISE_OP(^, *arg1, Reg[arg2].u); + // bitwise ops technically operate on unsigned numbers, but it makes no + // difference + int32_t* signed_arg1 = effective_address(modrm); + *signed_arg1 ^= Reg[arg2].i; + trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *signed_arg1 << end(); + SF = (*signed_arg1 >> 31); + ZF = (*signed_arg1 == 0); + CF = false; + OF = false; + trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); break; } diff --git a/subx/014indirect_addressing.cc b/subx/014indirect_addressing.cc index b8b3d6ce..4b891f99 100644 --- a/subx/014indirect_addressing.cc +++ b/subx/014indirect_addressing.cc @@ -59,8 +59,19 @@ case 0x03: { // add r/m32 to r32 const uint8_t modrm = next(); const uint8_t arg1 = (modrm>>3)&0x7; trace(Callstack_depth+1, "run") << "add r/m32 to " << rname(arg1) << end(); - const int32_t* arg2 = effective_address(modrm); - BINARY_ARITHMETIC_OP(+, Reg[arg1].i, *arg2); + const int32_t* signed_arg2 = effective_address(modrm); + int64_t signed_full_result = Reg[arg1].i + *signed_arg2; + Reg[arg1].i += *signed_arg2; + trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[arg1].i << end(); + SF = (Reg[arg1].i < 0); + ZF = (Reg[arg1].i == 0); + OF = (Reg[arg1].i != signed_full_result); + // set CF + uint32_t unsigned_arg2 = static_cast(*signed_arg2); + uint32_t unsigned_result = Reg[arg1].u + unsigned_arg2; + uint64_t unsigned_full_result = Reg[arg1].u + unsigned_arg2; + CF = (unsigned_result != unsigned_full_result); + trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); break; } @@ -114,8 +125,19 @@ case 0x2b: { // subtract r/m32 from r32 const uint8_t modrm = next(); const uint8_t arg1 = (modrm>>3)&0x7; trace(Callstack_depth+1, "run") << "subtract r/m32 from " << rname(arg1) << end(); - const int32_t* arg2 = effective_address(modrm); - BINARY_ARITHMETIC_OP(-, Reg[arg1].i, *arg2); + const int32_t* signed_arg2 = effective_address(modrm); + int64_t signed_full_result = Reg[arg1].i - *signed_arg2; + Reg[arg1].i -= *signed_arg2; + trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[arg1].i << end(); + SF = (Reg[arg1].i < 0); + ZF = (Reg[arg1].i == 0); + OF = (Reg[arg1].i != signed_full_result); + // set CF + uint32_t unsigned_arg2 = static_cast(*signed_arg2); + uint32_t unsigned_result = Reg[arg1].u - unsigned_arg2; + uint64_t unsigned_full_result = Reg[arg1].u - unsigned_arg2; + CF = (unsigned_result != unsigned_full_result); + trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); break; } @@ -168,8 +190,16 @@ case 0x23: { // and r/m32 with r32 const uint8_t modrm = next(); const uint8_t arg1 = (modrm>>3)&0x7; trace(Callstack_depth+1, "run") << "and r/m32 with " << rname(arg1) << end(); - const int32_t* arg2 = effective_address(modrm); - BINARY_BITWISE_OP(&, Reg[arg1].u, *arg2); + // bitwise ops technically operate on unsigned numbers, but it makes no + // difference + const int32_t* signed_arg2 = effective_address(modrm); + Reg[arg1].i &= *signed_arg2; + trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[arg1].i << end(); + SF = (Reg[arg1].i >> 31); + ZF = (Reg[arg1].i == 0); + CF = false; + OF = false; + trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); break; } @@ -223,8 +253,16 @@ case 0x0b: { // or r/m32 with r32 const uint8_t modrm = next(); const uint8_t arg1 = (modrm>>3)&0x7; trace(Callstack_depth+1, "run") << "or r/m32 with " << rname(arg1) << end(); - const int32_t* arg2 = effective_address(modrm); - BINARY_BITWISE_OP(|, Reg[arg1].u, *arg2); + // bitwise ops technically operate on unsigned numbers, but it makes no + // difference + const int32_t* signed_arg2 = effective_address(modrm); + Reg[arg1].i |= *signed_arg2; + trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[arg1].i << end(); + SF = (Reg[arg1].i >> 31); + ZF = (Reg[arg1].i == 0); + CF = false; + OF = false; + trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); break; } @@ -277,8 +315,16 @@ case 0x33: { // xor r/m32 with r32 const uint8_t modrm = next(); const uint8_t arg1 = (modrm>>3)&0x7; trace(Callstack_depth+1, "run") << "xor r/m32 with " << rname(arg1) << end(); - const int32_t* arg2 = effective_address(modrm); - BINARY_BITWISE_OP(|, Reg[arg1].u, *arg2); + // bitwise ops technically operate on unsigned numbers, but it makes no + // difference + const int32_t* signed_arg2 = effective_address(modrm); + Reg[arg1].i |= *signed_arg2; + trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[arg1].i << end(); + SF = (Reg[arg1].i >> 31); + ZF = (Reg[arg1].i == 0); + CF = false; + OF = false; + trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); break; } diff --git a/subx/015immediate_addressing.cc b/subx/015immediate_addressing.cc index 97c868bd..8a0ba020 100644 --- a/subx/015immediate_addressing.cc +++ b/subx/015immediate_addressing.cc @@ -25,15 +25,28 @@ void test_add_imm32_to_r32() { case 0x81: { // combine imm32 with r/m32 trace(Callstack_depth+1, "run") << "combine imm32 with r/m32" << end(); const uint8_t modrm = next(); - int32_t* arg1 = effective_address(modrm); - const int32_t arg2 = next32(); - trace(Callstack_depth+1, "run") << "imm32 is 0x" << HEXWORD << arg2 << end(); + int32_t* signed_arg1 = effective_address(modrm); + const int32_t signed_arg2 = next32(); + trace(Callstack_depth+1, "run") << "imm32 is 0x" << HEXWORD << signed_arg2 << end(); const uint8_t subop = (modrm>>3)&0x7; // middle 3 'reg opcode' bits switch (subop) { - case 0: + case 0: { trace(Callstack_depth+1, "run") << "subop add" << end(); - BINARY_ARITHMETIC_OP(+, *arg1, arg2); + int64_t signed_full_result = *signed_arg1 + signed_arg2; + *signed_arg1 += signed_arg2; + trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *signed_arg1 << end(); + SF = (*signed_arg1 < 0); + ZF = (*signed_arg1 == 0); + OF = (*signed_arg1 != signed_full_result); + // set CF + uint32_t unsigned_arg1 = static_cast(*signed_arg1); + uint32_t unsigned_arg2 = static_cast(signed_arg2); + uint32_t unsigned_result = unsigned_arg1 + unsigned_arg2; + uint64_t unsigned_full_result = unsigned_arg1 + unsigned_arg2; + CF = (unsigned_result != unsigned_full_result); + trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); break; + } // End Op 81 Subops default: cerr << "unrecognized subop for opcode 81: " << NUM(subop) << '\n'; @@ -85,9 +98,20 @@ void test_subtract_imm32_from_eax() { :(before "End Single-Byte Opcodes") case 0x2d: { // subtract imm32 from EAX - const int32_t arg2 = next32(); - trace(Callstack_depth+1, "run") << "subtract imm32 0x" << HEXWORD << arg2 << " from EAX" << end(); - BINARY_ARITHMETIC_OP(-, Reg[EAX].i, arg2); + const int32_t signed_arg2 = next32(); + trace(Callstack_depth+1, "run") << "subtract imm32 0x" << HEXWORD << signed_arg2 << " from EAX" << end(); + int64_t signed_full_result = Reg[EAX].i - signed_arg2; + Reg[EAX].i -= signed_arg2; + trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[EAX].i << end(); + SF = (Reg[EAX].i < 0); + ZF = (Reg[EAX].i == 0); + OF = (Reg[EAX].i != signed_full_result); + // set CF + uint32_t unsigned_arg2 = static_cast(signed_arg2); + uint32_t unsigned_result = Reg[EAX].u - unsigned_arg2; + uint64_t unsigned_full_result = Reg[EAX].u - unsigned_arg2; + CF = (unsigned_result != unsigned_full_result); + trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); break; } @@ -116,7 +140,19 @@ void test_subtract_imm32_from_mem_at_r32() { :(before "End Op 81 Subops") case 5: { trace(Callstack_depth+1, "run") << "subop subtract" << end(); - BINARY_ARITHMETIC_OP(-, *arg1, arg2); + int64_t signed_full_result = *signed_arg1 - signed_arg2; + *signed_arg1 -= signed_arg2; + trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *signed_arg1 << end(); + SF = (*signed_arg1 < 0); + ZF = (*signed_arg1 == 0); + OF = (*signed_arg1 != signed_full_result); + // set CF + uint32_t unsigned_arg1 = static_cast(*signed_arg1); + uint32_t unsigned_arg2 = static_cast(signed_arg2); + uint32_t unsigned_result = unsigned_arg1 - unsigned_arg2; + uint64_t unsigned_full_result = unsigned_arg1 - unsigned_arg2; + CF = (unsigned_result != unsigned_full_result); + trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); break; } @@ -353,9 +389,17 @@ void test_and_imm32_with_eax() { :(before "End Single-Byte Opcodes") case 0x25: { // and imm32 with EAX - const int32_t arg2 = next32(); - trace(Callstack_depth+1, "run") << "and imm32 0x" << HEXWORD << arg2 << " with EAX" << end(); - BINARY_BITWISE_OP(&, Reg[EAX].i, arg2); + // bitwise ops technically operate on unsigned numbers, but it makes no + // difference + const int32_t signed_arg2 = next32(); + trace(Callstack_depth+1, "run") << "and imm32 0x" << HEXWORD << signed_arg2 << " with EAX" << end(); + Reg[EAX].i &= signed_arg2; + trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[EAX].i << end(); + SF = (Reg[EAX].i >> 31); + ZF = (Reg[EAX].i == 0); + CF = false; + OF = false; + trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); break; } @@ -384,7 +428,15 @@ void test_and_imm32_with_mem_at_r32() { :(before "End Op 81 Subops") case 4: { trace(Callstack_depth+1, "run") << "subop and" << end(); - BINARY_BITWISE_OP(&, *arg1, arg2); + // bitwise ops technically operate on unsigned numbers, but it makes no + // difference + *signed_arg1 &= signed_arg2; + trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *signed_arg1 << end(); + SF = (*signed_arg1 >> 31); + ZF = (*signed_arg1 == 0); + CF = false; + OF = false; + trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); break; } @@ -429,9 +481,17 @@ void test_or_imm32_with_eax() { :(before "End Single-Byte Opcodes") case 0x0d: { // or imm32 with EAX - const int32_t arg2 = next32(); - trace(Callstack_depth+1, "run") << "or imm32 0x" << HEXWORD << arg2 << " with EAX" << end(); - BINARY_BITWISE_OP(|, Reg[EAX].i, arg2); + // bitwise ops technically operate on unsigned numbers, but it makes no + // difference + const int32_t signed_arg2 = next32(); + trace(Callstack_depth+1, "run") << "or imm32 0x" << HEXWORD << signed_arg2 << " with EAX" << end(); + Reg[EAX].i |= signed_arg2; + trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[EAX].i << end(); + SF = (Reg[EAX].i >> 31); + ZF = (Reg[EAX].i == 0); + CF = false; + OF = false; + trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); break; } @@ -460,7 +520,15 @@ void test_or_imm32_with_mem_at_r32() { :(before "End Op 81 Subops") case 1: { trace(Callstack_depth+1, "run") << "subop or" << end(); - BINARY_BITWISE_OP(|, *arg1, arg2); + // bitwise ops technically operate on unsigned numbers, but it makes no + // difference + *signed_arg1 |= signed_arg2; \ + trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *signed_arg1 << end(); \ + SF = (*signed_arg1 >> 31); \ + ZF = (*signed_arg1 == 0); \ + CF = false; \ + OF = false; \ + trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); \ break; } @@ -503,9 +571,17 @@ void test_xor_imm32_with_eax() { :(before "End Single-Byte Opcodes") case 0x35: { // xor imm32 with EAX - const int32_t arg2 = next32(); - trace(Callstack_depth+1, "run") << "xor imm32 0x" << HEXWORD << arg2 << " with EAX" << end(); - BINARY_BITWISE_OP(^, Reg[EAX].i, arg2); + // bitwise ops technically operate on unsigned numbers, but it makes no + // difference + const int32_t signed_arg2 = next32(); + trace(Callstack_depth+1, "run") << "xor imm32 0x" << HEXWORD << signed_arg2 << " with EAX" << end(); + Reg[EAX].i ^= signed_arg2; + trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[EAX].i << end(); + SF = (Reg[EAX].i >> 31); + ZF = (Reg[EAX].i == 0); + CF = false; + OF = false; + trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); break; } @@ -534,7 +610,15 @@ void test_xor_imm32_with_mem_at_r32() { :(before "End Op 81 Subops") case 6: { trace(Callstack_depth+1, "run") << "subop xor" << end(); - BINARY_BITWISE_OP(^, *arg1, arg2); + // bitwise ops technically operate on unsigned numbers, but it makes no + // difference + *signed_arg1 ^= signed_arg2; + trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *signed_arg1 << end(); + SF = (*signed_arg1 >> 31); + ZF = (*signed_arg1 == 0); + CF = false; + OF = false; + trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); break; } @@ -644,10 +728,10 @@ void test_compare_imm32_with_r32_greater() { :(before "End Op 81 Subops") case 7: { trace(Callstack_depth+1, "run") << "subop compare" << end(); - const int32_t tmp1 = *arg1 - arg2; + const int32_t tmp1 = *signed_arg1 - signed_arg2; SF = (tmp1 < 0); ZF = (tmp1 == 0); - const int64_t tmp2 = *arg1 - arg2; + const int64_t tmp2 = *signed_arg1 - signed_arg2; OF = (tmp1 != tmp2); trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); break; -- cgit 1.4.1-2-gfad0 From 3f2c4fc564fc7169bb64107b5b7655d76c98204c Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Mon, 13 May 2019 07:53:31 -0700 Subject: . Make the first instruction described something that doesn't touch flags, so we don't introduce too much complexity all at once. --- subx/011run.cc | 44 ++++++++++++++++++++--------------------- subx/015immediate_addressing.cc | 26 ++++++++++++++++++++++-- 2 files changed, 46 insertions(+), 24 deletions(-) (limited to 'subx/015immediate_addressing.cc') diff --git a/subx/011run.cc b/subx/011run.cc index ccc891c3..9c1bc4b0 100644 --- a/subx/011run.cc +++ b/subx/011run.cc @@ -65,19 +65,18 @@ void test_add_imm32_to_eax() { // opcode ModR/M SIB displacement immediate // instruction mod, reg, Reg/Mem bits scale, index, base // 1-3 bytes 0/1 byte 0/1 byte 0/1/2/4 bytes 0/1/2/4 bytes - " 05 . . . 0a 0b 0c 0d\n" // add 0x0d0c0b0a to EAX + " b8 . . . 0a 0b 0c 0d\n" // copy 0x0d0c0b0a to EAX // The periods are just to help the eye track long gaps between columns, // and are otherwise ignored. ); // This program, when run, causes the following events in the trace: CHECK_TRACE_CONTENTS( - "load: 0x00000001 -> 05\n" + "load: 0x00000001 -> b8\n" "load: 0x00000002 -> 0a\n" "load: 0x00000003 -> 0b\n" "load: 0x00000004 -> 0c\n" "load: 0x00000005 -> 0d\n" - "run: add imm32 0x0d0c0b0a to reg EAX\n" - "run: storing 0x0d0c0b0a\n" + "run: copy imm32 0x0d0c0b0a to EAX\n" ); } @@ -350,29 +349,30 @@ void parse_and_load(const string& text_bytes) { //:: run :(before "End Initialize Op Names") -put_new(Name, "05", "add imm32 to EAX (add)"); +put_new(Name, "b8", "copy imm32 to EAX (mov)"); -//: our first opcode :(before "End Single-Byte Opcodes") -case 0x05: { // add imm32 to EAX - int32_t signed_arg2 = next32(); - trace(Callstack_depth+1, "run") << "add imm32 0x" << HEXWORD << signed_arg2 << " to reg EAX" << end(); - int64_t signed_full_result = Reg[EAX].i + signed_arg2; - Reg[EAX].i += signed_arg2; - trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[EAX].i << end(); - SF = (Reg[EAX].i < 0); - ZF = (Reg[EAX].i == 0); - OF = (Reg[EAX].i != signed_full_result); - // set CF - uint32_t unsigned_arg1 = static_cast(Reg[EAX].i); - uint32_t unsigned_arg2 = static_cast(signed_arg2); - uint32_t unsigned_result = unsigned_arg1 + unsigned_arg2; - uint64_t unsigned_full_result = unsigned_arg1 + unsigned_arg2; - CF = (unsigned_result != unsigned_full_result); - trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); +case 0xb8: { // copy imm32 to EAX + const int32_t src = next32(); + trace(Callstack_depth+1, "run") << "copy imm32 0x" << HEXWORD << src << " to EAX" << end(); + Reg[EAX].i = src; break; } +:(code) +void test_copy_imm32_to_EAX() { + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " b8 0a 0b 0c 0d \n" // copy 0x0d0c0b0a to EAX + ); + CHECK_TRACE_CONTENTS( + "run: copy imm32 0x0d0c0b0a to EAX\n" + ); +} + +//: our first opcode + :(code) // read a 32-bit int in little-endian order from the instruction stream int32_t next32() { diff --git a/subx/015immediate_addressing.cc b/subx/015immediate_addressing.cc index 8a0ba020..f4762c2b 100644 --- a/subx/015immediate_addressing.cc +++ b/subx/015immediate_addressing.cc @@ -1,5 +1,28 @@ //: instructions that (immediately) contain an argument to act with +:(before "End Initialize Op Names") +put_new(Name, "05", "add imm32 to EAX (add)"); + +:(before "End Single-Byte Opcodes") +case 0x05: { // add imm32 to EAX + int32_t signed_arg2 = next32(); + trace(Callstack_depth+1, "run") << "add imm32 0x" << HEXWORD << signed_arg2 << " to reg EAX" << end(); + int64_t signed_full_result = Reg[EAX].i + signed_arg2; + Reg[EAX].i += signed_arg2; + trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[EAX].i << end(); + SF = (Reg[EAX].i < 0); + ZF = (Reg[EAX].i == 0); + OF = (Reg[EAX].i != signed_full_result); + // set CF + uint32_t unsigned_arg1 = static_cast(Reg[EAX].i); + uint32_t unsigned_arg2 = static_cast(signed_arg2); + uint32_t unsigned_result = unsigned_arg1 + unsigned_arg2; + uint64_t unsigned_full_result = unsigned_arg1 + unsigned_arg2; + CF = (unsigned_result != unsigned_full_result); + trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); + break; +} + :(before "End Initialize Op Names") put_new(Name, "81", "combine rm32 with imm32 based on subop (add/sub/and/or/xor/cmp)"); @@ -832,7 +855,7 @@ void test_compare_imm32_with_mem_at_r32_equal() { //:: copy (mov) :(before "End Initialize Op Names") -put_new(Name, "b8", "copy imm32 to EAX (mov)"); +// b8 defined earlier to copy imm32 to EAX put_new(Name, "b9", "copy imm32 to ECX (mov)"); put_new(Name, "ba", "copy imm32 to EDX (mov)"); put_new(Name, "bb", "copy imm32 to EBX (mov)"); @@ -854,7 +877,6 @@ void test_copy_imm32_to_r32() { } :(before "End Single-Byte Opcodes") -case 0xb8: case 0xb9: case 0xba: case 0xbb: -- cgit 1.4.1-2-gfad0 From 40f4f1b454a3510c35dfa41db1dff323793ec895 Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Mon, 13 May 2019 10:54:42 -0700 Subject: . Standardize layout of some code fragments, and fix several bugs in computing the overflow flag in the process. a64 = b32 + c32 doesn't benefit from `a` being 64-bit without casting `b`. --- subx/013direct_addressing.cc | 13 ++++---- subx/014indirect_addressing.cc | 21 ++++++------ subx/015immediate_addressing.cc | 72 ++++++++++++++++++++--------------------- 3 files changed, 52 insertions(+), 54 deletions(-) (limited to 'subx/015immediate_addressing.cc') diff --git a/subx/013direct_addressing.cc b/subx/013direct_addressing.cc index 7b3997f6..d4dcd92a 100644 --- a/subx/013direct_addressing.cc +++ b/subx/013direct_addressing.cc @@ -27,9 +27,9 @@ case 0x01: { // add r32 to r/m32 trace(Callstack_depth+1, "run") << "add " << rname(arg2) << " to r/m32" << end(); int32_t* signed_arg1 = effective_address(modrm); int32_t signed_result = *signed_arg1 + Reg[arg2].i; - int64_t signed_full_result = static_cast(*signed_arg1) + Reg[arg2].i; SF = (signed_result < 0); ZF = (signed_result == 0); + int64_t signed_full_result = static_cast(*signed_arg1) + Reg[arg2].i; OF = (signed_result != signed_full_result); // set CF uint32_t unsigned_arg1 = static_cast(*signed_arg1); @@ -176,9 +176,9 @@ case 0x29: { // subtract r32 from r/m32 trace(Callstack_depth+1, "run") << "subtract " << rname(arg2) << " from r/m32" << end(); int32_t* signed_arg1 = effective_address(modrm); int32_t signed_result = *signed_arg1 - Reg[arg2].i; - int64_t signed_full_result = static_cast(*signed_arg1) - Reg[arg2].i; SF = (signed_result < 0); ZF = (signed_result == 0); + int64_t signed_full_result = static_cast(*signed_arg1) - Reg[arg2].i; OF = (signed_result != signed_full_result); // set CF uint32_t unsigned_arg1 = static_cast(*signed_arg1); @@ -275,7 +275,7 @@ case 0xf7: { switch (subop) { case 4: { // mul unsigned EAX by r/m32 trace(Callstack_depth+1, "run") << "subop: multiply EAX by r/m32" << end(); - const uint64_t result = Reg[EAX].u * static_cast(*arg1); + const uint64_t result = static_cast(Reg[EAX].u) * static_cast(*arg1); Reg[EAX].u = result & 0xffffffff; Reg[EDX].u = result >> 32; OF = (Reg[EDX].u != 0); @@ -318,14 +318,15 @@ case 0xaf: { // multiply r32 by r/m32 const uint8_t arg1 = (modrm>>3)&0x7; trace(Callstack_depth+1, "run") << "multiply " << rname(arg1) << " by r/m32" << end(); const int32_t* arg2 = effective_address(modrm); - int64_t full_result = Reg[arg1].i * (*arg2); - Reg[arg1].i *= (*arg2); - trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[arg1].i << end(); + int32_t result = Reg[arg1].i * (*arg2); SF = (Reg[arg1].i < 0); ZF = (Reg[arg1].i == 0); + int64_t full_result = static_cast(Reg[arg1].i) * (*arg2); OF = (Reg[arg1].i != full_result); CF = OF; trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); + Reg[arg1].i = result; + trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[arg1].i << end(); break; } diff --git a/subx/014indirect_addressing.cc b/subx/014indirect_addressing.cc index bf00747a..5ac0845c 100644 --- a/subx/014indirect_addressing.cc +++ b/subx/014indirect_addressing.cc @@ -61,9 +61,9 @@ case 0x03: { // add r/m32 to r32 trace(Callstack_depth+1, "run") << "add r/m32 to " << rname(arg1) << end(); const int32_t* signed_arg2 = effective_address(modrm); int32_t signed_result = Reg[arg1].i + *signed_arg2; - int64_t signed_full_result = static_cast(Reg[arg1].i) + *signed_arg2; SF = (signed_result < 0); ZF = (signed_result == 0); + int64_t signed_full_result = static_cast(Reg[arg1].i) + *signed_arg2; OF = (signed_result != signed_full_result); // set CF uint32_t unsigned_arg2 = static_cast(*signed_arg2); @@ -189,9 +189,9 @@ case 0x2b: { // subtract r/m32 from r32 trace(Callstack_depth+1, "run") << "subtract r/m32 from " << rname(arg1) << end(); const int32_t* signed_arg2 = effective_address(modrm); const int32_t signed_result = Reg[arg1].i - *signed_arg2; - int64_t signed_full_result = static_cast(Reg[arg1].i) - *signed_arg2; SF = (signed_result < 0); ZF = (signed_result == 0); + int64_t signed_full_result = static_cast(Reg[arg1].i) - *signed_arg2; OF = (signed_result != signed_full_result); // set CF uint32_t unsigned_arg2 = static_cast(*signed_arg2); @@ -563,15 +563,14 @@ case 0x3b: { // set SF if r32 < r/m32 trace(Callstack_depth+1, "run") << "compare " << rname(reg1) << " with r/m32" << end(); const int32_t signed_arg1 = Reg[reg1].i; const int32_t* signed_arg2 = effective_address(modrm); - const int32_t signed_difference = signed_arg1 - *signed_arg2; + const int32_t signed_difference = Reg[reg1].i - *signed_arg2; SF = (signed_difference < 0); ZF = (signed_difference == 0); - int64_t full_signed_difference = signed_arg1 - *signed_arg2; + int64_t full_signed_difference = static_cast(Reg[reg1].i) - *signed_arg2; OF = (signed_difference != full_signed_difference); - const uint32_t unsigned_arg1 = static_cast(signed_arg1); const uint32_t unsigned_arg2 = static_cast(*signed_arg2); - const uint32_t unsigned_difference = unsigned_arg1 - unsigned_arg2; - const uint64_t full_unsigned_difference = unsigned_arg1 - unsigned_arg2; + const uint32_t unsigned_difference = Reg[reg1].u - unsigned_arg2; + const uint64_t full_unsigned_difference = static_cast(Reg[reg1].u) - unsigned_arg2; CF = (unsigned_difference != full_unsigned_difference); trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); break; @@ -584,7 +583,7 @@ void test_compare_r32_with_mem_at_r32_lesser() { run( "== 0x1\n" // code segment // op ModR/M SIB displacement immediate - " 3b 18 \n" // compare *EAX with EBX + " 3b 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 @@ -592,18 +591,17 @@ void test_compare_r32_with_mem_at_r32_lesser() { CHECK_TRACE_CONTENTS( "run: compare EBX with r/m32\n" "run: effective address is 0x00002000 (EAX)\n" - "run: SF=1; ZF=0; CF=0; OF=0\n" + "run: SF=1; ZF=0; CF=1; 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 + " 3b 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 @@ -617,7 +615,6 @@ void test_compare_r32_with_mem_at_r32_equal() { //:: copy (mov) -:(code) void test_copy_r32_to_mem_at_r32() { Reg[EBX].i = 0xaf; Reg[EAX].i = 0x60; diff --git a/subx/015immediate_addressing.cc b/subx/015immediate_addressing.cc index f4762c2b..7abf7951 100644 --- a/subx/015immediate_addressing.cc +++ b/subx/015immediate_addressing.cc @@ -7,19 +7,19 @@ put_new(Name, "05", "add imm32 to EAX (add)"); case 0x05: { // add imm32 to EAX int32_t signed_arg2 = next32(); trace(Callstack_depth+1, "run") << "add imm32 0x" << HEXWORD << signed_arg2 << " to reg EAX" << end(); - int64_t signed_full_result = Reg[EAX].i + signed_arg2; - Reg[EAX].i += signed_arg2; - trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[EAX].i << end(); - SF = (Reg[EAX].i < 0); - ZF = (Reg[EAX].i == 0); - OF = (Reg[EAX].i != signed_full_result); + int32_t signed_result = Reg[EAX].i + signed_arg2; + SF = (signed_result < 0); + ZF = (signed_result == 0); + int64_t signed_full_result = static_cast(Reg[EAX].i) + signed_arg2; + OF = (signed_result != signed_full_result); // set CF - uint32_t unsigned_arg1 = static_cast(Reg[EAX].i); uint32_t unsigned_arg2 = static_cast(signed_arg2); - uint32_t unsigned_result = unsigned_arg1 + unsigned_arg2; - uint64_t unsigned_full_result = unsigned_arg1 + unsigned_arg2; + uint32_t unsigned_result = Reg[EAX].u + unsigned_arg2; + uint64_t unsigned_full_result = static_cast(Reg[EAX].u) + unsigned_arg2; CF = (unsigned_result != unsigned_full_result); trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); + Reg[EAX].i = signed_result; + trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[EAX].i << end(); break; } @@ -55,19 +55,20 @@ case 0x81: { // combine imm32 with r/m32 switch (subop) { case 0: { trace(Callstack_depth+1, "run") << "subop add" << end(); - int64_t signed_full_result = *signed_arg1 + signed_arg2; - *signed_arg1 += signed_arg2; - trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *signed_arg1 << end(); - SF = (*signed_arg1 < 0); - ZF = (*signed_arg1 == 0); - OF = (*signed_arg1 != signed_full_result); + int32_t signed_result = *signed_arg1 + signed_arg2; + SF = (signed_result < 0); + ZF = (signed_result == 0); + int64_t signed_full_result = static_cast(*signed_arg1) + signed_arg2; + OF = (signed_result != signed_full_result); // set CF uint32_t unsigned_arg1 = static_cast(*signed_arg1); uint32_t unsigned_arg2 = static_cast(signed_arg2); uint32_t unsigned_result = unsigned_arg1 + unsigned_arg2; - uint64_t unsigned_full_result = unsigned_arg1 + unsigned_arg2; + uint64_t unsigned_full_result = static_cast(unsigned_arg1) + unsigned_arg2; CF = (unsigned_result != unsigned_full_result); trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); + *signed_arg1 = signed_result; + trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *signed_arg1 << end(); break; } // End Op 81 Subops @@ -163,19 +164,20 @@ void test_subtract_imm32_from_mem_at_r32() { :(before "End Op 81 Subops") case 5: { trace(Callstack_depth+1, "run") << "subop subtract" << end(); - int64_t signed_full_result = *signed_arg1 - signed_arg2; - *signed_arg1 -= signed_arg2; - trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *signed_arg1 << end(); - SF = (*signed_arg1 < 0); - ZF = (*signed_arg1 == 0); - OF = (*signed_arg1 != signed_full_result); + int32_t signed_result = *signed_arg1 - signed_arg2; + SF = (signed_result < 0); + ZF = (signed_result == 0); + int64_t signed_full_result = static_cast(*signed_arg1) - signed_arg2; + OF = (signed_result != signed_full_result); // set CF uint32_t unsigned_arg1 = static_cast(*signed_arg1); uint32_t unsigned_arg2 = static_cast(signed_arg2); uint32_t unsigned_result = unsigned_arg1 - unsigned_arg2; - uint64_t unsigned_full_result = unsigned_arg1 - unsigned_arg2; + uint64_t unsigned_full_result = static_cast(unsigned_arg1) - unsigned_arg2; CF = (unsigned_result != unsigned_full_result); trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); + *signed_arg1 = signed_result; + trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *signed_arg1 << end(); break; } @@ -674,10 +676,10 @@ void test_compare_imm32_with_eax_greater() { run( "== 0x1\n" // code segment // op ModR/M SIB displacement immediate - " 3d 07 0b 0c 0d \n" // compare 0x0d0c0b07 with EAX + " 3d 07 0b 0c 0d \n" // compare EAX with 0x0d0c0b07 ); CHECK_TRACE_CONTENTS( - "run: compare EAX and imm32 0x0d0c0b07\n" + "run: compare EAX with imm32 0x0d0c0b07\n" "run: SF=0; ZF=0; CF=0; OF=0\n" ); } @@ -686,36 +688,35 @@ void test_compare_imm32_with_eax_greater() { case 0x3d: { // compare EAX with imm32 const int32_t signed_arg1 = Reg[EAX].i; const int32_t signed_arg2 = next32(); - trace(Callstack_depth+1, "run") << "compare EAX and imm32 0x" << HEXWORD << signed_arg2 << end(); + trace(Callstack_depth+1, "run") << "compare EAX with imm32 0x" << HEXWORD << signed_arg2 << end(); const int32_t signed_difference = signed_arg1 - signed_arg2; SF = (signed_difference < 0); ZF = (signed_difference == 0); - const int64_t full_signed_difference = signed_arg1 - signed_arg2; + const int64_t full_signed_difference = static_cast(signed_arg1) - signed_arg2; OF = (signed_difference != full_signed_difference); const uint32_t unsigned_arg1 = static_cast(signed_arg1); const uint32_t unsigned_arg2 = static_cast(signed_arg2); const uint32_t unsigned_difference = unsigned_arg1 - unsigned_arg2; - const uint64_t full_unsigned_difference = unsigned_arg1 - unsigned_arg2; + const uint64_t full_unsigned_difference = static_cast(unsigned_arg1) - unsigned_arg2; CF = (unsigned_difference != full_unsigned_difference); trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); break; } :(code) -void test_compare_imm32_with_eax_lesser() { +void test_compare_eax_with_imm32_lesser() { Reg[EAX].i = 0x0d0c0b07; run( "== 0x1\n" // code segment // op ModR/M SIB displacement immediate - " 3d 0a 0b 0c 0d \n" // compare 0x0d0c0b0a with EAX + " 3d 0a 0b 0c 0d \n" // compare EAX with 0x0d0c0b0a ); CHECK_TRACE_CONTENTS( - "run: compare EAX and imm32 0x0d0c0b0a\n" - "run: SF=1; ZF=0; CF=0; OF=0\n" + "run: compare EAX with imm32 0x0d0c0b0a\n" + "run: SF=1; ZF=0; CF=1; OF=0\n" ); } -:(code) void test_compare_imm32_with_eax_equal() { Reg[EAX].i = 0x0d0c0b0a; run( @@ -724,14 +725,13 @@ void test_compare_imm32_with_eax_equal() { " 3d 0a 0b 0c 0d \n" // compare 0x0d0c0b0a with EAX ); CHECK_TRACE_CONTENTS( - "run: compare EAX and imm32 0x0d0c0b0a\n" + "run: compare EAX with imm32 0x0d0c0b0a\n" "run: SF=0; ZF=1; CF=0; OF=0\n" ); } //: -:(code) void test_compare_imm32_with_r32_greater() { Reg[EBX].i = 0x0d0c0b0a; run( @@ -754,7 +754,7 @@ case 7: { const int32_t tmp1 = *signed_arg1 - signed_arg2; SF = (tmp1 < 0); ZF = (tmp1 == 0); - const int64_t tmp2 = *signed_arg1 - signed_arg2; + const int64_t tmp2 = static_cast(*signed_arg1) - signed_arg2; OF = (tmp1 != tmp2); trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); break; -- cgit 1.4.1-2-gfad0 From 241dc91982691c1c6c7c342c40f1812611268741 Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Mon, 13 May 2019 11:45:46 -0700 Subject: . --- subx/015immediate_addressing.cc | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'subx/015immediate_addressing.cc') diff --git a/subx/015immediate_addressing.cc b/subx/015immediate_addressing.cc index 7abf7951..30f96523 100644 --- a/subx/015immediate_addressing.cc +++ b/subx/015immediate_addressing.cc @@ -124,18 +124,19 @@ void test_subtract_imm32_from_eax() { case 0x2d: { // subtract imm32 from EAX const int32_t signed_arg2 = next32(); trace(Callstack_depth+1, "run") << "subtract imm32 0x" << HEXWORD << signed_arg2 << " from EAX" << end(); - int64_t signed_full_result = Reg[EAX].i - signed_arg2; - Reg[EAX].i -= signed_arg2; - trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[EAX].i << end(); - SF = (Reg[EAX].i < 0); - ZF = (Reg[EAX].i == 0); - OF = (Reg[EAX].i != signed_full_result); + int32_t signed_result = Reg[EAX].i - signed_arg2; + SF = (signed_result < 0); + ZF = (signed_result == 0); + int64_t signed_full_result = static_cast(Reg[EAX].i) - signed_arg2; + OF = (signed_result != signed_full_result); // set CF uint32_t unsigned_arg2 = static_cast(signed_arg2); uint32_t unsigned_result = Reg[EAX].u - unsigned_arg2; - uint64_t unsigned_full_result = Reg[EAX].u - unsigned_arg2; + uint64_t unsigned_full_result = static_cast(Reg[EAX].u) - unsigned_arg2; CF = (unsigned_result != unsigned_full_result); trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); + Reg[EAX].i = signed_result; + trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[EAX].i << end(); break; } -- cgit 1.4.1-2-gfad0 From dd7077f729e12ff42b36e09d24e8e09388fda2dd Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Mon, 13 May 2019 12:10:23 -0700 Subject: flag tests for opcode 05 --- subx/015immediate_addressing.cc | 51 +++++++++++++++++++++++++++++++++++++- subx/034compute_segment_address.cc | 2 +- 2 files changed, 51 insertions(+), 2 deletions(-) (limited to 'subx/015immediate_addressing.cc') diff --git a/subx/015immediate_addressing.cc b/subx/015immediate_addressing.cc index 30f96523..eedf81a3 100644 --- a/subx/015immediate_addressing.cc +++ b/subx/015immediate_addressing.cc @@ -6,7 +6,7 @@ put_new(Name, "05", "add imm32 to EAX (add)"); :(before "End Single-Byte Opcodes") case 0x05: { // add imm32 to EAX int32_t signed_arg2 = next32(); - trace(Callstack_depth+1, "run") << "add imm32 0x" << HEXWORD << signed_arg2 << " to reg EAX" << end(); + trace(Callstack_depth+1, "run") << "add imm32 0x" << HEXWORD << signed_arg2 << " to EAX" << end(); int32_t signed_result = Reg[EAX].i + signed_arg2; SF = (signed_result < 0); ZF = (signed_result == 0); @@ -23,6 +23,55 @@ case 0x05: { // add imm32 to EAX break; } +:(code) +void test_add_imm32_to_EAX_signed_overflow() { + Reg[EAX].i = 0x7fffffff; // largest positive signed integer + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " 05 01 00 00 00 \n" // add 1 to EAX + // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) + ); + CHECK_TRACE_CONTENTS( + "run: add imm32 0x00000001 to EAX\n" + "run: SF=1; ZF=0; CF=0; OF=1\n" + "run: storing 0x80000000\n" + ); +} + +void test_add_imm32_to_EAX_unsigned_overflow() { + Reg[EAX].u = 0xffffffff; // largest unsigned number + Reg[EBX].u = 1; + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " 05 01 00 00 00 \n" // add 1 to EAX + // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) + ); + CHECK_TRACE_CONTENTS( + "run: add imm32 0x00000001 to EAX\n" + "run: SF=0; ZF=1; CF=1; OF=0\n" + "run: storing 0x00000000\n" + ); +} + +void test_add_imm32_to_EAX_unsigned_and_signed_overflow() { + Reg[EAX].u = 0x80000000; // smallest negative signed integer + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " 05 00 00 00 80 \n" // add 0x80000000 to EAX + // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) + ); + CHECK_TRACE_CONTENTS( + "run: add imm32 0x80000000 to EAX\n" + "run: SF=0; ZF=1; CF=1; OF=1\n" + "run: storing 0x00000000\n" + ); +} + +//: + :(before "End Initialize Op Names") put_new(Name, "81", "combine rm32 with imm32 based on subop (add/sub/and/or/xor/cmp)"); diff --git a/subx/034compute_segment_address.cc b/subx/034compute_segment_address.cc index a1b7482d..47311219 100644 --- a/subx/034compute_segment_address.cc +++ b/subx/034compute_segment_address.cc @@ -14,7 +14,7 @@ void test_segment_name() { "load: 0x09000056 -> 0b\n" "load: 0x09000057 -> 0c\n" "load: 0x09000058 -> 0d\n" - "run: add imm32 0x0d0c0b0a to reg EAX\n" + "run: add imm32 0x0d0c0b0a to EAX\n" "run: storing 0x0d0c0b0a\n" ); } -- cgit 1.4.1-2-gfad0 From e6f8c7f64aaba15ef1ccf5f3bc73096bed0e4467 Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Mon, 13 May 2019 12:28:24 -0700 Subject: flag tests for opcode 81 --- subx/015immediate_addressing.cc | 152 +++++++++++++++++++++++++++++++++++----- 1 file changed, 135 insertions(+), 17 deletions(-) (limited to 'subx/015immediate_addressing.cc') diff --git a/subx/015immediate_addressing.cc b/subx/015immediate_addressing.cc index eedf81a3..7c0da1a0 100644 --- a/subx/015immediate_addressing.cc +++ b/subx/015immediate_addressing.cc @@ -82,7 +82,7 @@ void test_add_imm32_to_r32() { "== 0x1\n" // code segment // op ModR/M SIB displacement immediate " 81 c3 0a 0b 0c 0d\n" // add 0x0d0c0b0a to EBX - // ModR/M in binary: 11 (direct mode) 000 (add imm32) 011 (dest EBX) + // ModR/M in binary: 11 (direct mode) 000 (subop add) 011 (dest EBX) ); CHECK_TRACE_CONTENTS( "run: combine imm32 with r/m32\n" @@ -128,6 +128,61 @@ case 0x81: { // combine imm32 with r/m32 break; } +:(code) +void test_add_imm32_to_r32_signed_overflow() { + Reg[EBX].i = 0x7fffffff; // largest positive signed integer + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " 81 c3 01 00 00 00\n" // add 1 to EBX + // ModR/M in binary: 11 (direct mode) 000 (subop add) 011 (dest EBX) + ); + CHECK_TRACE_CONTENTS( + "run: combine imm32 with r/m32\n" + "run: r/m32 is EBX\n" + "run: imm32 is 0x00000001\n" + "run: subop add\n" + "run: SF=1; ZF=0; CF=0; OF=1\n" + "run: storing 0x80000000\n" + ); +} + +void test_add_imm32_to_r32_unsigned_overflow() { + Reg[EBX].u = 0xffffffff; // largest unsigned number + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " 81 c3 01 00 00 00\n" // add 1 to EBX + // ModR/M in binary: 11 (direct mode) 011 (subop add) 011 (dest EBX) + ); + CHECK_TRACE_CONTENTS( + "run: combine imm32 with r/m32\n" + "run: r/m32 is EBX\n" + "run: imm32 is 0x00000001\n" + "run: subop add\n" + "run: SF=0; ZF=1; CF=1; OF=0\n" + "run: storing 0x00000000\n" + ); +} + +void test_add_imm32_to_r32_unsigned_and_signed_overflow() { + Reg[EBX].u = 0x80000000; // smallest negative signed integer + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " 81 c3 00 00 00 80\n" // add 0x80000000 to EBX + // ModR/M in binary: 11 (direct mode) 011 (subop add) 011 (dest EBX) + ); + CHECK_TRACE_CONTENTS( + "run: combine imm32 with r/m32\n" + "run: r/m32 is EBX\n" + "run: imm32 is 0x80000000\n" + "run: subop add\n" + "run: SF=0; ZF=1; CF=1; OF=1\n" + "run: storing 0x00000000\n" + ); +} + //: :(code) @@ -137,7 +192,7 @@ void test_add_imm32_to_mem_at_r32() { "== 0x1\n" // code segment // op ModR/M SIB displacement immediate " 81 03 0a 0b 0c 0d \n" // add 0x0d0c0b0a to *EBX - // ModR/M in binary: 00 (indirect mode) 000 (add imm32) 011 (dest EBX) + // ModR/M in binary: 00 (indirect mode) 000 (subop add) 011 (dest EBX) "== 0x2000\n" // data segment "01 00 00 00\n" // 0x00000001 ); @@ -198,7 +253,7 @@ void test_subtract_imm32_from_mem_at_r32() { "== 0x1\n" // code segment // op ModR/M SIB displacement immediate " 81 2b 01 00 00 00 \n" // subtract 1 from *EBX - // ModR/M in binary: 00 (indirect mode) 101 (subtract imm32) 011 (dest EBX) + // ModR/M in binary: 00 (indirect mode) 101 (subop subtract) 011 (dest EBX) "== 0x2000\n" // data segment "0a 00 00 00\n" // 0x0000000a ); @@ -231,16 +286,79 @@ case 5: { break; } +:(code) +void test_subtract_imm32_from_mem_at_r32_signed_overflow() { + Reg[EBX].i = 0x2000; + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " 81 2b ff ff ff 7f \n" // subtract largest positive signed integer from *EBX + // ModR/M in binary: 00 (indirect mode) 101 (subop subtract) 011 (dest EBX) + "== 0x2000\n" // data segment + "00 00 00 80\n" // smallest negative signed integer + ); + CHECK_TRACE_CONTENTS( + "run: combine imm32 with r/m32\n" + "run: effective address is 0x00002000 (EBX)\n" + "run: effective address contains 80000000\n" + "run: imm32 is 0x7fffffff\n" + "run: subop subtract\n" + "run: SF=0; ZF=0; CF=0; OF=1\n" + "run: storing 0x00000001\n" + ); +} + +void test_subtract_imm32_from_mem_at_r32_unsigned_overflow() { + Reg[EBX].i = 0x2000; + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " 81 2b 01 00 00 00 \n" // subtract 1 from *EBX + // ModR/M in binary: 00 (indirect mode) 101 (subop subtract) 011 (dest EBX) + "== 0x2000\n" // data segment + "00 00 00 00\n" // 0 + ); + CHECK_TRACE_CONTENTS( + "run: combine imm32 with r/m32\n" + "run: effective address is 0x00002000 (EBX)\n" + "run: effective address contains 0\n" + "run: imm32 is 0x00000001\n" + "run: subop subtract\n" + "run: SF=1; ZF=0; CF=1; OF=0\n" + "run: storing 0xffffffff\n" + ); +} + +void test_subtract_imm32_from_mem_at_r32_signed_and_unsigned_overflow() { + Reg[EBX].i = 0x2000; + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " 81 2b 00 00 00 80 \n" // subtract smallest negative signed integer from *EBX + // ModR/M in binary: 00 (indirect mode) 101 (subop subtract) 011 (dest EBX) + "== 0x2000\n" // data segment + "00 00 00 00\n" // 0 + ); + CHECK_TRACE_CONTENTS( + "run: combine imm32 with r/m32\n" + "run: effective address is 0x00002000 (EBX)\n" + "run: effective address contains 0\n" + "run: imm32 is 0x80000000\n" + "run: subop subtract\n" + "run: SF=1; ZF=0; CF=1; OF=1\n" + "run: storing 0x80000000\n" + ); +} + //: -:(code) void test_subtract_imm32_from_r32() { Reg[EBX].i = 10; run( "== 0x1\n" // code segment // op ModR/M SIB displacement immediate " 81 eb 01 00 00 00 \n" // subtract 1 from EBX - // ModR/M in binary: 11 (direct mode) 101 (subtract imm32) 011 (dest EBX) + // ModR/M in binary: 11 (direct mode) 101 (subop subtract) 011 (dest EBX) ); CHECK_TRACE_CONTENTS( "run: combine imm32 with r/m32\n" @@ -487,7 +605,7 @@ void test_and_imm32_with_mem_at_r32() { "== 0x1\n" // code segment // op ModR/M SIB displacement immediate " 81 23 0a 0b 0c 0d \n" // and 0x0d0c0b0a with *EBX - // ModR/M in binary: 00 (indirect mode) 100 (and imm32) 011 (dest EBX) + // ModR/M in binary: 00 (indirect mode) 100 (subop and) 011 (dest EBX) "== 0x2000\n" // data segment "ff 00 00 00\n" // 0x000000ff ); @@ -524,7 +642,7 @@ void test_and_imm32_with_r32() { "== 0x1\n" // code segment // op ModR/M SIB displacement immediate " 81 e3 0a 0b 0c 0d \n" // and 0x0d0c0b0a with EBX - // ModR/M in binary: 11 (direct mode) 100 (and imm32) 011 (dest EBX) + // ModR/M in binary: 11 (direct mode) 100 (subop and) 011 (dest EBX) ); CHECK_TRACE_CONTENTS( "run: combine imm32 with r/m32\n" @@ -579,7 +697,7 @@ void test_or_imm32_with_mem_at_r32() { "== 0x1\n" // code segment // op ModR/M SIB displacement immediate " 81 0b 0a 0b 0c 0d \n" // or 0x0d0c0b0a with *EBX - // ModR/M in binary: 00 (indirect mode) 001 (or imm32) 011 (dest EBX) + // ModR/M in binary: 00 (indirect mode) 001 (subop or) 011 (dest EBX) "== 0x2000\n" // data segment "a0 b0 c0 d0\n" // 0xd0c0b0a0 ); @@ -614,7 +732,7 @@ void test_or_imm32_with_r32() { "== 0x1\n" // code segment // op ModR/M SIB displacement immediate " 81 cb 0a 0b 0c 0d \n" // or 0x0d0c0b0a with EBX - // ModR/M in binary: 11 (direct mode) 001 (or imm32) 011 (dest EBX) + // ModR/M in binary: 11 (direct mode) 001 (subop or) 011 (dest EBX) ); CHECK_TRACE_CONTENTS( "run: combine imm32 with r/m32\n" @@ -669,7 +787,7 @@ void test_xor_imm32_with_mem_at_r32() { "== 0x1\n" // code segment // op ModR/M SIB displacement immediate " 81 33 0a 0b 0c 0d \n" // xor 0x0d0c0b0a with *EBX - // ModR/M in binary: 00 (indirect mode) 110 (xor imm32) 011 (dest EBX) + // ModR/M in binary: 00 (indirect mode) 110 (subop xor) 011 (dest EBX) "== 0x2000\n" // data segment "a0 b0 c0 d0\n" // 0xd0c0b0a0 ); @@ -704,7 +822,7 @@ void test_xor_imm32_with_r32() { "== 0x1\n" // code segment // op ModR/M SIB displacement immediate " 81 f3 0a 0b 0c 0d \n" // xor 0x0d0c0b0a with EBX - // ModR/M in binary: 11 (direct mode) 110 (xor imm32) 011 (dest EBX) + // ModR/M in binary: 11 (direct mode) 110 (subop xor) 011 (dest EBX) ); CHECK_TRACE_CONTENTS( "run: combine imm32 with r/m32\n" @@ -788,7 +906,7 @@ void test_compare_imm32_with_r32_greater() { "== 0x1\n" // code segment // op ModR/M SIB displacement immediate " 81 fb 07 0b 0c 0d \n" // compare 0x0d0c0b07 with EBX - // ModR/M in binary: 11 (direct mode) 111 (compare imm32) 011 (dest EBX) + // ModR/M in binary: 11 (direct mode) 111 (subop compare) 011 (dest EBX) ); CHECK_TRACE_CONTENTS( "run: combine imm32 with r/m32\n" @@ -817,7 +935,7 @@ void test_compare_imm32_with_r32_lesser() { "== 0x1\n" // code segment // op ModR/M SIB displacement immediate " 81 fb 0a 0b 0c 0d \n" // compare 0x0d0c0b0a with EBX - // ModR/M in binary: 11 (direct mode) 111 (compare imm32) 011 (dest EBX) + // ModR/M in binary: 11 (direct mode) 111 (subop compare) 011 (dest EBX) ); CHECK_TRACE_CONTENTS( "run: combine imm32 with r/m32\n" @@ -834,7 +952,7 @@ void test_compare_imm32_with_r32_equal() { "== 0x1\n" // code segment // op ModR/M SIB displacement immediate " 81 fb 0a 0b 0c 0d \n" // compare 0x0d0c0b0a with EBX - // ModR/M in binary: 11 (direct mode) 111 (compare imm32) 011 (dest EBX) + // ModR/M in binary: 11 (direct mode) 111 (subop compare) 011 (dest EBX) ); CHECK_TRACE_CONTENTS( "run: combine imm32 with r/m32\n" @@ -851,7 +969,7 @@ void test_compare_imm32_with_mem_at_r32_greater() { "== 0x1\n" // code segment // op ModR/M SIB displacement immediate " 81 3b 07 0b 0c 0d \n" // compare 0x0d0c0b07 with *EBX - // ModR/M in binary: 00 (indirect mode) 111 (compare imm32) 011 (dest EBX) + // ModR/M in binary: 00 (indirect mode) 111 (subop compare) 011 (dest EBX) "== 0x2000\n" // data segment "0a 0b 0c 0d\n" // 0x0d0c0b0a ); @@ -870,7 +988,7 @@ void test_compare_imm32_with_mem_at_r32_lesser() { "== 0x1\n" // code segment // op ModR/M SIB displacement immediate " 81 3b 0a 0b 0c 0d \n" // compare 0x0d0c0b0a with *EBX - // ModR/M in binary: 00 (indirect mode) 111 (compare imm32) 011 (dest EBX) + // ModR/M in binary: 00 (indirect mode) 111 (subop compare) 011 (dest EBX) "== 0x2000\n" // data segment "07 0b 0c 0d\n" // 0x0d0c0b07 ); @@ -890,7 +1008,7 @@ void test_compare_imm32_with_mem_at_r32_equal() { "== 0x1\n" // code segment // op ModR/M SIB displacement immediate " 81 3b 0a 0b 0c 0d \n" // compare 0x0d0c0b0a with *EBX - // ModR/M in binary: 00 (indirect mode) 111 (compare imm32) 011 (dest EBX) + // ModR/M in binary: 00 (indirect mode) 111 (subop compare) 011 (dest EBX) "== 0x2000\n" // data segment "0a 0b 0c 0d\n" // 0x0d0c0b0a ); -- cgit 1.4.1-2-gfad0 From cb7b44647e5cf1bdb146986f205dfc71c8263fd5 Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Mon, 13 May 2019 12:36:00 -0700 Subject: flag tests for opcode 2d --- subx/015immediate_addressing.cc | 47 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) (limited to 'subx/015immediate_addressing.cc') diff --git a/subx/015immediate_addressing.cc b/subx/015immediate_addressing.cc index 7c0da1a0..959482cb 100644 --- a/subx/015immediate_addressing.cc +++ b/subx/015immediate_addressing.cc @@ -244,9 +244,54 @@ case 0x2d: { // subtract imm32 from EAX break; } +:(code) +void test_subtract_imm32_from_EAX_signed_overflow() { + Reg[EAX].i = 0x80000000; // smallest negative signed integer + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " 2d ff ff ff 7f \n" // subtract largest positive signed integer from EAX + // ModR/M in binary: 00 (indirect mode) 101 (subop subtract) 011 (dest EBX) + ); + CHECK_TRACE_CONTENTS( + "run: subtract imm32 0x7fffffff from EAX\n" + "run: SF=0; ZF=0; CF=0; OF=1\n" + "run: storing 0x00000001\n" + ); +} + +void test_subtract_imm32_from_EAX_unsigned_overflow() { + Reg[EAX].i = 0; + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " 2d 01 00 00 00 \n" // subtract 1 from EAX + // ModR/M in binary: 00 (indirect mode) 101 (subop subtract) 011 (dest EBX) + ); + CHECK_TRACE_CONTENTS( + "run: subtract imm32 0x00000001 from EAX\n" + "run: SF=1; ZF=0; CF=1; OF=0\n" + "run: storing 0xffffffff\n" + ); +} + +void test_subtract_imm32_from_EAX_signed_and_unsigned_overflow() { + Reg[EAX].i = 0; + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " 2d 00 00 00 80 \n" // subtract smallest negative signed integer from EAX + // ModR/M in binary: 00 (indirect mode) 101 (subop subtract) 011 (dest EBX) + ); + CHECK_TRACE_CONTENTS( + "run: subtract imm32 0x80000000 from EAX\n" + "run: SF=1; ZF=0; CF=1; OF=1\n" + "run: storing 0x80000000\n" + ); +} + //: -:(code) void test_subtract_imm32_from_mem_at_r32() { Reg[EBX].i = 0x2000; run( -- cgit 1.4.1-2-gfad0 From 59a04f794f45864fe0901a9747ca24cfc41a9bb4 Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Mon, 13 May 2019 12:38:36 -0700 Subject: . --- subx/011run.cc | 2 +- subx/013direct_addressing.cc | 10 +++++----- subx/015immediate_addressing.cc | 14 +++++++------- 3 files changed, 13 insertions(+), 13 deletions(-) (limited to 'subx/015immediate_addressing.cc') diff --git a/subx/011run.cc b/subx/011run.cc index 9c1bc4b0..d949f87e 100644 --- a/subx/011run.cc +++ b/subx/011run.cc @@ -35,7 +35,7 @@ put_new(Help, "syntax", cerr << " syntax\n"; :(code) -void test_add_imm32_to_eax() { +void test_add_imm32_to_EAX() { // At the lowest level, SubX programs are a series of hex bytes, each // (variable-length) instruction on one line. run( diff --git a/subx/013direct_addressing.cc b/subx/013direct_addressing.cc index d4dcd92a..a2331213 100644 --- a/subx/013direct_addressing.cc +++ b/subx/013direct_addressing.cc @@ -249,7 +249,7 @@ void test_subtract_r32_from_r32_signed_and_unsigned_overflow() { put_new(Name, "f7", "negate/multiply/divide rm32 (with EAX and EDX if necessary) depending on subop (neg/mul/idiv)"); :(code) -void test_multiply_eax_by_r32() { +void test_multiply_EAX_by_r32() { Reg[EAX].i = 4; Reg[ECX].i = 3; run( @@ -388,7 +388,7 @@ void test_negate_can_overflow() { //:: divide with remainder -void test_divide_eax_by_rm32() { +void test_divide_EAX_by_rm32() { Reg[EAX].u = 7; Reg[EDX].u = 0; Reg[ECX].i = 3; @@ -422,7 +422,7 @@ case 7: { // divide EDX:EAX by r/m32, storing quotient in EAX and remainder in } :(code) -void test_divide_eax_by_negative_rm32() { +void test_divide_EAX_by_negative_rm32() { Reg[EAX].u = 7; Reg[EDX].u = 0; Reg[ECX].i = -3; @@ -441,7 +441,7 @@ void test_divide_eax_by_negative_rm32() { ); } -void test_divide_negative_eax_by_rm32() { +void test_divide_negative_EAX_by_rm32() { Reg[EAX].i = -7; Reg[EDX].i = -1; // sign extend Reg[ECX].i = 3; @@ -460,7 +460,7 @@ void test_divide_negative_eax_by_rm32() { ); } -void test_divide_negative_edx_eax_by_rm32() { +void test_divide_negative_EDX_EAX_by_rm32() { Reg[EAX].i = 0; // lower 32 bits are clear Reg[EDX].i = -7; Reg[ECX].i = 0x40000000; // 2^30 (largest positive power of 2) diff --git a/subx/015immediate_addressing.cc b/subx/015immediate_addressing.cc index 959482cb..6682bc6d 100644 --- a/subx/015immediate_addressing.cc +++ b/subx/015immediate_addressing.cc @@ -211,7 +211,7 @@ void test_add_imm32_to_mem_at_r32() { put_new(Name, "2d", "subtract imm32 from EAX (sub)"); :(code) -void test_subtract_imm32_from_eax() { +void test_subtract_imm32_from_EAX() { Reg[EAX].i = 0x0d0c0baa; run( "== 0x1\n" // code segment @@ -612,7 +612,7 @@ void test_shift_right_logical_negative_r32_with_imm8() { put_new(Name, "25", "EAX = bitwise AND of imm32 with EAX (and)"); :(code) -void test_and_imm32_with_eax() { +void test_and_imm32_with_EAX() { Reg[EAX].i = 0xff; run( "== 0x1\n" // code segment @@ -704,7 +704,7 @@ void test_and_imm32_with_r32() { put_new(Name, "0d", "EAX = bitwise OR of imm32 with EAX (or)"); :(code) -void test_or_imm32_with_eax() { +void test_or_imm32_with_EAX() { Reg[EAX].i = 0xd0c0b0a0; run( "== 0x1\n" // code segment @@ -794,7 +794,7 @@ void test_or_imm32_with_r32() { put_new(Name, "35", "EAX = bitwise XOR of imm32 with EAX (xor)"); :(code) -void test_xor_imm32_with_eax() { +void test_xor_imm32_with_EAX() { Reg[EAX].i = 0xddccb0a0; run( "== 0x1\n" // code segment @@ -884,7 +884,7 @@ void test_xor_imm32_with_r32() { put_new(Name, "3d", "compare: set SF if EAX < imm32 (cmp)"); :(code) -void test_compare_imm32_with_eax_greater() { +void test_compare_imm32_with_EAX_greater() { Reg[EAX].i = 0x0d0c0b0a; run( "== 0x1\n" // code segment @@ -917,7 +917,7 @@ case 0x3d: { // compare EAX with imm32 } :(code) -void test_compare_eax_with_imm32_lesser() { +void test_compare_EAX_with_imm32_lesser() { Reg[EAX].i = 0x0d0c0b07; run( "== 0x1\n" // code segment @@ -930,7 +930,7 @@ void test_compare_eax_with_imm32_lesser() { ); } -void test_compare_imm32_with_eax_equal() { +void test_compare_imm32_with_EAX_equal() { Reg[EAX].i = 0x0d0c0b0a; run( "== 0x1\n" // code segment -- cgit 1.4.1-2-gfad0 From 5747b18422deb95aa10be5e0c32b9d60d11db980 Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Mon, 13 May 2019 17:09:33 -0700 Subject: . --- subx/015immediate_addressing.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'subx/015immediate_addressing.cc') diff --git a/subx/015immediate_addressing.cc b/subx/015immediate_addressing.cc index 6682bc6d..6e70ce71 100644 --- a/subx/015immediate_addressing.cc +++ b/subx/015immediate_addressing.cc @@ -612,7 +612,7 @@ void test_shift_right_logical_negative_r32_with_imm8() { put_new(Name, "25", "EAX = bitwise AND of imm32 with EAX (and)"); :(code) -void test_and_imm32_with_EAX() { +void test_and_EAX_with_imm32() { Reg[EAX].i = 0xff; run( "== 0x1\n" // code segment @@ -704,7 +704,7 @@ void test_and_imm32_with_r32() { put_new(Name, "0d", "EAX = bitwise OR of imm32 with EAX (or)"); :(code) -void test_or_imm32_with_EAX() { +void test_or_EAX_with_imm32() { Reg[EAX].i = 0xd0c0b0a0; run( "== 0x1\n" // code segment @@ -794,7 +794,7 @@ void test_or_imm32_with_r32() { put_new(Name, "35", "EAX = bitwise XOR of imm32 with EAX (xor)"); :(code) -void test_xor_imm32_with_EAX() { +void test_xor_EAX_with_imm32() { Reg[EAX].i = 0xddccb0a0; run( "== 0x1\n" // code segment @@ -884,7 +884,7 @@ void test_xor_imm32_with_r32() { put_new(Name, "3d", "compare: set SF if EAX < imm32 (cmp)"); :(code) -void test_compare_imm32_with_EAX_greater() { +void test_compare_EAX_with_imm32_greater() { Reg[EAX].i = 0x0d0c0b0a; run( "== 0x1\n" // code segment @@ -930,7 +930,7 @@ void test_compare_EAX_with_imm32_lesser() { ); } -void test_compare_imm32_with_EAX_equal() { +void test_compare_EAX_with_imm32_equal() { Reg[EAX].i = 0x0d0c0b0a; run( "== 0x1\n" // code segment -- cgit 1.4.1-2-gfad0 From 2b9925c70835b102d26f27f2a32044552d0b6426 Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Mon, 13 May 2019 17:14:11 -0700 Subject: flag tests for opcode 3d --- subx/015immediate_addressing.cc | 51 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 4 deletions(-) (limited to 'subx/015immediate_addressing.cc') diff --git a/subx/015immediate_addressing.cc b/subx/015immediate_addressing.cc index 6e70ce71..6bf394df 100644 --- a/subx/015immediate_addressing.cc +++ b/subx/015immediate_addressing.cc @@ -917,19 +917,62 @@ case 0x3d: { // compare EAX with imm32 } :(code) -void test_compare_EAX_with_imm32_lesser() { - Reg[EAX].i = 0x0d0c0b07; +void test_compare_EAX_with_imm32_lesser_unsigned_and_signed() { + Reg[EAX].i = 0x0a0b0c07; run( "== 0x1\n" // code segment // op ModR/M SIB displacement immediate - " 3d 0a 0b 0c 0d \n" // compare EAX with 0x0d0c0b0a + " 3d 0d 0c 0b 0a \n" // compare EAX with imm32 + // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) ); CHECK_TRACE_CONTENTS( - "run: compare EAX with imm32 0x0d0c0b0a\n" + "run: compare EAX with imm32 0x0a0b0c0d\n" "run: SF=1; ZF=0; CF=1; OF=0\n" ); } +void test_compare_EAX_with_imm32_lesser_unsigned_and_signed_due_to_overflow() { + Reg[EAX].i = 0x7fffffff; // largest positive signed integer + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " 3d 00 00 00 80\n" // compare EAX with smallest negative signed integer + // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) + ); + CHECK_TRACE_CONTENTS( + "run: compare EAX with imm32 0x80000000\n" + "run: SF=1; ZF=0; CF=1; OF=1\n" + ); +} + +void test_compare_EAX_with_imm32_lesser_signed() { + Reg[EAX].i = 0xffffffff; // -1 + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " 3d 01 00 00 00\n" // compare EAX with 1 + // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) + ); + CHECK_TRACE_CONTENTS( + "run: compare EAX with imm32 0x00000001\n" + "run: SF=1; ZF=0; CF=0; OF=0\n" + ); +} + +void test_compare_EAX_with_imm32_lesser_unsigned() { + Reg[EAX].i = 0x00000001; // 1 + run( + "== 0x1\n" // code segment + // op ModR/M SIB displacement immediate + " 3d ff ff ff ff\n" // compare EAX with -1 + // ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) + ); + CHECK_TRACE_CONTENTS( + "run: compare EAX with imm32 0xffffffff\n" + "run: SF=0; ZF=0; CF=1; OF=0\n" + ); +} + void test_compare_EAX_with_imm32_equal() { Reg[EAX].i = 0x0d0c0b0a; run( -- cgit 1.4.1-2-gfad0 From 6f6d458fcd619810d657fe3e1b82b4d1970dc2df Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Mon, 13 May 2019 17:27:45 -0700 Subject: start using the new carry flag Skimping on tests; the code changes seem pretty trivial. Will this fix CI?! --- subx/012elf.cc | 23 ++++++++--------- subx/013direct_addressing.cc | 14 +++++------ subx/014indirect_addressing.cc | 23 ++++++++--------- subx/015immediate_addressing.cc | 6 ++--- subx/017jump_disp8.cc | 54 +++++++++++++++++++++++++++++++++------- subx/019functions.cc | 22 ++++++++-------- subx/031check_operands.cc | 4 +++ subx/040---tests.cc | 4 +-- subx/057write.subx | 2 +- subx/060read.subx | 2 +- subx/062write-stream.subx | 2 +- subx/apps/assort | Bin 21809 -> 21809 bytes subx/apps/crenshaw2-1 | Bin 18968 -> 18968 bytes subx/apps/crenshaw2-1b | Bin 19527 -> 19527 bytes subx/apps/factorial | Bin 17884 -> 17884 bytes subx/apps/handle | Bin 18711 -> 18711 bytes subx/apps/hex | Bin 21977 -> 21977 bytes subx/apps/pack | Bin 36569 -> 36569 bytes 18 files changed, 96 insertions(+), 60 deletions(-) (limited to 'subx/015immediate_addressing.cc') diff --git a/subx/012elf.cc b/subx/012elf.cc index 0fa9d793..0ae0b108 100644 --- a/subx/012elf.cc +++ b/subx/012elf.cc @@ -141,20 +141,17 @@ void load_segment_from_program_header(uint8_t* elf_contents, int segment_index, // code: 0x09000000 -> 0x09ffffff (specified in ELF binary) // data: 0x0a000000 -> 0x0affffff (specified in ELF binary) // --- heap gets mmap'd somewhere here --- -// stack: 0x7dffffff -> 0x7d000000 (downward; not in ELF binary) -// argv hack: 0x7f000000 -> 0x7fffffff (not in ELF binary) +// stack: 0xbdffffff -> 0xbd000000 (downward; not in ELF binary) +// argv hack: 0xbf000000 -> 0xbfffffff (not in ELF binary) // -// For now we avoid addresses with the most significant bit set; SubX doesn't -// support unsigned comparison yet (https://github.com/akkartik/mu/issues/30) -// Once we do, we can go up to 0xc0000000; higher addresses are reserved for -// the Linux kernel. -const int CODE_SEGMENT = 0x09000000; -const int DATA_SEGMENT = 0x0a000000; -const int START_HEAP = 0x0b000000; -const int END_HEAP = 0x7d000000; -const int STACK_SEGMENT = 0x7d000000; -const int AFTER_STACK = 0x7e000000; -const int ARGV_DATA_SEGMENT = 0x7f000000; +// Addresses above 0xc0000000 are reserved for the Linux kernel. +const uint32_t CODE_SEGMENT = 0x09000000; +const uint32_t DATA_SEGMENT = 0x0a000000; +const uint32_t START_HEAP = 0x0b000000; +const uint32_t END_HEAP = 0xbd000000; +const uint32_t STACK_SEGMENT = 0xbd000000; +const uint32_t AFTER_STACK = 0xbe000000; +const uint32_t ARGV_DATA_SEGMENT = 0xbf000000; // When updating the above memory map, don't forget to update `mmap`'s // implementation in the 'syscalls' layer. :(before "End Dump Info for Instruction") diff --git a/subx/013direct_addressing.cc b/subx/013direct_addressing.cc index a2331213..2914e0dd 100644 --- a/subx/013direct_addressing.cc +++ b/subx/013direct_addressing.cc @@ -1183,8 +1183,8 @@ put_new(Name, "57", "push EDI to stack (push)"); :(code) void test_push_r32() { - Mem.push_back(vma(0x7d000000)); // manually allocate memory - Reg[ESP].u = 0x7d000008; + Mem.push_back(vma(0xbd000000)); // manually allocate memory + Reg[ESP].u = 0xbd000008; Reg[EBX].i = 0x0000000a; run( "== 0x1\n" // code segment @@ -1193,7 +1193,7 @@ void test_push_r32() { ); CHECK_TRACE_CONTENTS( "run: push EBX\n" - "run: decrementing ESP to 0x7d000004\n" + "run: decrementing ESP to 0xbd000004\n" "run: pushing value 0x0000000a\n" ); } @@ -1228,9 +1228,9 @@ put_new(Name, "5f", "pop top of stack to EDI (pop)"); :(code) void test_pop_r32() { - Mem.push_back(vma(0x7d000000)); // manually allocate memory - Reg[ESP].u = 0x7d000008; - write_mem_i32(0x7d000008, 0x0000000a); // ..before this write + Mem.push_back(vma(0xbd000000)); // manually allocate memory + Reg[ESP].u = 0xbd000008; + write_mem_i32(0xbd000008, 0x0000000a); // ..before this write run( "== 0x1\n" // code segment // op ModR/M SIB displacement immediate @@ -1241,7 +1241,7 @@ void test_pop_r32() { CHECK_TRACE_CONTENTS( "run: pop into EBX\n" "run: popping value 0x0000000a\n" - "run: incrementing ESP to 0x7d00000c\n" + "run: incrementing ESP to 0xbd00000c\n" ); } diff --git a/subx/014indirect_addressing.cc b/subx/014indirect_addressing.cc index e89a9986..a281921f 100644 --- a/subx/014indirect_addressing.cc +++ b/subx/014indirect_addressing.cc @@ -561,7 +561,6 @@ case 0x3b: { // set SF if r32 < r/m32 const uint8_t modrm = next(); const uint8_t reg1 = (modrm>>3)&0x7; trace(Callstack_depth+1, "run") << "compare " << rname(reg1) << " with r/m32" << end(); - const int32_t signed_arg1 = Reg[reg1].i; const int32_t* signed_arg2 = effective_address(modrm); const int32_t signed_difference = Reg[reg1].i - *signed_arg2; SF = (signed_difference < 0); @@ -732,8 +731,8 @@ void test_jump_mem_at_r32() { // 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" + " b8 00 00 00 01\n" + " b8 00 00 00 02\n" "== 0x2000\n" // data segment "08 00 00 00\n" // 0x00000008 ); @@ -742,9 +741,9 @@ void test_jump_mem_at_r32() { "run: jump to r/m32\n" "run: effective address is 0x00002000 (EAX)\n" "run: jumping to 0x00000008\n" - "run: 0x00000008 opcode: 05\n" + "run: 0x00000008 opcode: b8\n" ); - CHECK_TRACE_DOESNT_CONTAIN("run: 0x00000003 opcode: 05"); + CHECK_TRACE_DOESNT_CONTAIN("run: 0x00000003 opcode: b8"); } :(before "End Op ff Subops") @@ -761,8 +760,8 @@ case 4: { // jump to r/m32 :(code) void test_push_mem_at_r32() { Reg[EAX].i = 0x2000; - Mem.push_back(vma(0x7d000000)); // manually allocate memory - Reg[ESP].u = 0x7d000014; + Mem.push_back(vma(0xbd000000)); // manually allocate memory + Reg[ESP].u = 0xbd000014; run( "== 0x1\n" // code segment // op ModR/M SIB displacement immediate @@ -773,7 +772,7 @@ void test_push_mem_at_r32() { CHECK_TRACE_CONTENTS( "run: push r/m32\n" "run: effective address is 0x00002000 (EAX)\n" - "run: decrementing ESP to 0x7d000010\n" + "run: decrementing ESP to 0xbd000010\n" "run: pushing value 0x000000af\n" ); } @@ -794,9 +793,9 @@ put_new(Name, "8f", "pop top of stack to rm32 (pop)"); :(code) void test_pop_mem_at_r32() { Reg[EAX].i = 0x60; - Mem.push_back(vma(0x7d000000)); // manually allocate memory - Reg[ESP].u = 0x7d000000; - write_mem_i32(0x7d000000, 0x00000030); + Mem.push_back(vma(0xbd000000)); // manually allocate memory + Reg[ESP].u = 0xbd000000; + write_mem_i32(0xbd000000, 0x00000030); run( "== 0x1\n" // code segment // op ModR/M SIB displacement immediate @@ -807,7 +806,7 @@ void test_pop_mem_at_r32() { "run: pop into r/m32\n" "run: effective address is 0x00000060 (EAX)\n" "run: popping value 0x00000030\n" - "run: incrementing ESP to 0x7d000004\n" + "run: incrementing ESP to 0xbd000004\n" ); } diff --git a/subx/015immediate_addressing.cc b/subx/015immediate_addressing.cc index 6bf394df..4210c024 100644 --- a/subx/015immediate_addressing.cc +++ b/subx/015immediate_addressing.cc @@ -1191,8 +1191,8 @@ put_new(Name, "68", "push imm32 to stack (push)"); :(code) void test_push_imm32() { - Mem.push_back(vma(0x7d000000)); // manually allocate memory - Reg[ESP].u = 0x7d000014; + Mem.push_back(vma(0xbd000000)); // manually allocate memory + Reg[ESP].u = 0xbd000014; run( "== 0x1\n" // code segment // op ModR/M SIB displacement immediate @@ -1200,7 +1200,7 @@ void test_push_imm32() { ); CHECK_TRACE_CONTENTS( "run: push imm32 0x000000af\n" - "run: ESP is now 0x7d000010\n" + "run: ESP is now 0xbd000010\n" "run: contents at ESP: 0x000000af\n" ); } diff --git a/subx/017jump_disp8.cc b/subx/017jump_disp8.cc index 22ae6567..35cc1331 100644 --- a/subx/017jump_disp8.cc +++ b/subx/017jump_disp8.cc @@ -135,7 +135,8 @@ void test_jne_rel8_fail() { //:: jump if greater :(before "End Initialize Op Names") -put_new(Name, "7f", "jump disp8 bytes away if greater, if ZF is unset and SF == OF (jcc/jg/jnle)"); +put_new(Name, "7f", "jump disp8 bytes away if greater (signed), if ZF is unset and SF == OF (jcc/jg/jnle)"); +put_new(Name, "77", "jump disp8 bytes away if greater (unsigned), if ZF is unset and CF is unset (jcc/ja/jnbe)"); :(code) void test_jg_rel8_success() { @@ -158,9 +159,17 @@ void test_jg_rel8_success() { } :(before "End Single-Byte Opcodes") -case 0x7f: { // jump rel8 if !SF and !ZF +case 0x7f: { // jump rel8 if SF == OF and !ZF const int8_t offset = static_cast(next()); - if (!ZF && SF == OF) { + if (SF == OF && !ZF) { + trace(Callstack_depth+1, "run") << "jump " << NUM(offset) << end(); + EIP += offset; + } + break; +} +case 0x77: { // jump rel8 if !CF and !ZF + const int8_t offset = static_cast(next()); + if (!CF && !ZF) { trace(Callstack_depth+1, "run") << "jump " << NUM(offset) << end(); EIP += offset; } @@ -190,7 +199,8 @@ void test_jg_rel8_fail() { //:: jump if greater or equal :(before "End Initialize Op Names") -put_new(Name, "7d", "jump disp8 bytes away if greater or equal, if SF == OF (jcc/jge/jnl)"); +put_new(Name, "7d", "jump disp8 bytes away if greater or equal (signed), if SF == OF (jcc/jge/jnl)"); +put_new(Name, "73", "jump disp8 bytes away if greater or equal (unsigned), if CF is unset (jcc/jae/jnb)"); :(code) void test_jge_rel8_success() { @@ -212,7 +222,7 @@ void test_jge_rel8_success() { } :(before "End Single-Byte Opcodes") -case 0x7d: { // jump rel8 if !SF +case 0x7d: { // jump rel8 if SF == OF const int8_t offset = static_cast(next()); if (SF == OF) { trace(Callstack_depth+1, "run") << "jump " << NUM(offset) << end(); @@ -220,6 +230,14 @@ case 0x7d: { // jump rel8 if !SF } break; } +case 0x73: { // jump rel8 if !CF + const int8_t offset = static_cast(next()); + if (!CF) { + trace(Callstack_depth+1, "run") << "jump " << NUM(offset) << end(); + EIP += offset; + } + break; +} :(code) void test_jge_rel8_fail() { @@ -243,7 +261,8 @@ void test_jge_rel8_fail() { //:: jump if lesser :(before "End Initialize Op Names") -put_new(Name, "7c", "jump disp8 bytes away if lesser, if SF != OF (jcc/jl/jnge)"); +put_new(Name, "7c", "jump disp8 bytes away if lesser (signed), if SF != OF (jcc/jl/jnge)"); +put_new(Name, "72", "jump disp8 bytes away if lesser (unsigned), if CF is set (jcc/jb/jnae)"); :(code) void test_jl_rel8_success() { @@ -266,7 +285,7 @@ void test_jl_rel8_success() { } :(before "End Single-Byte Opcodes") -case 0x7c: { // jump rel8 if SF and !ZF +case 0x7c: { // jump rel8 if SF != OF const int8_t offset = static_cast(next()); if (SF != OF) { trace(Callstack_depth+1, "run") << "jump " << NUM(offset) << end(); @@ -274,6 +293,14 @@ case 0x7c: { // jump rel8 if SF and !ZF } break; } +case 0x72: { // jump rel8 if CF + const int8_t offset = static_cast(next()); + if (CF) { + trace(Callstack_depth+1, "run") << "jump " << NUM(offset) << end(); + EIP += offset; + } + break; +} :(code) void test_jl_rel8_fail() { @@ -298,7 +325,8 @@ void test_jl_rel8_fail() { //:: jump if lesser or equal :(before "End Initialize Op Names") -put_new(Name, "7e", "jump disp8 bytes away if lesser or equal, if ZF is set or SF != OF (jcc/jle/jng)"); +put_new(Name, "7e", "jump disp8 bytes away if lesser or equal (signed), if ZF is set or SF != OF (jcc/jle/jng)"); +put_new(Name, "76", "jump disp8 bytes away if lesser or equal (unsigned), if ZF is set or CF is set (jcc/jbe/jna)"); :(code) void test_jle_rel8_equal() { @@ -341,7 +369,7 @@ void test_jle_rel8_lesser() { } :(before "End Single-Byte Opcodes") -case 0x7e: { // jump rel8 if SF or ZF +case 0x7e: { // jump rel8 if ZF or SF != OF const int8_t offset = static_cast(next()); if (ZF || SF != OF) { trace(Callstack_depth+1, "run") << "jump " << NUM(offset) << end(); @@ -349,6 +377,14 @@ case 0x7e: { // jump rel8 if SF or ZF } break; } +case 0x76: { // jump rel8 if ZF or CF + const int8_t offset = static_cast(next()); + if (ZF || CF) { + trace(Callstack_depth+1, "run") << "jump " << NUM(offset) << end(); + EIP += offset; + } + break; +} :(code) void test_jle_rel8_greater() { diff --git a/subx/019functions.cc b/subx/019functions.cc index 27fb4fb0..00da8397 100644 --- a/subx/019functions.cc +++ b/subx/019functions.cc @@ -5,8 +5,8 @@ put_new(Name, "e8", "call disp32 (call)"); :(code) void test_call_disp32() { - Mem.push_back(vma(0x7d000000)); // manually allocate memory - Reg[ESP].u = 0x7d000064; + Mem.push_back(vma(0xbd000000)); // manually allocate memory + Reg[ESP].u = 0xbd000064; run( "== 0x1\n" // code segment // op ModR/M SIB displacement immediate @@ -15,7 +15,7 @@ void test_call_disp32() { ); CHECK_TRACE_CONTENTS( "run: call imm32 0x000000a0\n" - "run: decrementing ESP to 0x7d000060\n" + "run: decrementing ESP to 0xbd000060\n" "run: pushing value 0x00000006\n" "run: jumping to 0x000000a6\n" ); @@ -37,8 +37,8 @@ case 0xe8: { // call disp32 relative to next EIP :(code) void test_call_r32() { - Mem.push_back(vma(0x7d000000)); // manually allocate memory - Reg[ESP].u = 0x7d000064; + Mem.push_back(vma(0xbd000000)); // manually allocate memory + Reg[ESP].u = 0xbd000064; Reg[EBX].u = 0x000000a0; run( "== 0x1\n" // code segment @@ -49,7 +49,7 @@ void test_call_r32() { CHECK_TRACE_CONTENTS( "run: call to r/m32\n" "run: r/m32 is EBX\n" - "run: decrementing ESP to 0x7d000060\n" + "run: decrementing ESP to 0xbd000060\n" "run: pushing value 0x00000003\n" "run: jumping to 0x000000a3\n" ); @@ -68,8 +68,8 @@ case 2: { // call function pointer at r/m32 :(code) void test_call_mem_at_r32() { - Mem.push_back(vma(0x7d000000)); // manually allocate memory - Reg[ESP].u = 0x7d000064; + Mem.push_back(vma(0xbd000000)); // manually allocate memory + Reg[ESP].u = 0xbd000064; Reg[EBX].u = 0x2000; run( "== 0x1\n" // code segment @@ -82,7 +82,7 @@ void test_call_mem_at_r32() { CHECK_TRACE_CONTENTS( "run: call to r/m32\n" "run: effective address is 0x00002000 (EBX)\n" - "run: decrementing ESP to 0x7d000060\n" + "run: decrementing ESP to 0xbd000060\n" "run: pushing value 0x00000003\n" "run: jumping to 0x000000a3\n" ); @@ -95,8 +95,8 @@ put_new(Name, "c3", "return from most recent unfinished call (ret)"); :(code) void test_ret() { - Mem.push_back(vma(0x7d000000)); // manually allocate memory - Reg[ESP].u = 0x7d000064; + Mem.push_back(vma(0xbd000000)); // manually allocate memory + Reg[ESP].u = 0xbd000064; write_mem_u32(Reg[ESP].u, 0x10); run( "== 0x1\n" // code segment diff --git a/subx/031check_operands.cc b/subx/031check_operands.cc index 9590979f..aad84da6 100644 --- a/subx/031check_operands.cc +++ b/subx/031check_operands.cc @@ -152,8 +152,12 @@ void init_permitted_operands() { // jump put(Permitted_operands, "eb", 0x04); + put(Permitted_operands, "72", 0x04); + put(Permitted_operands, "73", 0x04); put(Permitted_operands, "74", 0x04); put(Permitted_operands, "75", 0x04); + put(Permitted_operands, "76", 0x04); + put(Permitted_operands, "77", 0x04); put(Permitted_operands, "7c", 0x04); put(Permitted_operands, "7d", 0x04); put(Permitted_operands, "7e", 0x04); diff --git a/subx/040---tests.cc b/subx/040---tests.cc index 237bb811..e5949bbd 100644 --- a/subx/040---tests.cc +++ b/subx/040---tests.cc @@ -16,8 +16,8 @@ Transform.push_back(create_test_function); :(code) void test_run_test() { - Mem.push_back(vma(0x7d000000)); // manually allocate memory - Reg[ESP].u = 0x7d000100; + Mem.push_back(vma(0xbd000000)); // manually allocate memory + Reg[ESP].u = 0xbd000100; run( "== 0x1\n" // code segment "main:\n" diff --git a/subx/057write.subx b/subx/057write.subx index 3135003b..455146ac 100644 --- a/subx/057write.subx +++ b/subx/057write.subx @@ -27,7 +27,7 @@ write: # f : fd or (address stream), s : (address array byte) -> 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP # if (f < 0x08000000) _write(f, s) and return # f can't be a user-mode address, so treat it as a kernel file descriptor 81 7/subop/compare 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 0x08000000/imm32 # compare *(EBP+8) - 7d/jump-if-greater-or-equal $write:fake/disp8 + 73/jump-if-greater-unsigned-or-equal $write:fake/disp8 # . . push args ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) diff --git a/subx/060read.subx b/subx/060read.subx index cedafbf5..d377a1ad 100644 --- a/subx/060read.subx +++ b/subx/060read.subx @@ -51,7 +51,7 @@ read: # f : fd or (address stream), s : (address stream) -> num-bytes-read/EAX 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP # if (f < 0x08000000) return _read(f, s) # f can't be a user-mode address, so treat it as a kernel file descriptor 81 7/subop/compare 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 0x08000000/imm32 # compare *(EBP+8) - 7d/jump-if-greater-or-equal $read:fake/disp8 + 73/jump-if-greater-unsigned-or-equal $read:fake/disp8 # . . push args ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) diff --git a/subx/062write-stream.subx b/subx/062write-stream.subx index 83268422..92c67dc2 100644 --- a/subx/062write-stream.subx +++ b/subx/062write-stream.subx @@ -21,7 +21,7 @@ write-stream: # f : fd or (address stream), s : (address stream) -> 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP # if (f < 0x08000000) _write-stream(f, s), return # f can't be a user-mode address, so treat it as a kernel file descriptor 81 7/subop/compare 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 0x08000000/imm32 # compare *(EBP+8) - 7d/jump-if-greater-or-equal $write-stream:fake/disp8 + 73/jump-if-greater-unsigned-or-equal $write-stream:fake/disp8 # . . push args ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) diff --git a/subx/apps/assort b/subx/apps/assort index 3fbc3b7e..d2aaaf1a 100755 Binary files a/subx/apps/assort and b/subx/apps/assort differ diff --git a/subx/apps/crenshaw2-1 b/subx/apps/crenshaw2-1 index ca1e52fa..3fbc9c33 100755 Binary files a/subx/apps/crenshaw2-1 and b/subx/apps/crenshaw2-1 differ diff --git a/subx/apps/crenshaw2-1b b/subx/apps/crenshaw2-1b index 8a468ff5..71265ffe 100755 Binary files a/subx/apps/crenshaw2-1b and b/subx/apps/crenshaw2-1b differ diff --git a/subx/apps/factorial b/subx/apps/factorial index 9ea9716b..4f5f7dc2 100755 Binary files a/subx/apps/factorial and b/subx/apps/factorial differ diff --git a/subx/apps/handle b/subx/apps/handle index b32183db..520ca276 100755 Binary files a/subx/apps/handle and b/subx/apps/handle differ diff --git a/subx/apps/hex b/subx/apps/hex index ed1d9eeb..667fbc1f 100755 Binary files a/subx/apps/hex and b/subx/apps/hex differ diff --git a/subx/apps/pack b/subx/apps/pack index a4a20626..2b313f08 100755 Binary files a/subx/apps/pack and b/subx/apps/pack differ -- cgit 1.4.1-2-gfad0