From fc455c969d1d193f2bd8cb4f139b7da74b719117 Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Sun, 15 Jul 2018 15:13:31 -0700 Subject: 4347 --- subx/011direct_addressing.cc | 323 ----------------------- subx/012direct_addressing.cc | 323 +++++++++++++++++++++++ subx/012indirect_addressing.cc | 561 ---------------------------------------- subx/013immediate_addressing.cc | 425 ------------------------------ subx/013indirect_addressing.cc | 561 ++++++++++++++++++++++++++++++++++++++++ subx/014immediate_addressing.cc | 425 ++++++++++++++++++++++++++++++ subx/014index_addressing.cc | 125 --------- subx/015index_addressing.cc | 125 +++++++++ subx/015jump_relative.cc | 252 ------------------ subx/016jump_relative.cc | 238 +++++++++-------- subx/017functions.cc | 81 ------ subx/017jump_relative.cc | 258 ++++++++++++++++++ subx/018functions.cc | 81 ++++++ 13 files changed, 1889 insertions(+), 1889 deletions(-) delete mode 100644 subx/011direct_addressing.cc create mode 100644 subx/012direct_addressing.cc delete mode 100644 subx/012indirect_addressing.cc delete mode 100644 subx/013immediate_addressing.cc create mode 100644 subx/013indirect_addressing.cc create mode 100644 subx/014immediate_addressing.cc delete mode 100644 subx/014index_addressing.cc create mode 100644 subx/015index_addressing.cc delete mode 100644 subx/015jump_relative.cc delete mode 100644 subx/017functions.cc create mode 100644 subx/017jump_relative.cc create mode 100644 subx/018functions.cc (limited to 'subx') diff --git a/subx/011direct_addressing.cc b/subx/011direct_addressing.cc deleted file mode 100644 index fffcbd6a..00000000 --- a/subx/011direct_addressing.cc +++ /dev/null @@ -1,323 +0,0 @@ -//: operating directly on a register - -:(scenario add_r32_to_r32) -% Reg[EAX].i = 0x10; -% Reg[EBX].i = 1; -# op ModR/M SIB displacement immediate - 01 d8 # add EBX to EAX -# ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) -+run: add EBX to r/m32 -+run: r/m32 is EAX -+run: storing 0x00000011 - -:(before "End Single-Byte Opcodes") -case 0x01: { // add r32 to r/m32 - uint8_t modrm = next(); - uint8_t arg2 = (modrm>>3)&0x7; - trace(2, "run") << "add " << rname(arg2) << " to r/m32" << end(); - int32_t* arg1 = effective_address(modrm); - BINARY_ARITHMETIC_OP(+, *arg1, Reg[arg2].i); - break; -} - -:(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 -// 'Mem' at once. -int32_t* effective_address(uint8_t modrm) { - uint8_t mod = (modrm>>6); - // ignore middle 3 'reg opcode' bits - uint8_t rm = modrm & 0x7; - uint32_t addr = 0; - switch (mod) { - case 3: - // mod 3 is just register direct addressing - trace(2, "run") << "r/m32 is " << rname(rm) << end(); - return &Reg[rm].i; - // End Mod Special-cases(addr) - default: - cerr << "unrecognized mod bits: " << NUM(mod) << '\n'; - exit(1); - } - //: other mods are indirect, and they'll set addr appropriately - return mem_addr_i32(addr); -} - -//:: subtract - -:(scenario subtract_r32_from_r32) -% Reg[EAX].i = 10; -% Reg[EBX].i = 1; -# op ModR/M SIB displacement immediate - 29 d8 # subtract EBX from EAX -# ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) -+run: subtract EBX from r/m32 -+run: r/m32 is EAX -+run: storing 0x00000009 - -:(before "End Single-Byte Opcodes") -case 0x29: { // subtract r32 from r/m32 - uint8_t modrm = next(); - uint8_t arg2 = (modrm>>3)&0x7; - trace(2, "run") << "subtract " << rname(arg2) << " from r/m32" << end(); - int32_t* arg1 = effective_address(modrm); - BINARY_ARITHMETIC_OP(-, *arg1, Reg[arg2].i); - break; -} - -//:: and - -:(scenario and_r32_with_r32) -% Reg[EAX].i = 0x0a0b0c0d; -% Reg[EBX].i = 0x000000ff; -# op ModR/M SIB displacement immediate - 21 d8 # and EBX with destination EAX -# ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) -+run: and EBX with r/m32 -+run: r/m32 is EAX -+run: storing 0x0000000d - -:(before "End Single-Byte Opcodes") -case 0x21: { // and r32 with r/m32 - uint8_t modrm = next(); - uint8_t arg2 = (modrm>>3)&0x7; - trace(2, "run") << "and " << rname(arg2) << " with r/m32" << end(); - int32_t* arg1 = effective_address(modrm); - BINARY_BITWISE_OP(&, *arg1, Reg[arg2].u); - break; -} - -//:: or - -:(scenario or_r32_with_r32) -% Reg[EAX].i = 0x0a0b0c0d; -% Reg[EBX].i = 0xa0b0c0d0; -# op ModR/M SIB displacement immediate - 09 d8 # or EBX with destination EAX -# ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) -+run: or EBX with r/m32 -+run: r/m32 is EAX -+run: storing 0xaabbccdd - -:(before "End Single-Byte Opcodes") -case 0x09: { // or r32 with r/m32 - uint8_t modrm = next(); - uint8_t arg2 = (modrm>>3)&0x7; - trace(2, "run") << "or " << rname(arg2) << " with r/m32" << end(); - int32_t* arg1 = effective_address(modrm); - BINARY_BITWISE_OP(|, *arg1, Reg[arg2].u); - break; -} - -//:: xor - -:(scenario xor_r32_with_r32) -% Reg[EAX].i = 0x0a0b0c0d; -% Reg[EBX].i = 0xaabbc0d0; -# op ModR/M SIB displacement immediate - 31 d8 # xor EBX with destination EAX -# ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) -+run: xor EBX with r/m32 -+run: r/m32 is EAX -+run: storing 0xa0b0ccdd - -:(before "End Single-Byte Opcodes") -case 0x31: { // xor r32 with r/m32 - uint8_t modrm = next(); - uint8_t arg2 = (modrm>>3)&0x7; - trace(2, "run") << "xor " << rname(arg2) << " with r/m32" << end(); - int32_t* arg1 = effective_address(modrm); - BINARY_BITWISE_OP(^, *arg1, Reg[arg2].u); - break; -} - -//:: not - -:(scenario not_r32) -% Reg[EBX].i = 0x0f0f00ff; -# op ModR/M SIB displacement immediate - f7 c3 # not EBX -# ModR/M in binary: 11 (direct mode) 000 (unused) 011 (dest EBX) -+run: 'not' of r/m32 -+run: r/m32 is EBX -+run: storing 0xf0f0ff00 - -:(before "End Single-Byte Opcodes") -case 0xf7: { // xor r32 with r/m32 - uint8_t modrm = next(); - trace(2, "run") << "'not' of r/m32" << end(); - int32_t* arg1 = effective_address(modrm); - *arg1 = ~(*arg1); - trace(2, "run") << "storing 0x" << HEXWORD << *arg1 << end(); - SF = (*arg1 >> 31); - ZF = (*arg1 == 0); - OF = false; - break; -} - -//:: compare (cmp) - -:(scenario compare_r32_with_r32_greater) -% Reg[EAX].i = 0x0a0b0c0d; -% Reg[EBX].i = 0x0a0b0c07; -# op ModR/M SIB displacement immediate - 39 d8 # compare EBX with EAX -# ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) -+run: compare EBX with r/m32 -+run: r/m32 is EAX -+run: SF=0; ZF=0; OF=0 - -:(before "End Single-Byte Opcodes") -case 0x39: { // set SF if r/m32 < r32 - uint8_t modrm = next(); - uint8_t reg2 = (modrm>>3)&0x7; - trace(2, "run") << "compare " << rname(reg2) << " with r/m32" << end(); - int32_t* arg1 = effective_address(modrm); - int32_t arg2 = Reg[reg2].i; - int32_t tmp1 = *arg1 - arg2; - SF = (tmp1 < 0); - ZF = (tmp1 == 0); - int64_t tmp2 = *arg1 - arg2; - OF = (tmp1 != tmp2); - trace(2, "run") << "SF=" << SF << "; ZF=" << ZF << "; OF=" << OF << end(); - break; -} - -:(scenario compare_r32_with_r32_lesser) -% Reg[EAX].i = 0x0a0b0c07; -% Reg[EBX].i = 0x0a0b0c0d; -# op ModR/M SIB displacement immediate - 39 d8 # compare EBX with EAX -# ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) -+run: compare EBX with r/m32 -+run: r/m32 is EAX -+run: SF=1; ZF=0; OF=0 - -:(scenario compare_r32_with_r32_equal) -% Reg[EAX].i = 0x0a0b0c0d; -% Reg[EBX].i = 0x0a0b0c0d; -# op ModR/M SIB displacement immediate - 39 d8 # compare EBX with EAX -# ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) -+run: compare EBX with r/m32 -+run: r/m32 is EAX -+run: SF=0; ZF=1; OF=0 - -//:: copy (mov) - -:(scenario copy_r32_to_r32) -% Reg[EBX].i = 0xaf; -# op ModR/M SIB displacement immediate - 89 d8 # copy EBX to EAX -# ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) -+run: copy EBX to r/m32 -+run: r/m32 is EAX -+run: storing 0x000000af - -:(before "End Single-Byte Opcodes") -case 0x89: { // copy r32 to r/m32 - uint8_t modrm = next(); - uint8_t reg2 = (modrm>>3)&0x7; - trace(2, "run") << "copy " << rname(reg2) << " to r/m32" << end(); - int32_t* arg1 = effective_address(modrm); - *arg1 = Reg[reg2].i; - trace(2, "run") << "storing 0x" << HEXWORD << *arg1 << end(); - break; -} - -//:: xchg - -:(scenario xchg_r32_with_r32) -% Reg[EBX].i = 0xaf; -% Reg[EAX].i = 0x2e; -# op ModR/M SIB displacement immediate - 87 d8 # exchange EBX with EAX -# ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) -+run: exchange EBX with r/m32 -+run: r/m32 is EAX -+run: storing 0x000000af in r/m32 -+run: storing 0x0000002e in EBX - -:(before "End Single-Byte Opcodes") -case 0x87: { // exchange r32 with r/m32 - uint8_t modrm = next(); - uint8_t reg2 = (modrm>>3)&0x7; - trace(2, "run") << "exchange " << rname(reg2) << " with r/m32" << end(); - int32_t* arg1 = effective_address(modrm); - int32_t tmp = *arg1; - *arg1 = Reg[reg2].i; - Reg[reg2].i = tmp; - trace(2, "run") << "storing 0x" << HEXWORD << *arg1 << " in r/m32" << end(); - trace(2, "run") << "storing 0x" << HEXWORD << Reg[reg2].i << " in " << rname(reg2) << end(); - break; -} - -//:: push - -:(scenario push_r32) -% Reg[ESP].u = 0x64; -% Reg[EBX].i = 0x0000000a; -# op ModR/M SIB displacement immediate - 53 # push EBX to stack -+run: push EBX -+run: decrementing ESP to 0x00000060 -+run: pushing value 0x0000000a - -:(before "End Single-Byte Opcodes") -case 0x50: -case 0x51: -case 0x52: -case 0x53: -case 0x54: -case 0x55: -case 0x56: -case 0x57: { // push r32 to stack - uint8_t reg = op & 0x7; - trace(2, "run") << "push " << rname(reg) << end(); - push(Reg[reg].u); - break; -} -:(code) -void push(uint32_t val) { - Reg[ESP].u -= 4; - trace(2, "run") << "decrementing ESP to 0x" << HEXWORD << Reg[ESP].u << end(); - trace(2, "run") << "pushing value 0x" << HEXWORD << val << end(); - write_mem_u32(Reg[ESP].u, val); -} - -//:: pop - -:(scenario pop_r32) -% Reg[ESP].u = 0x60; -% write_mem_i32(0x60, 0x0000000a); -== 0x1 # code segment -# op ModR/M SIB displacement immediate - 5b # pop stack to EBX -== 0x60 # data segment -0a 00 00 00 # 0x0a -+run: pop into EBX -+run: popping value 0x0000000a -+run: incrementing ESP to 0x00000064 - -:(before "End Single-Byte Opcodes") -case 0x58: -case 0x59: -case 0x5a: -case 0x5b: -case 0x5c: -case 0x5d: -case 0x5e: -case 0x5f: { // pop stack into r32 - uint8_t reg = op & 0x7; - trace(2, "run") << "pop into " << rname(reg) << end(); - Reg[reg].u = pop(); - break; -} -:(code) -uint32_t pop() { - uint32_t result = read_mem_u32(Reg[ESP].u); - trace(2, "run") << "popping value 0x" << HEXWORD << result << end(); - Reg[ESP].u += 4; - trace(2, "run") << "incrementing ESP to 0x" << HEXWORD << Reg[ESP].u << end(); - return result; -} diff --git a/subx/012direct_addressing.cc b/subx/012direct_addressing.cc new file mode 100644 index 00000000..fffcbd6a --- /dev/null +++ b/subx/012direct_addressing.cc @@ -0,0 +1,323 @@ +//: operating directly on a register + +:(scenario add_r32_to_r32) +% Reg[EAX].i = 0x10; +% Reg[EBX].i = 1; +# op ModR/M SIB displacement immediate + 01 d8 # add EBX to EAX +# ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) ++run: add EBX to r/m32 ++run: r/m32 is EAX ++run: storing 0x00000011 + +:(before "End Single-Byte Opcodes") +case 0x01: { // add r32 to r/m32 + uint8_t modrm = next(); + uint8_t arg2 = (modrm>>3)&0x7; + trace(2, "run") << "add " << rname(arg2) << " to r/m32" << end(); + int32_t* arg1 = effective_address(modrm); + BINARY_ARITHMETIC_OP(+, *arg1, Reg[arg2].i); + break; +} + +:(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 +// 'Mem' at once. +int32_t* effective_address(uint8_t modrm) { + uint8_t mod = (modrm>>6); + // ignore middle 3 'reg opcode' bits + uint8_t rm = modrm & 0x7; + uint32_t addr = 0; + switch (mod) { + case 3: + // mod 3 is just register direct addressing + trace(2, "run") << "r/m32 is " << rname(rm) << end(); + return &Reg[rm].i; + // End Mod Special-cases(addr) + default: + cerr << "unrecognized mod bits: " << NUM(mod) << '\n'; + exit(1); + } + //: other mods are indirect, and they'll set addr appropriately + return mem_addr_i32(addr); +} + +//:: subtract + +:(scenario subtract_r32_from_r32) +% Reg[EAX].i = 10; +% Reg[EBX].i = 1; +# op ModR/M SIB displacement immediate + 29 d8 # subtract EBX from EAX +# ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) ++run: subtract EBX from r/m32 ++run: r/m32 is EAX ++run: storing 0x00000009 + +:(before "End Single-Byte Opcodes") +case 0x29: { // subtract r32 from r/m32 + uint8_t modrm = next(); + uint8_t arg2 = (modrm>>3)&0x7; + trace(2, "run") << "subtract " << rname(arg2) << " from r/m32" << end(); + int32_t* arg1 = effective_address(modrm); + BINARY_ARITHMETIC_OP(-, *arg1, Reg[arg2].i); + break; +} + +//:: and + +:(scenario and_r32_with_r32) +% Reg[EAX].i = 0x0a0b0c0d; +% Reg[EBX].i = 0x000000ff; +# op ModR/M SIB displacement immediate + 21 d8 # and EBX with destination EAX +# ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) ++run: and EBX with r/m32 ++run: r/m32 is EAX ++run: storing 0x0000000d + +:(before "End Single-Byte Opcodes") +case 0x21: { // and r32 with r/m32 + uint8_t modrm = next(); + uint8_t arg2 = (modrm>>3)&0x7; + trace(2, "run") << "and " << rname(arg2) << " with r/m32" << end(); + int32_t* arg1 = effective_address(modrm); + BINARY_BITWISE_OP(&, *arg1, Reg[arg2].u); + break; +} + +//:: or + +:(scenario or_r32_with_r32) +% Reg[EAX].i = 0x0a0b0c0d; +% Reg[EBX].i = 0xa0b0c0d0; +# op ModR/M SIB displacement immediate + 09 d8 # or EBX with destination EAX +# ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) ++run: or EBX with r/m32 ++run: r/m32 is EAX ++run: storing 0xaabbccdd + +:(before "End Single-Byte Opcodes") +case 0x09: { // or r32 with r/m32 + uint8_t modrm = next(); + uint8_t arg2 = (modrm>>3)&0x7; + trace(2, "run") << "or " << rname(arg2) << " with r/m32" << end(); + int32_t* arg1 = effective_address(modrm); + BINARY_BITWISE_OP(|, *arg1, Reg[arg2].u); + break; +} + +//:: xor + +:(scenario xor_r32_with_r32) +% Reg[EAX].i = 0x0a0b0c0d; +% Reg[EBX].i = 0xaabbc0d0; +# op ModR/M SIB displacement immediate + 31 d8 # xor EBX with destination EAX +# ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) ++run: xor EBX with r/m32 ++run: r/m32 is EAX ++run: storing 0xa0b0ccdd + +:(before "End Single-Byte Opcodes") +case 0x31: { // xor r32 with r/m32 + uint8_t modrm = next(); + uint8_t arg2 = (modrm>>3)&0x7; + trace(2, "run") << "xor " << rname(arg2) << " with r/m32" << end(); + int32_t* arg1 = effective_address(modrm); + BINARY_BITWISE_OP(^, *arg1, Reg[arg2].u); + break; +} + +//:: not + +:(scenario not_r32) +% Reg[EBX].i = 0x0f0f00ff; +# op ModR/M SIB displacement immediate + f7 c3 # not EBX +# ModR/M in binary: 11 (direct mode) 000 (unused) 011 (dest EBX) ++run: 'not' of r/m32 ++run: r/m32 is EBX ++run: storing 0xf0f0ff00 + +:(before "End Single-Byte Opcodes") +case 0xf7: { // xor r32 with r/m32 + uint8_t modrm = next(); + trace(2, "run") << "'not' of r/m32" << end(); + int32_t* arg1 = effective_address(modrm); + *arg1 = ~(*arg1); + trace(2, "run") << "storing 0x" << HEXWORD << *arg1 << end(); + SF = (*arg1 >> 31); + ZF = (*arg1 == 0); + OF = false; + break; +} + +//:: compare (cmp) + +:(scenario compare_r32_with_r32_greater) +% Reg[EAX].i = 0x0a0b0c0d; +% Reg[EBX].i = 0x0a0b0c07; +# op ModR/M SIB displacement immediate + 39 d8 # compare EBX with EAX +# ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) ++run: compare EBX with r/m32 ++run: r/m32 is EAX ++run: SF=0; ZF=0; OF=0 + +:(before "End Single-Byte Opcodes") +case 0x39: { // set SF if r/m32 < r32 + uint8_t modrm = next(); + uint8_t reg2 = (modrm>>3)&0x7; + trace(2, "run") << "compare " << rname(reg2) << " with r/m32" << end(); + int32_t* arg1 = effective_address(modrm); + int32_t arg2 = Reg[reg2].i; + int32_t tmp1 = *arg1 - arg2; + SF = (tmp1 < 0); + ZF = (tmp1 == 0); + int64_t tmp2 = *arg1 - arg2; + OF = (tmp1 != tmp2); + trace(2, "run") << "SF=" << SF << "; ZF=" << ZF << "; OF=" << OF << end(); + break; +} + +:(scenario compare_r32_with_r32_lesser) +% Reg[EAX].i = 0x0a0b0c07; +% Reg[EBX].i = 0x0a0b0c0d; +# op ModR/M SIB displacement immediate + 39 d8 # compare EBX with EAX +# ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) ++run: compare EBX with r/m32 ++run: r/m32 is EAX ++run: SF=1; ZF=0; OF=0 + +:(scenario compare_r32_with_r32_equal) +% Reg[EAX].i = 0x0a0b0c0d; +% Reg[EBX].i = 0x0a0b0c0d; +# op ModR/M SIB displacement immediate + 39 d8 # compare EBX with EAX +# ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) ++run: compare EBX with r/m32 ++run: r/m32 is EAX ++run: SF=0; ZF=1; OF=0 + +//:: copy (mov) + +:(scenario copy_r32_to_r32) +% Reg[EBX].i = 0xaf; +# op ModR/M SIB displacement immediate + 89 d8 # copy EBX to EAX +# ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) ++run: copy EBX to r/m32 ++run: r/m32 is EAX ++run: storing 0x000000af + +:(before "End Single-Byte Opcodes") +case 0x89: { // copy r32 to r/m32 + uint8_t modrm = next(); + uint8_t reg2 = (modrm>>3)&0x7; + trace(2, "run") << "copy " << rname(reg2) << " to r/m32" << end(); + int32_t* arg1 = effective_address(modrm); + *arg1 = Reg[reg2].i; + trace(2, "run") << "storing 0x" << HEXWORD << *arg1 << end(); + break; +} + +//:: xchg + +:(scenario xchg_r32_with_r32) +% Reg[EBX].i = 0xaf; +% Reg[EAX].i = 0x2e; +# op ModR/M SIB displacement immediate + 87 d8 # exchange EBX with EAX +# ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX) ++run: exchange EBX with r/m32 ++run: r/m32 is EAX ++run: storing 0x000000af in r/m32 ++run: storing 0x0000002e in EBX + +:(before "End Single-Byte Opcodes") +case 0x87: { // exchange r32 with r/m32 + uint8_t modrm = next(); + uint8_t reg2 = (modrm>>3)&0x7; + trace(2, "run") << "exchange " << rname(reg2) << " with r/m32" << end(); + int32_t* arg1 = effective_address(modrm); + int32_t tmp = *arg1; + *arg1 = Reg[reg2].i; + Reg[reg2].i = tmp; + trace(2, "run") << "storing 0x" << HEXWORD << *arg1 << " in r/m32" << end(); + trace(2, "run") << "storing 0x" << HEXWORD << Reg[reg2].i << " in " << rname(reg2) << end(); + break; +} + +//:: push + +:(scenario push_r32) +% Reg[ESP].u = 0x64; +% Reg[EBX].i = 0x0000000a; +# op ModR/M SIB displacement immediate + 53 # push EBX to stack ++run: push EBX ++run: decrementing ESP to 0x00000060 ++run: pushing value 0x0000000a + +:(before "End Single-Byte Opcodes") +case 0x50: +case 0x51: +case 0x52: +case 0x53: +case 0x54: +case 0x55: +case 0x56: +case 0x57: { // push r32 to stack + uint8_t reg = op & 0x7; + trace(2, "run") << "push " << rname(reg) << end(); + push(Reg[reg].u); + break; +} +:(code) +void push(uint32_t val) { + Reg[ESP].u -= 4; + trace(2, "run") << "decrementing ESP to 0x" << HEXWORD << Reg[ESP].u << end(); + trace(2, "run") << "pushing value 0x" << HEXWORD << val << end(); + write_mem_u32(Reg[ESP].u, val); +} + +//:: pop + +:(scenario pop_r32) +% Reg[ESP].u = 0x60; +% write_mem_i32(0x60, 0x0000000a); +== 0x1 # code segment +# op ModR/M SIB displacement immediate + 5b # pop stack to EBX +== 0x60 # data segment +0a 00 00 00 # 0x0a ++run: pop into EBX ++run: popping value 0x0000000a ++run: incrementing ESP to 0x00000064 + +:(before "End Single-Byte Opcodes") +case 0x58: +case 0x59: +case 0x5a: +case 0x5b: +case 0x5c: +case 0x5d: +case 0x5e: +case 0x5f: { // pop stack into r32 + uint8_t reg = op & 0x7; + trace(2, "run") << "pop into " << rname(reg) << end(); + Reg[reg].u = pop(); + break; +} +:(code) +uint32_t pop() { + uint32_t result = read_mem_u32(Reg[ESP].u); + trace(2, "run") << "popping value 0x" << HEXWORD << result << end(); + Reg[ESP].u += 4; + trace(2, "run") << "incrementing ESP to 0x" << HEXWORD << Reg[ESP].u << end(); + return result; +} diff --git a/subx/012indirect_addressing.cc b/subx/012indirect_addressing.cc deleted file mode 100644 index df56a248..00000000 --- a/subx/012indirect_addressing.cc +++ /dev/null @@ -1,561 +0,0 @@ -//: operating on memory at the address provided by some register -//: we'll now start providing data in a separate segment - -:(scenario add_r32_to_mem_at_r32) -% Reg[EBX].i = 0x10; -% Reg[EAX].i = 0x60; -== 0x01 # code segment -# op ModR/M SIB displacement immediate - 01 18 # add EBX to *EAX -# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) -== 0x60 # data segment -01 00 00 00 # 1 -+run: add EBX to r/m32 -+run: effective address is 0x60 (EAX) -+run: storing 0x00000011 - -:(before "End Mod Special-cases(addr)") -case 0: // indirect addressing - switch (rm) { - default: // address in register - trace(2, "run") << "effective address is 0x" << std::hex << Reg[rm].u << " (" << rname(rm) << ")" << end(); - addr = Reg[rm].u; - break; - // End Mod 0 Special-cases(addr) - } - break; - -//: - -:(scenario add_mem_at_r32_to_r32) -% Reg[EAX].i = 0x60; -% Reg[EBX].i = 0x10; -== 0x01 # code segment -# op ModR/M SIB displacement immediate - 03 18 # add *EAX to EBX -# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) -== 0x60 # data segment -01 00 00 00 # 1 -+run: add r/m32 to EBX -+run: effective address is 0x60 (EAX) -+run: storing 0x00000011 - -:(before "End Single-Byte Opcodes") -case 0x03: { // add r/m32 to r32 - uint8_t modrm = next(); - uint8_t arg1 = (modrm>>3)&0x7; - trace(2, "run") << "add r/m32 to " << rname(arg1) << end(); - const int32_t* arg2 = effective_address(modrm); - BINARY_ARITHMETIC_OP(+, Reg[arg1].i, *arg2); - break; -} - -//:: subtract - -:(scenario subtract_r32_from_mem_at_r32) -% Reg[EAX].i = 0x60; -% Reg[EBX].i = 1; -== 0x01 # code segment -# op ModR/M SIB displacement immediate - 29 18 # subtract EBX from *EAX -# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) -== 0x60 # data segment -0a 00 00 00 # 10 -+run: subtract EBX from r/m32 -+run: effective address is 0x60 (EAX) -+run: storing 0x00000009 - -//: - -:(scenario subtract_mem_at_r32_from_r32) -% Reg[EAX].i = 0x60; -% Reg[EBX].i = 10; -== 0x01 # code segment -# op ModR/M SIB displacement immediate - 2b 18 # subtract *EAX from EBX -# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) -== 0x60 # data segment -01 00 00 00 # 1 -+run: subtract r/m32 from EBX -+run: effective address is 0x60 (EAX) -+run: storing 0x00000009 - -:(before "End Single-Byte Opcodes") -case 0x2b: { // subtract r/m32 from r32 - uint8_t modrm = next(); - uint8_t arg1 = (modrm>>3)&0x7; - trace(2, "run") << "subtract r/m32 from " << rname(arg1) << end(); - const int32_t* arg2 = effective_address(modrm); - BINARY_ARITHMETIC_OP(-, Reg[arg1].i, *arg2); - break; -} - -//:: and - -:(scenario and_r32_with_mem_at_r32) -% Reg[EAX].i = 0x60; -% Reg[EBX].i = 0xff; -== 0x01 # code segment -# op ModR/M SIB displacement immediate - 21 18 # and EBX with *EAX -# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) -== 0x60 # data segment -0d 0c 0b 0a # 0x0a0b0c0d -+run: and EBX with r/m32 -+run: effective address is 0x60 (EAX) -+run: storing 0x0000000d - -//: - -:(scenario and_mem_at_r32_with_r32) -% Reg[EAX].i = 0x60; -% Reg[EBX].i = 0x0a0b0c0d; -== 0x01 # code segment -# op ModR/M SIB displacement immediate - 23 18 # and *EAX with EBX -# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) -== 0x60 # data segment -ff 00 00 00 # 0xff -+run: and r/m32 with EBX -+run: effective address is 0x60 (EAX) -+run: storing 0x0000000d - -:(before "End Single-Byte Opcodes") -case 0x23: { // and r/m32 with r32 - uint8_t modrm = next(); - uint8_t arg1 = (modrm>>3)&0x7; - trace(2, "run") << "and r/m32 with " << rname(arg1) << end(); - const int32_t* arg2 = effective_address(modrm); - BINARY_BITWISE_OP(&, Reg[arg1].u, *arg2); - break; -} - -//:: or - -:(scenario or_r32_with_mem_at_r32) -% Reg[EAX].i = 0x60; -% Reg[EBX].i = 0xa0b0c0d0; -== 0x01 # code segment -# op ModR/M SIB displacement immediate - 09 18 # or EBX with *EAX -# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) -== 0x60 # data segment -0d 0c 0b 0a # 0x0a0b0c0d -+run: or EBX with r/m32 -+run: effective address is 0x60 (EAX) -+run: storing 0xaabbccdd - -//: - -:(scenario or_mem_at_r32_with_r32) -% Reg[EAX].i = 0x60; -% Reg[EBX].i = 0xa0b0c0d0; -== 0x01 # code segment -# op ModR/M SIB displacement immediate - 0b 18 # or *EAX with EBX -# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) -== 0x60 # data segment -0d 0c 0b 0a # 0x0a0b0c0d -+run: or r/m32 with EBX -+run: effective address is 0x60 (EAX) -+run: storing 0xaabbccdd - -:(before "End Single-Byte Opcodes") -case 0x0b: { // or r/m32 with r32 - uint8_t modrm = next(); - uint8_t arg1 = (modrm>>3)&0x7; - trace(2, "run") << "or r/m32 with " << rname(arg1) << end(); - const int32_t* arg2 = effective_address(modrm); - BINARY_BITWISE_OP(|, Reg[arg1].u, *arg2); - break; -} - -//:: xor - -:(scenario xor_r32_with_mem_at_r32) -% Reg[EAX].i = 0x60; -% Reg[EBX].i = 0xa0b0c0d0; -== 0x01 # code segment -# op ModR/M SIB displacement immediate - 31 18 # xor EBX with *EAX -# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) -== 0x60 # data segment -0d 0c bb aa # 0xaabb0c0d -+run: xor EBX with r/m32 -+run: effective address is 0x60 (EAX) -+run: storing 0x0a0bccdd - -//: - -:(scenario xor_mem_at_r32_with_r32) -% Reg[EAX].i = 0x60; -% Reg[EBX].i = 0xa0b0c0d0; -== 0x01 # code segment -# op ModR/M SIB displacement immediate - 33 18 # xor *EAX with EBX -# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) -== 0x60 # data segment -0d 0c 0b 0a # 0x0a0b0c0d -+run: xor r/m32 with EBX -+run: effective address is 0x60 (EAX) -+run: storing 0xaabbccdd - -:(before "End Single-Byte Opcodes") -case 0x33: { // xor r/m32 with r32 - uint8_t modrm = next(); - uint8_t arg1 = (modrm>>3)&0x7; - trace(2, "run") << "xor r/m32 with " << rname(arg1) << end(); - const int32_t* arg2 = effective_address(modrm); - BINARY_BITWISE_OP(|, Reg[arg1].u, *arg2); - break; -} - -//:: not - -:(scenario not_r32_with_mem_at_r32) -% Reg[EBX].i = 0x60; -== 0x01 # code segment -# op ModR/M SIB displacement immediate - f7 03 # negate *EBX -# ModR/M in binary: 00 (indirect mode) 000 (unused) 011 (dest EBX) -== 0x60 # data segment -ff 00 0f 0f # 0x0f0f00ff -+run: 'not' of r/m32 -+run: effective address is 0x60 (EBX) -+run: storing 0xf0f0ff00 - -//:: compare (cmp) - -:(scenario compare_mem_at_r32_with_r32_greater) -% Reg[EAX].i = 0x60; -% Reg[EBX].i = 0x0a0b0c07; -== 0x01 # code segment -# op ModR/M SIB displacement immediate - 39 18 # compare EBX with *EAX -# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) -== 0x60 # data segment -0d 0c 0b 0a # 0x0a0b0c0d -+run: compare EBX with r/m32 -+run: effective address is 0x60 (EAX) -+run: SF=0; ZF=0; OF=0 - -:(scenario compare_mem_at_r32_with_r32_lesser) -% Reg[EAX].i = 0x60; -% Reg[EBX].i = 0x0a0b0c0d; -== 0x01 # code segment -# op ModR/M SIB displacement immediate - 39 18 # compare EBX with *EAX -# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) -== 0x60 # data segment -07 0c 0b 0a # 0x0a0b0c0d -+run: compare EBX with r/m32 -+run: effective address is 0x60 (EAX) -+run: SF=1; ZF=0; OF=0 - -:(scenario compare_mem_at_r32_with_r32_equal) -% Reg[EAX].i = 0x60; -% Reg[EBX].i = 0x0a0b0c0d; -== 0x01 # code segment -# op ModR/M SIB displacement immediate - 39 18 # compare EBX with *EAX -# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) -== 0x60 # data segment -0d 0c 0b 0a # 0x0a0b0c0d -+run: compare EBX with r/m32 -+run: effective address is 0x60 (EAX) -+run: SF=0; ZF=1; OF=0 - -//: - -:(scenario compare_r32_with_mem_at_r32_greater) -% Reg[EAX].i = 0x60; -% Reg[EBX].i = 0x0a0b0c0d; -== 0x01 # code segment -# op ModR/M SIB displacement immediate - 3b 18 # compare *EAX with EBX -# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) -== 0x60 # data segment -07 0c 0b 0a # 0x0a0b0c0d -+run: compare r/m32 with EBX -+run: effective address is 0x60 (EAX) -+run: SF=0; ZF=0; OF=0 - -:(before "End Single-Byte Opcodes") -case 0x3b: { // set SF if r32 < r/m32 - uint8_t modrm = next(); - uint8_t reg1 = (modrm>>3)&0x7; - trace(2, "run") << "compare r/m32 with " << rname(reg1) << end(); - int32_t arg1 = Reg[reg1].i; - int32_t* arg2 = effective_address(modrm); - int32_t tmp1 = arg1 - *arg2; - SF = (tmp1 < 0); - ZF = (tmp1 == 0); - int64_t tmp2 = arg1 - *arg2; - OF = (tmp1 != tmp2); - trace(2, "run") << "SF=" << SF << "; ZF=" << ZF << "; OF=" << OF << end(); - break; -} - -:(scenario compare_r32_with_mem_at_r32_lesser) -% Reg[EAX].i = 0x60; -% Reg[EBX].i = 0x0a0b0c07; -== 0x01 # code segment -# op ModR/M SIB displacement immediate - 3b 18 # compare *EAX with EBX -# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) -== 0x60 # data segment -0d 0c 0b 0a # 0x0a0b0c0d -+run: compare r/m32 with EBX -+run: effective address is 0x60 (EAX) -+run: SF=1; ZF=0; OF=0 - -:(scenario compare_r32_with_mem_at_r32_equal) -% Reg[EAX].i = 0x60; -% Reg[EBX].i = 0x0a0b0c0d; -== 0x01 # code segment -# op ModR/M SIB displacement immediate - 3b 18 # compare *EAX with EBX -# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) -== 0x60 # data segment -0d 0c 0b 0a # 0x0a0b0c0d -+run: compare r/m32 with EBX -+run: effective address is 0x60 (EAX) -+run: SF=0; ZF=1; OF=0 - -//:: copy (mov) - -:(scenario copy_r32_to_mem_at_r32) -% Reg[EBX].i = 0xaf; -% Reg[EAX].i = 0x60; -# op ModR/M SIB displacement immediate - 89 18 # copy EBX to *EAX -# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) -+run: copy EBX to r/m32 -+run: effective address is 0x60 (EAX) -+run: storing 0x000000af - -//: - -:(scenario copy_mem_at_r32_to_r32) -% Reg[EAX].i = 0x60; -== 0x01 # code segment -# op ModR/M SIB displacement immediate - 8b 18 # copy *EAX to EBX -# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) -== 0x60 # data segment -af 00 00 00 # 0xaf -+run: copy r/m32 to EBX -+run: effective address is 0x60 (EAX) -+run: storing 0x000000af - -:(before "End Single-Byte Opcodes") -case 0x8b: { // copy r32 to r/m32 - uint8_t modrm = next(); - uint8_t reg1 = (modrm>>3)&0x7; - trace(2, "run") << "copy r/m32 to " << rname(reg1) << end(); - int32_t* arg2 = effective_address(modrm); - Reg[reg1].i = *arg2; - trace(2, "run") << "storing 0x" << HEXWORD << *arg2 << end(); - break; -} - -//:: jump - -:(scenario jump_mem_at_r32) -% Reg[EAX].i = 0x60; -== 0x01 # code segment -# op ModR/M SIB displacement immediate - ff 20 # jump to *EAX -# ModR/M in binary: 00 (indirect mode) 100 (jump to r/m32) 000 (src EAX) - 05 00 00 00 01 - 05 00 00 00 02 -== 0x60 # data segment -08 00 00 00 # 8 -+run: inst: 0x00000001 -+run: jump to r/m32 -+run: effective address is 0x60 (EAX) -+run: jumping to 0x00000008 -+run: inst: 0x00000008 --run: inst: 0x00000003 - -:(before "End Single-Byte Opcodes") -case 0xff: { - uint8_t modrm = next(); - uint8_t subop = (modrm>>3)&0x7; // middle 3 'reg opcode' bits - switch (subop) { - case 4: { // jump to r/m32 - trace(2, "run") << "jump to r/m32" << end(); - int32_t* arg2 = effective_address(modrm); - EIP = *arg2; - trace(2, "run") << "jumping to 0x" << HEXWORD << EIP << end(); - break; - } - // End Op ff Subops - } - break; -} - -//:: push - -:(scenario push_mem_at_r32) -% Reg[EAX].i = 0x60; -% Reg[ESP].u = 0x14; -== 0x01 # code segment -# op ModR/M SIB displacement immediate - ff 30 # push *EAX to stack -# ModR/M in binary: 00 (indirect mode) 110 (push r/m32) 000 (src EAX) -== 0x60 # data segment -af 00 00 00 # 0xaf -+run: push r/m32 -+run: effective address is 0x60 (EAX) -+run: decrementing ESP to 0x00000010 -+run: pushing value 0x000000af - -:(before "End Op ff Subops") -case 6: { // push r/m32 to stack - trace(2, "run") << "push r/m32" << end(); - const int32_t* val = effective_address(modrm); - push(*val); - break; -} - -//:: pop - -:(scenario pop_mem_at_r32) -% Reg[EAX].i = 0x60; -% Reg[ESP].u = 0x10; -== 0x01 # code segment -# op ModR/M SIB displacement immediate - 8f 00 # pop stack into *EAX -# ModR/M in binary: 00 (indirect mode) 000 (pop r/m32) 000 (dest EAX) -== 0x10 # data segment -30 00 00 00 # 0x30 -+run: pop into r/m32 -+run: effective address is 0x60 (EAX) -+run: popping value 0x00000030 -+run: incrementing ESP to 0x00000014 - -:(before "End Single-Byte Opcodes") -case 0x8f: { // pop stack into r/m32 - uint8_t modrm = next(); - uint8_t subop = (modrm>>3)&0x7; - switch (subop) { - case 0: { - trace(2, "run") << "pop into r/m32" << end(); - int32_t* dest = effective_address(modrm); - *dest = pop(); - break; - } - } - break; -} - -//:: special-case for loading address from disp32 rather than register - -:(scenario add_r32_to_mem_at_displacement) -% Reg[EBX].i = 0x10; // source -== 0x01 # code segment -# op ModR/M SIB displacement immediate - 01 1d 60 00 00 00 # add EBX to *0x60 -# ModR/M in binary: 00 (indirect mode) 011 (src EBX) 101 (dest in disp32) -== 0x60 # data segment -01 00 00 00 # 1 -+run: add EBX to r/m32 -+run: effective address is 0x60 (disp32) -+run: storing 0x00000011 - -:(before "End Mod 0 Special-cases(addr)") -case 5: // exception: mod 0b00 rm 0b101 => incoming disp32 - addr = imm32(); - trace(2, "run") << "effective address is 0x" << std::hex << addr << " (disp32)" << end(); - break; - -//: - -:(scenario add_r32_to_mem_at_r32_plus_disp8) -% Reg[EBX].i = 0x10; // source -% Reg[EAX].i = 0x5e; // dest -== 0x01 # code segment -# op ModR/M SIB displacement immediate - 01 58 02 # add EBX to *(EAX+2) -# ModR/M in binary: 01 (indirect+disp8 mode) 011 (src EBX) 000 (dest EAX) -== 0x60 # data segment -01 00 00 00 # 1 -+run: add EBX to r/m32 -+run: effective address is initially 0x5e (EAX) -+run: effective address is 0x60 (after adding disp8) -+run: storing 0x00000011 - -:(before "End Mod Special-cases(addr)") -case 1: // indirect + disp8 addressing - switch (rm) { - default: - addr = Reg[rm].u; - trace(2, "run") << "effective address is initially 0x" << std::hex << addr << " (" << rname(rm) << ")" << end(); - break; - // End Mod 1 Special-cases(addr) - } - if (addr > 0) { - addr += static_cast(next()); - trace(2, "run") << "effective address is 0x" << std::hex << addr << " (after adding disp8)" << end(); - } - break; - -:(scenario add_r32_to_mem_at_r32_plus_negative_disp8) -% Reg[EBX].i = 0x10; // source -% Reg[EAX].i = 0x61; // dest -== 0x01 # code segment -# op ModR/M SIB displacement immediate - 01 58 ff # add EBX to *(EAX-1) -# ModR/M in binary: 01 (indirect+disp8 mode) 011 (src EBX) 000 (dest EAX) -== 0x60 # data segment -01 00 00 00 # 1 -+run: add EBX to r/m32 -+run: effective address is initially 0x61 (EAX) -+run: effective address is 0x60 (after adding disp8) -+run: storing 0x00000011 - -//: - -:(scenario add_r32_to_mem_at_r32_plus_disp32) -% Reg[EBX].i = 0x10; // source -% Reg[EAX].i = 0x5e; // dest -== 0x01 # code segment -# op ModR/M SIB displacement immediate - 01 98 02 00 00 00 # add EBX to *(EAX+2) -# ModR/M in binary: 10 (indirect+disp32 mode) 011 (src EBX) 000 (dest EAX) -== 0x60 # data segment -01 00 00 00 # 1 -+run: add EBX to r/m32 -+run: effective address is initially 0x5e (EAX) -+run: effective address is 0x60 (after adding disp32) -+run: storing 0x00000011 - -:(before "End Mod Special-cases(addr)") -case 2: // indirect + disp32 addressing - switch (rm) { - default: - addr = Reg[rm].u; - trace(2, "run") << "effective address is initially 0x" << std::hex << addr << " (" << rname(rm) << ")" << end(); - break; - // End Mod 2 Special-cases(addr) - } - if (addr > 0) { - addr += imm32(); - trace(2, "run") << "effective address is 0x" << std::hex << addr << " (after adding disp32)" << end(); - } - break; - -:(scenario add_r32_to_mem_at_r32_plus_negative_disp32) -% Reg[EBX].i = 0x10; // source -% Reg[EAX].i = 0x61; // dest -== 0x01 # code segment -# op ModR/M SIB displacement immediate - 01 98 ff ff ff ff # add EBX to *(EAX-1) -# ModR/M in binary: 10 (indirect+disp32 mode) 011 (src EBX) 000 (dest EAX) -== 0x60 # data segment -01 00 00 00 # 1 -+run: add EBX to r/m32 -+run: effective address is initially 0x61 (EAX) -+run: effective address is 0x60 (after adding disp32) -+run: storing 0x00000011 diff --git a/subx/013immediate_addressing.cc b/subx/013immediate_addressing.cc deleted file mode 100644 index c1e88f21..00000000 --- a/subx/013immediate_addressing.cc +++ /dev/null @@ -1,425 +0,0 @@ -//: instructions that (immediately) contain an argument to act with - -:(scenario add_imm32_to_r32) -% Reg[EBX].i = 1; -# op ModR/M SIB displacement immediate - 81 c3 0a 0b 0c 0d # add 0x0d0c0b0a to EBX -# ModR/M in binary: 11 (direct mode) 000 (add imm32) 011 (dest EBX) -+run: combine imm32 0x0d0c0b0a with r/m32 -+run: r/m32 is EBX -+run: subop add -+run: storing 0x0d0c0b0b - -:(before "End Single-Byte Opcodes") -case 0x81: { // combine imm32 with r/m32 - uint8_t modrm = next(); - int32_t arg2 = imm32(); - trace(2, "run") << "combine imm32 0x" << HEXWORD << arg2 << " with r/m32" << end(); - int32_t* arg1 = effective_address(modrm); - uint8_t subop = (modrm>>3)&0x7; // middle 3 'reg opcode' bits - switch (subop) { - case 0: - trace(2, "run") << "subop add" << end(); - BINARY_ARITHMETIC_OP(+, *arg1, arg2); - break; - // End Op 81 Subops - default: - cerr << "unrecognized sub-opcode after 81: " << NUM(subop) << '\n'; - exit(1); - } - break; -} - -//: - -:(scenario add_imm32_to_mem_at_r32) -% Reg[EBX].i = 0x60; -== 0x01 # code segment -# op ModR/M SIB displacement immediate - 81 03 0a 0b 0c 0d # add 0x0d0c0b0a to *EBX -# ModR/M in binary: 00 (indirect mode) 000 (add imm32) 011 (dest EBX) -== 0x60 # data segment -01 00 00 00 # 1 -+run: combine imm32 0x0d0c0b0a with r/m32 -+run: effective address is 0x60 (EBX) -+run: subop add -+run: storing 0x0d0c0b0b - -//:: subtract - -:(scenario subtract_imm32_from_eax) -% Reg[EAX].i = 0x0d0c0baa; -# op ModR/M SIB displacement immediate - 2d 0a 0b 0c 0d # subtract 0x0d0c0b0a from EAX -+run: subtract imm32 0x0d0c0b0a from EAX -+run: storing 0x000000a0 - -:(before "End Single-Byte Opcodes") -case 0x2d: { // subtract imm32 from EAX - int32_t arg2 = imm32(); - trace(2, "run") << "subtract imm32 0x" << HEXWORD << arg2 << " from EAX" << end(); - BINARY_ARITHMETIC_OP(-, Reg[EAX].i, arg2); - break; -} - -//: - -:(scenario subtract_imm32_from_mem_at_r32) -% Reg[EBX].i = 0x60; -== 0x01 # code segment -# op ModR/M SIB displacement immediate - 81 2b 01 00 00 00 # subtract 1 from *EBX -# ModR/M in binary: 00 (indirect mode) 101 (subtract imm32) 011 (dest EBX) -== 0x60 # data segment -0a 00 00 00 # 10 -+run: combine imm32 0x00000001 with r/m32 -+run: effective address is 0x60 (EBX) -+run: subop subtract -+run: storing 0x00000009 - -:(before "End Op 81 Subops") -case 5: { - trace(2, "run") << "subop subtract" << end(); - BINARY_ARITHMETIC_OP(-, *arg1, arg2); - break; -} - -//: - -:(scenario subtract_imm32_from_r32) -% Reg[EBX].i = 10; -# op ModR/M SIB displacement immediate - 81 eb 01 00 00 00 # subtract 1 from EBX -# ModR/M in binary: 11 (direct mode) 101 (subtract imm32) 011 (dest EBX) -+run: combine imm32 0x00000001 with r/m32 -+run: r/m32 is EBX -+run: subop subtract -+run: storing 0x00000009 - -//:: and - -:(scenario and_imm32_with_eax) -% Reg[EAX].i = 0xff; -# op ModR/M SIB displacement immediate - 25 0a 0b 0c 0d # and 0x0d0c0b0a with EAX -+run: and imm32 0x0d0c0b0a with EAX -+run: storing 0x0000000a - -:(before "End Single-Byte Opcodes") -case 0x25: { // and imm32 with EAX - int32_t arg2 = imm32(); - trace(2, "run") << "and imm32 0x" << HEXWORD << arg2 << " with EAX" << end(); - BINARY_BITWISE_OP(&, Reg[EAX].i, arg2); - break; -} - -//: - -:(scenario and_imm32_with_mem_at_r32) -% Reg[EBX].i = 0x60; -== 0x01 # code segment -# op ModR/M SIB displacement immediate - 81 23 0a 0b 0c 0d # and 0x0d0c0b0a with *EBX -# ModR/M in binary: 00 (indirect mode) 100 (and imm32) 011 (dest EBX) -== 0x60 # data segment -ff 00 00 00 # 0xff -+run: combine imm32 0x0d0c0b0a with r/m32 -+run: effective address is 0x60 (EBX) -+run: subop and -+run: storing 0x0000000a - -:(before "End Op 81 Subops") -case 4: { - trace(2, "run") << "subop and" << end(); - BINARY_BITWISE_OP(&, *arg1, arg2); - break; -} - -//: - -:(scenario and_imm32_with_r32) -% Reg[EBX].i = 0xff; -# op ModR/M SIB displacement immediate - 81 e3 0a 0b 0c 0d # and 0x0d0c0b0a with EBX -# ModR/M in binary: 11 (direct mode) 100 (and imm32) 011 (dest EBX) -+run: combine imm32 0x0d0c0b0a with r/m32 -+run: r/m32 is EBX -+run: subop and -+run: storing 0x0000000a - -//:: or - -:(scenario or_imm32_with_eax) -% Reg[EAX].i = 0xd0c0b0a0; -# op ModR/M SIB displacement immediate - 0d 0a 0b 0c 0d # or 0x0d0c0b0a with EAX -+run: or imm32 0x0d0c0b0a with EAX -+run: storing 0xddccbbaa - -:(before "End Single-Byte Opcodes") -case 0x0d: { // or imm32 with EAX - int32_t arg2 = imm32(); - trace(2, "run") << "or imm32 0x" << HEXWORD << arg2 << " with EAX" << end(); - BINARY_BITWISE_OP(|, Reg[EAX].i, arg2); - break; -} - -//: - -:(scenario or_imm32_with_mem_at_r32) -% Reg[EBX].i = 0x60; -== 0x01 # code segment -# op ModR/M SIB displacement immediate - 81 0b 0a 0b 0c 0d # or 0x0d0c0b0a with *EBX -# ModR/M in binary: 00 (indirect mode) 001 (or imm32) 011 (dest EBX) -== 0x60 # data segment -a0 b0 c0 d0 # 0xd0c0b0a0 -+run: combine imm32 0x0d0c0b0a with r/m32 -+run: effective address is 0x60 (EBX) -+run: subop or -+run: storing 0xddccbbaa - -:(before "End Op 81 Subops") -case 1: { - trace(2, "run") << "subop or" << end(); - BINARY_BITWISE_OP(|, *arg1, arg2); - break; -} - -:(scenario or_imm32_with_r32) -% Reg[EBX].i = 0xd0c0b0a0; -# op ModR/M SIB displacement immediate - 81 cb 0a 0b 0c 0d # or 0x0d0c0b0a with EBX -# ModR/M in binary: 11 (direct mode) 001 (or imm32) 011 (dest EBX) -+run: combine imm32 0x0d0c0b0a with r/m32 -+run: r/m32 is EBX -+run: subop or -+run: storing 0xddccbbaa - -//:: xor - -:(scenario xor_imm32_with_eax) -% Reg[EAX].i = 0xddccb0a0; -# op ModR/M SIB displacement immediate - 35 0a 0b 0c 0d # xor 0x0d0c0b0a with EAX -+run: xor imm32 0x0d0c0b0a with EAX -+run: storing 0xd0c0bbaa - -:(before "End Single-Byte Opcodes") -case 0x35: { // xor imm32 with EAX - int32_t arg2 = imm32(); - trace(2, "run") << "xor imm32 0x" << HEXWORD << arg2 << " with EAX" << end(); - BINARY_BITWISE_OP(^, Reg[EAX].i, arg2); - break; -} - -//: - -:(scenario xor_imm32_with_mem_at_r32) -% Reg[EBX].i = 0x60; -== 0x01 # code segment -# op ModR/M SIB displacement immediate - 81 33 0a 0b 0c 0d # xor 0x0d0c0b0a with *EBX -# ModR/M in binary: 00 (indirect mode) 110 (xor imm32) 011 (dest EBX) -== 0x60 # data segment -a0 b0 c0 d0 # 0xd0c0b0a0 -+run: combine imm32 0x0d0c0b0a with r/m32 -+run: effective address is 0x60 (EBX) -+run: subop xor -+run: storing 0xddccbbaa - -:(before "End Op 81 Subops") -case 6: { - trace(2, "run") << "subop xor" << end(); - BINARY_BITWISE_OP(^, *arg1, arg2); - break; -} - -:(scenario xor_imm32_with_r32) -% Reg[EBX].i = 0xd0c0b0a0; -# op ModR/M SIB displacement immediate - 81 f3 0a 0b 0c 0d # xor 0x0d0c0b0a with EBX -# ModR/M in binary: 11 (direct mode) 110 (xor imm32) 011 (dest EBX) -+run: combine imm32 0x0d0c0b0a with r/m32 -+run: r/m32 is EBX -+run: subop xor -+run: storing 0xddccbbaa - -//:: compare (cmp) - -:(scenario compare_imm32_with_eax_greater) -% Reg[EAX].i = 0x0d0c0b0a; -# op ModR/M SIB displacement immediate - 3d 07 0b 0c 0d # compare 0x0d0c0b07 with EAX -+run: compare EAX and imm32 0x0d0c0b07 -+run: SF=0; ZF=0; OF=0 - -:(before "End Single-Byte Opcodes") -case 0x3d: { // subtract imm32 from EAX - int32_t arg1 = Reg[EAX].i; - int32_t arg2 = imm32(); - trace(2, "run") << "compare EAX and imm32 0x" << HEXWORD << arg2 << end(); - int32_t tmp1 = arg1 - arg2; - SF = (tmp1 < 0); - ZF = (tmp1 == 0); - int64_t tmp2 = arg1 - arg2; - OF = (tmp1 != tmp2); - trace(2, "run") << "SF=" << SF << "; ZF=" << ZF << "; OF=" << OF << end(); - break; -} - -:(scenario compare_imm32_with_eax_lesser) -% Reg[EAX].i = 0x0d0c0b07; -# op ModR/M SIB displacement immediate - 3d 0a 0b 0c 0d # compare 0x0d0c0b0a with EAX -+run: compare EAX and imm32 0x0d0c0b0a -+run: SF=1; ZF=0; OF=0 - -:(scenario compare_imm32_with_eax_equal) -% Reg[EAX].i = 0x0d0c0b0a; -# op ModR/M SIB displacement immediate - 3d 0a 0b 0c 0d # compare 0x0d0c0b0a with EAX -+run: compare EAX and imm32 0x0d0c0b0a -+run: SF=0; ZF=1; OF=0 - -//: - -:(scenario compare_imm32_with_r32_greater) -% Reg[EBX].i = 0x0d0c0b0a; -# op ModR/M SIB displacement immediate - 81 fb 07 0b 0c 0d # compare 0x0d0c0b07 with EBX -# ModR/M in binary: 11 (direct mode) 111 (compare imm32) 011 (dest EBX) -+run: combine imm32 0x0d0c0b07 with r/m32 -+run: r/m32 is EBX -+run: SF=0; ZF=0; OF=0 - -:(before "End Op 81 Subops") -case 7: { - trace(2, "run") << "subop compare" << end(); - int32_t tmp1 = *arg1 - arg2; - SF = (tmp1 < 0); - ZF = (tmp1 == 0); - int64_t tmp2 = *arg1 - arg2; - OF = (tmp1 != tmp2); - trace(2, "run") << "SF=" << SF << "; ZF=" << ZF << "; OF=" << OF << end(); - break; -} - -:(scenario compare_imm32_with_r32_lesser) -% Reg[EBX].i = 0x0d0c0b07; -# op ModR/M SIB displacement immediate - 81 fb 0a 0b 0c 0d # compare 0x0d0c0b0a with EBX -# ModR/M in binary: 11 (direct mode) 111 (compare imm32) 011 (dest EBX) -+run: combine imm32 0x0d0c0b0a with r/m32 -+run: r/m32 is EBX -+run: SF=1; ZF=0; OF=0 - -:(scenario compare_imm32_with_r32_equal) -% Reg[EBX].i = 0x0d0c0b0a; -# op ModR/M SIB displacement immediate - 81 fb 0a 0b 0c 0d # compare 0x0d0c0b0a with EBX -# ModR/M in binary: 11 (direct mode) 111 (compare imm32) 011 (dest EBX) -+run: combine imm32 0x0d0c0b0a with r/m32 -+run: r/m32 is EBX -+run: SF=0; ZF=1; OF=0 - -:(scenario compare_imm32_with_mem_at_r32_greater) -% Reg[EBX].i = 0x60; -== 0x01 # code segment -# op ModR/M SIB displacement immediate - 81 3b 07 0b 0c 0d # compare 0x0d0c0b07 with *EBX -# ModR/M in binary: 00 (indirect mode) 111 (compare imm32) 011 (dest EBX) -== 0x60 # data segment -0a 0b 0c 0d # 0x0d0c0b0a -+run: combine imm32 0x0d0c0b07 with r/m32 -+run: effective address is 0x60 (EBX) -+run: SF=0; ZF=0; OF=0 - -:(scenario compare_imm32_with_mem_at_r32_lesser) -% Reg[EBX].i = 0x60; -== 0x01 # code segment -# op ModR/M SIB displacement immediate - 81 3b 0a 0b 0c 0d # compare 0x0d0c0b0a with *EBX -# ModR/M in binary: 00 (indirect mode) 111 (compare imm32) 011 (dest EBX) -== 0x60 # data segment -07 0b 0c 0d # 0x0d0c0b07 -+run: combine imm32 0x0d0c0b0a with r/m32 -+run: effective address is 0x60 (EBX) -+run: SF=1; ZF=0; OF=0 - -:(scenario compare_imm32_with_mem_at_r32_equal) -% Reg[EBX].i = 0x0d0c0b0a; -% Reg[EBX].i = 0x60; -== 0x01 # code segment -# op ModR/M SIB displacement immediate - 81 3b 0a 0b 0c 0d # compare 0x0d0c0b0a with *EBX -# ModR/M in binary: 00 (indirect mode) 111 (compare imm32) 011 (dest EBX) -== 0x60 # data segment -0a 0b 0c 0d # 0x0d0c0b0a -+run: combine imm32 0x0d0c0b0a with r/m32 -+run: effective address is 0x60 (EBX) -+run: SF=0; ZF=1; OF=0 - -//:: copy (mov) - -:(scenario copy_imm32_to_r32) -# op ModR/M SIB displacement immediate - bb 0a 0b 0c 0d # copy 0x0d0c0b0a to EBX -+run: copy imm32 0x0d0c0b0a to EBX - -:(before "End Single-Byte Opcodes") -case 0xb8: -case 0xb9: -case 0xba: -case 0xbb: -case 0xbc: -case 0xbd: -case 0xbe: -case 0xbf: { // copy imm32 to r32 - uint8_t reg1 = op & 0x7; - int32_t arg2 = imm32(); - trace(2, "run") << "copy imm32 0x" << HEXWORD << arg2 << " to " << rname(reg1) << end(); - Reg[reg1].i = arg2; - break; -} - -//: - -:(scenario copy_imm32_to_mem_at_r32) -% Reg[EBX].i = 0x60; -# op ModR/M SIB displacement immediate - c7 03 0a 0b 0c 0d # copy 0x0d0c0b0a to *EBX -# ModR/M in binary: 00 (indirect mode) 000 (unused) 011 (dest EBX) -+run: copy imm32 0x0d0c0b0a to r/m32 -+run: effective address is 0x60 (EBX) - -:(before "End Single-Byte Opcodes") -case 0xc7: { // copy imm32 to r32 - uint8_t modrm = next(); - int32_t arg2 = imm32(); - trace(2, "run") << "copy imm32 0x" << HEXWORD << arg2 << " to r/m32" << end(); - int32_t* arg1 = effective_address(modrm); - *arg1 = arg2; - break; -} - -//:: push - -:(scenario push_imm32) -% Reg[ESP].u = 0x14; -# op ModR/M SIB displacement immediate - 68 af 00 00 00 # push *EAX to stack -+run: push imm32 0x000000af -+run: ESP is now 0x00000010 -+run: contents at ESP: 0x000000af - -:(before "End Single-Byte Opcodes") -case 0x68: { - int32_t val = imm32(); - trace(2, "run") << "push imm32 0x" << HEXWORD << val << end(); - Reg[ESP].u -= 4; - write_mem_i32(Reg[ESP].u, val); - trace(2, "run") << "ESP is now 0x" << HEXWORD << Reg[ESP].u << end(); - trace(2, "run") << "contents at ESP: 0x" << HEXWORD << read_mem_u32(Reg[ESP].u) << end(); - break; -} diff --git a/subx/013indirect_addressing.cc b/subx/013indirect_addressing.cc new file mode 100644 index 00000000..df56a248 --- /dev/null +++ b/subx/013indirect_addressing.cc @@ -0,0 +1,561 @@ +//: operating on memory at the address provided by some register +//: we'll now start providing data in a separate segment + +:(scenario add_r32_to_mem_at_r32) +% Reg[EBX].i = 0x10; +% Reg[EAX].i = 0x60; +== 0x01 # code segment +# op ModR/M SIB displacement immediate + 01 18 # add EBX to *EAX +# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) +== 0x60 # data segment +01 00 00 00 # 1 ++run: add EBX to r/m32 ++run: effective address is 0x60 (EAX) ++run: storing 0x00000011 + +:(before "End Mod Special-cases(addr)") +case 0: // indirect addressing + switch (rm) { + default: // address in register + trace(2, "run") << "effective address is 0x" << std::hex << Reg[rm].u << " (" << rname(rm) << ")" << end(); + addr = Reg[rm].u; + break; + // End Mod 0 Special-cases(addr) + } + break; + +//: + +:(scenario add_mem_at_r32_to_r32) +% Reg[EAX].i = 0x60; +% Reg[EBX].i = 0x10; +== 0x01 # code segment +# op ModR/M SIB displacement immediate + 03 18 # add *EAX to EBX +# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) +== 0x60 # data segment +01 00 00 00 # 1 ++run: add r/m32 to EBX ++run: effective address is 0x60 (EAX) ++run: storing 0x00000011 + +:(before "End Single-Byte Opcodes") +case 0x03: { // add r/m32 to r32 + uint8_t modrm = next(); + uint8_t arg1 = (modrm>>3)&0x7; + trace(2, "run") << "add r/m32 to " << rname(arg1) << end(); + const int32_t* arg2 = effective_address(modrm); + BINARY_ARITHMETIC_OP(+, Reg[arg1].i, *arg2); + break; +} + +//:: subtract + +:(scenario subtract_r32_from_mem_at_r32) +% Reg[EAX].i = 0x60; +% Reg[EBX].i = 1; +== 0x01 # code segment +# op ModR/M SIB displacement immediate + 29 18 # subtract EBX from *EAX +# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) +== 0x60 # data segment +0a 00 00 00 # 10 ++run: subtract EBX from r/m32 ++run: effective address is 0x60 (EAX) ++run: storing 0x00000009 + +//: + +:(scenario subtract_mem_at_r32_from_r32) +% Reg[EAX].i = 0x60; +% Reg[EBX].i = 10; +== 0x01 # code segment +# op ModR/M SIB displacement immediate + 2b 18 # subtract *EAX from EBX +# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) +== 0x60 # data segment +01 00 00 00 # 1 ++run: subtract r/m32 from EBX ++run: effective address is 0x60 (EAX) ++run: storing 0x00000009 + +:(before "End Single-Byte Opcodes") +case 0x2b: { // subtract r/m32 from r32 + uint8_t modrm = next(); + uint8_t arg1 = (modrm>>3)&0x7; + trace(2, "run") << "subtract r/m32 from " << rname(arg1) << end(); + const int32_t* arg2 = effective_address(modrm); + BINARY_ARITHMETIC_OP(-, Reg[arg1].i, *arg2); + break; +} + +//:: and + +:(scenario and_r32_with_mem_at_r32) +% Reg[EAX].i = 0x60; +% Reg[EBX].i = 0xff; +== 0x01 # code segment +# op ModR/M SIB displacement immediate + 21 18 # and EBX with *EAX +# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) +== 0x60 # data segment +0d 0c 0b 0a # 0x0a0b0c0d ++run: and EBX with r/m32 ++run: effective address is 0x60 (EAX) ++run: storing 0x0000000d + +//: + +:(scenario and_mem_at_r32_with_r32) +% Reg[EAX].i = 0x60; +% Reg[EBX].i = 0x0a0b0c0d; +== 0x01 # code segment +# op ModR/M SIB displacement immediate + 23 18 # and *EAX with EBX +# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) +== 0x60 # data segment +ff 00 00 00 # 0xff ++run: and r/m32 with EBX ++run: effective address is 0x60 (EAX) ++run: storing 0x0000000d + +:(before "End Single-Byte Opcodes") +case 0x23: { // and r/m32 with r32 + uint8_t modrm = next(); + uint8_t arg1 = (modrm>>3)&0x7; + trace(2, "run") << "and r/m32 with " << rname(arg1) << end(); + const int32_t* arg2 = effective_address(modrm); + BINARY_BITWISE_OP(&, Reg[arg1].u, *arg2); + break; +} + +//:: or + +:(scenario or_r32_with_mem_at_r32) +% Reg[EAX].i = 0x60; +% Reg[EBX].i = 0xa0b0c0d0; +== 0x01 # code segment +# op ModR/M SIB displacement immediate + 09 18 # or EBX with *EAX +# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) +== 0x60 # data segment +0d 0c 0b 0a # 0x0a0b0c0d ++run: or EBX with r/m32 ++run: effective address is 0x60 (EAX) ++run: storing 0xaabbccdd + +//: + +:(scenario or_mem_at_r32_with_r32) +% Reg[EAX].i = 0x60; +% Reg[EBX].i = 0xa0b0c0d0; +== 0x01 # code segment +# op ModR/M SIB displacement immediate + 0b 18 # or *EAX with EBX +# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) +== 0x60 # data segment +0d 0c 0b 0a # 0x0a0b0c0d ++run: or r/m32 with EBX ++run: effective address is 0x60 (EAX) ++run: storing 0xaabbccdd + +:(before "End Single-Byte Opcodes") +case 0x0b: { // or r/m32 with r32 + uint8_t modrm = next(); + uint8_t arg1 = (modrm>>3)&0x7; + trace(2, "run") << "or r/m32 with " << rname(arg1) << end(); + const int32_t* arg2 = effective_address(modrm); + BINARY_BITWISE_OP(|, Reg[arg1].u, *arg2); + break; +} + +//:: xor + +:(scenario xor_r32_with_mem_at_r32) +% Reg[EAX].i = 0x60; +% Reg[EBX].i = 0xa0b0c0d0; +== 0x01 # code segment +# op ModR/M SIB displacement immediate + 31 18 # xor EBX with *EAX +# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) +== 0x60 # data segment +0d 0c bb aa # 0xaabb0c0d ++run: xor EBX with r/m32 ++run: effective address is 0x60 (EAX) ++run: storing 0x0a0bccdd + +//: + +:(scenario xor_mem_at_r32_with_r32) +% Reg[EAX].i = 0x60; +% Reg[EBX].i = 0xa0b0c0d0; +== 0x01 # code segment +# op ModR/M SIB displacement immediate + 33 18 # xor *EAX with EBX +# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) +== 0x60 # data segment +0d 0c 0b 0a # 0x0a0b0c0d ++run: xor r/m32 with EBX ++run: effective address is 0x60 (EAX) ++run: storing 0xaabbccdd + +:(before "End Single-Byte Opcodes") +case 0x33: { // xor r/m32 with r32 + uint8_t modrm = next(); + uint8_t arg1 = (modrm>>3)&0x7; + trace(2, "run") << "xor r/m32 with " << rname(arg1) << end(); + const int32_t* arg2 = effective_address(modrm); + BINARY_BITWISE_OP(|, Reg[arg1].u, *arg2); + break; +} + +//:: not + +:(scenario not_r32_with_mem_at_r32) +% Reg[EBX].i = 0x60; +== 0x01 # code segment +# op ModR/M SIB displacement immediate + f7 03 # negate *EBX +# ModR/M in binary: 00 (indirect mode) 000 (unused) 011 (dest EBX) +== 0x60 # data segment +ff 00 0f 0f # 0x0f0f00ff ++run: 'not' of r/m32 ++run: effective address is 0x60 (EBX) ++run: storing 0xf0f0ff00 + +//:: compare (cmp) + +:(scenario compare_mem_at_r32_with_r32_greater) +% Reg[EAX].i = 0x60; +% Reg[EBX].i = 0x0a0b0c07; +== 0x01 # code segment +# op ModR/M SIB displacement immediate + 39 18 # compare EBX with *EAX +# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) +== 0x60 # data segment +0d 0c 0b 0a # 0x0a0b0c0d ++run: compare EBX with r/m32 ++run: effective address is 0x60 (EAX) ++run: SF=0; ZF=0; OF=0 + +:(scenario compare_mem_at_r32_with_r32_lesser) +% Reg[EAX].i = 0x60; +% Reg[EBX].i = 0x0a0b0c0d; +== 0x01 # code segment +# op ModR/M SIB displacement immediate + 39 18 # compare EBX with *EAX +# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) +== 0x60 # data segment +07 0c 0b 0a # 0x0a0b0c0d ++run: compare EBX with r/m32 ++run: effective address is 0x60 (EAX) ++run: SF=1; ZF=0; OF=0 + +:(scenario compare_mem_at_r32_with_r32_equal) +% Reg[EAX].i = 0x60; +% Reg[EBX].i = 0x0a0b0c0d; +== 0x01 # code segment +# op ModR/M SIB displacement immediate + 39 18 # compare EBX with *EAX +# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) +== 0x60 # data segment +0d 0c 0b 0a # 0x0a0b0c0d ++run: compare EBX with r/m32 ++run: effective address is 0x60 (EAX) ++run: SF=0; ZF=1; OF=0 + +//: + +:(scenario compare_r32_with_mem_at_r32_greater) +% Reg[EAX].i = 0x60; +% Reg[EBX].i = 0x0a0b0c0d; +== 0x01 # code segment +# op ModR/M SIB displacement immediate + 3b 18 # compare *EAX with EBX +# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) +== 0x60 # data segment +07 0c 0b 0a # 0x0a0b0c0d ++run: compare r/m32 with EBX ++run: effective address is 0x60 (EAX) ++run: SF=0; ZF=0; OF=0 + +:(before "End Single-Byte Opcodes") +case 0x3b: { // set SF if r32 < r/m32 + uint8_t modrm = next(); + uint8_t reg1 = (modrm>>3)&0x7; + trace(2, "run") << "compare r/m32 with " << rname(reg1) << end(); + int32_t arg1 = Reg[reg1].i; + int32_t* arg2 = effective_address(modrm); + int32_t tmp1 = arg1 - *arg2; + SF = (tmp1 < 0); + ZF = (tmp1 == 0); + int64_t tmp2 = arg1 - *arg2; + OF = (tmp1 != tmp2); + trace(2, "run") << "SF=" << SF << "; ZF=" << ZF << "; OF=" << OF << end(); + break; +} + +:(scenario compare_r32_with_mem_at_r32_lesser) +% Reg[EAX].i = 0x60; +% Reg[EBX].i = 0x0a0b0c07; +== 0x01 # code segment +# op ModR/M SIB displacement immediate + 3b 18 # compare *EAX with EBX +# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) +== 0x60 # data segment +0d 0c 0b 0a # 0x0a0b0c0d ++run: compare r/m32 with EBX ++run: effective address is 0x60 (EAX) ++run: SF=1; ZF=0; OF=0 + +:(scenario compare_r32_with_mem_at_r32_equal) +% Reg[EAX].i = 0x60; +% Reg[EBX].i = 0x0a0b0c0d; +== 0x01 # code segment +# op ModR/M SIB displacement immediate + 3b 18 # compare *EAX with EBX +# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) +== 0x60 # data segment +0d 0c 0b 0a # 0x0a0b0c0d ++run: compare r/m32 with EBX ++run: effective address is 0x60 (EAX) ++run: SF=0; ZF=1; OF=0 + +//:: copy (mov) + +:(scenario copy_r32_to_mem_at_r32) +% Reg[EBX].i = 0xaf; +% Reg[EAX].i = 0x60; +# op ModR/M SIB displacement immediate + 89 18 # copy EBX to *EAX +# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) ++run: copy EBX to r/m32 ++run: effective address is 0x60 (EAX) ++run: storing 0x000000af + +//: + +:(scenario copy_mem_at_r32_to_r32) +% Reg[EAX].i = 0x60; +== 0x01 # code segment +# op ModR/M SIB displacement immediate + 8b 18 # copy *EAX to EBX +# ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) +== 0x60 # data segment +af 00 00 00 # 0xaf ++run: copy r/m32 to EBX ++run: effective address is 0x60 (EAX) ++run: storing 0x000000af + +:(before "End Single-Byte Opcodes") +case 0x8b: { // copy r32 to r/m32 + uint8_t modrm = next(); + uint8_t reg1 = (modrm>>3)&0x7; + trace(2, "run") << "copy r/m32 to " << rname(reg1) << end(); + int32_t* arg2 = effective_address(modrm); + Reg[reg1].i = *arg2; + trace(2, "run") << "storing 0x" << HEXWORD << *arg2 << end(); + break; +} + +//:: jump + +:(scenario jump_mem_at_r32) +% Reg[EAX].i = 0x60; +== 0x01 # code segment +# op ModR/M SIB displacement immediate + ff 20 # jump to *EAX +# ModR/M in binary: 00 (indirect mode) 100 (jump to r/m32) 000 (src EAX) + 05 00 00 00 01 + 05 00 00 00 02 +== 0x60 # data segment +08 00 00 00 # 8 ++run: inst: 0x00000001 ++run: jump to r/m32 ++run: effective address is 0x60 (EAX) ++run: jumping to 0x00000008 ++run: inst: 0x00000008 +-run: inst: 0x00000003 + +:(before "End Single-Byte Opcodes") +case 0xff: { + uint8_t modrm = next(); + uint8_t subop = (modrm>>3)&0x7; // middle 3 'reg opcode' bits + switch (subop) { + case 4: { // jump to r/m32 + trace(2, "run") << "jump to r/m32" << end(); + int32_t* arg2 = effective_address(modrm); + EIP = *arg2; + trace(2, "run") << "jumping to 0x" << HEXWORD << EIP << end(); + break; + } + // End Op ff Subops + } + break; +} + +//:: push + +:(scenario push_mem_at_r32) +% Reg[EAX].i = 0x60; +% Reg[ESP].u = 0x14; +== 0x01 # code segment +# op ModR/M SIB displacement immediate + ff 30 # push *EAX to stack +# ModR/M in binary: 00 (indirect mode) 110 (push r/m32) 000 (src EAX) +== 0x60 # data segment +af 00 00 00 # 0xaf ++run: push r/m32 ++run: effective address is 0x60 (EAX) ++run: decrementing ESP to 0x00000010 ++run: pushing value 0x000000af + +:(before "End Op ff Subops") +case 6: { // push r/m32 to stack + trace(2, "run") << "push r/m32" << end(); + const int32_t* val = effective_address(modrm); + push(*val); + break; +} + +//:: pop + +:(scenario pop_mem_at_r32) +% Reg[EAX].i = 0x60; +% Reg[ESP].u = 0x10; +== 0x01 # code segment +# op ModR/M SIB displacement immediate + 8f 00 # pop stack into *EAX +# ModR/M in binary: 00 (indirect mode) 000 (pop r/m32) 000 (dest EAX) +== 0x10 # data segment +30 00 00 00 # 0x30 ++run: pop into r/m32 ++run: effective address is 0x60 (EAX) ++run: popping value 0x00000030 ++run: incrementing ESP to 0x00000014 + +:(before "End Single-Byte Opcodes") +case 0x8f: { // pop stack into r/m32 + uint8_t modrm = next(); + uint8_t subop = (modrm>>3)&0x7; + switch (subop) { + case 0: { + trace(2, "run") << "pop into r/m32" << end(); + int32_t* dest = effective_address(modrm); + *dest = pop(); + break; + } + } + break; +} + +//:: special-case for loading address from disp32 rather than register + +:(scenario add_r32_to_mem_at_displacement) +% Reg[EBX].i = 0x10; // source +== 0x01 # code segment +# op ModR/M SIB displacement immediate + 01 1d 60 00 00 00 # add EBX to *0x60 +# ModR/M in binary: 00 (indirect mode) 011 (src EBX) 101 (dest in disp32) +== 0x60 # data segment +01 00 00 00 # 1 ++run: add EBX to r/m32 ++run: effective address is 0x60 (disp32) ++run: storing 0x00000011 + +:(before "End Mod 0 Special-cases(addr)") +case 5: // exception: mod 0b00 rm 0b101 => incoming disp32 + addr = imm32(); + trace(2, "run") << "effective address is 0x" << std::hex << addr << " (disp32)" << end(); + break; + +//: + +:(scenario add_r32_to_mem_at_r32_plus_disp8) +% Reg[EBX].i = 0x10; // source +% Reg[EAX].i = 0x5e; // dest +== 0x01 # code segment +# op ModR/M SIB displacement immediate + 01 58 02 # add EBX to *(EAX+2) +# ModR/M in binary: 01 (indirect+disp8 mode) 011 (src EBX) 000 (dest EAX) +== 0x60 # data segment +01 00 00 00 # 1 ++run: add EBX to r/m32 ++run: effective address is initially 0x5e (EAX) ++run: effective address is 0x60 (after adding disp8) ++run: storing 0x00000011 + +:(before "End Mod Special-cases(addr)") +case 1: // indirect + disp8 addressing + switch (rm) { + default: + addr = Reg[rm].u; + trace(2, "run") << "effective address is initially 0x" << std::hex << addr << " (" << rname(rm) << ")" << end(); + break; + // End Mod 1 Special-cases(addr) + } + if (addr > 0) { + addr += static_cast(next()); + trace(2, "run") << "effective address is 0x" << std::hex << addr << " (after adding disp8)" << end(); + } + break; + +:(scenario add_r32_to_mem_at_r32_plus_negative_disp8) +% Reg[EBX].i = 0x10; // source +% Reg[EAX].i = 0x61; // dest +== 0x01 # code segment +# op ModR/M SIB displacement immediate + 01 58 ff # add EBX to *(EAX-1) +# ModR/M in binary: 01 (indirect+disp8 mode) 011 (src EBX) 000 (dest EAX) +== 0x60 # data segment +01 00 00 00 # 1 ++run: add EBX to r/m32 ++run: effective address is initially 0x61 (EAX) ++run: effective address is 0x60 (after adding disp8) ++run: storing 0x00000011 + +//: + +:(scenario add_r32_to_mem_at_r32_plus_disp32) +% Reg[EBX].i = 0x10; // source +% Reg[EAX].i = 0x5e; // dest +== 0x01 # code segment +# op ModR/M SIB displacement immediate + 01 98 02 00 00 00 # add EBX to *(EAX+2) +# ModR/M in binary: 10 (indirect+disp32 mode) 011 (src EBX) 000 (dest EAX) +== 0x60 # data segment +01 00 00 00 # 1 ++run: add EBX to r/m32 ++run: effective address is initially 0x5e (EAX) ++run: effective address is 0x60 (after adding disp32) ++run: storing 0x00000011 + +:(before "End Mod Special-cases(addr)") +case 2: // indirect + disp32 addressing + switch (rm) { + default: + addr = Reg[rm].u; + trace(2, "run") << "effective address is initially 0x" << std::hex << addr << " (" << rname(rm) << ")" << end(); + break; + // End Mod 2 Special-cases(addr) + } + if (addr > 0) { + addr += imm32(); + trace(2, "run") << "effective address is 0x" << std::hex << addr << " (after adding disp32)" << end(); + } + break; + +:(scenario add_r32_to_mem_at_r32_plus_negative_disp32) +% Reg[EBX].i = 0x10; // source +% Reg[EAX].i = 0x61; // dest +== 0x01 # code segment +# op ModR/M SIB displacement immediate + 01 98 ff ff ff ff # add EBX to *(EAX-1) +# ModR/M in binary: 10 (indirect+disp32 mode) 011 (src EBX) 000 (dest EAX) +== 0x60 # data segment +01 00 00 00 # 1 ++run: add EBX to r/m32 ++run: effective address is initially 0x61 (EAX) ++run: effective address is 0x60 (after adding disp32) ++run: storing 0x00000011 diff --git a/subx/014immediate_addressing.cc b/subx/014immediate_addressing.cc new file mode 100644 index 00000000..c1e88f21 --- /dev/null +++ b/subx/014immediate_addressing.cc @@ -0,0 +1,425 @@ +//: instructions that (immediately) contain an argument to act with + +:(scenario add_imm32_to_r32) +% Reg[EBX].i = 1; +# op ModR/M SIB displacement immediate + 81 c3 0a 0b 0c 0d # add 0x0d0c0b0a to EBX +# ModR/M in binary: 11 (direct mode) 000 (add imm32) 011 (dest EBX) ++run: combine imm32 0x0d0c0b0a with r/m32 ++run: r/m32 is EBX ++run: subop add ++run: storing 0x0d0c0b0b + +:(before "End Single-Byte Opcodes") +case 0x81: { // combine imm32 with r/m32 + uint8_t modrm = next(); + int32_t arg2 = imm32(); + trace(2, "run") << "combine imm32 0x" << HEXWORD << arg2 << " with r/m32" << end(); + int32_t* arg1 = effective_address(modrm); + uint8_t subop = (modrm>>3)&0x7; // middle 3 'reg opcode' bits + switch (subop) { + case 0: + trace(2, "run") << "subop add" << end(); + BINARY_ARITHMETIC_OP(+, *arg1, arg2); + break; + // End Op 81 Subops + default: + cerr << "unrecognized sub-opcode after 81: " << NUM(subop) << '\n'; + exit(1); + } + break; +} + +//: + +:(scenario add_imm32_to_mem_at_r32) +% Reg[EBX].i = 0x60; +== 0x01 # code segment +# op ModR/M SIB displacement immediate + 81 03 0a 0b 0c 0d # add 0x0d0c0b0a to *EBX +# ModR/M in binary: 00 (indirect mode) 000 (add imm32) 011 (dest EBX) +== 0x60 # data segment +01 00 00 00 # 1 ++run: combine imm32 0x0d0c0b0a with r/m32 ++run: effective address is 0x60 (EBX) ++run: subop add ++run: storing 0x0d0c0b0b + +//:: subtract + +:(scenario subtract_imm32_from_eax) +% Reg[EAX].i = 0x0d0c0baa; +# op ModR/M SIB displacement immediate + 2d 0a 0b 0c 0d # subtract 0x0d0c0b0a from EAX ++run: subtract imm32 0x0d0c0b0a from EAX ++run: storing 0x000000a0 + +:(before "End Single-Byte Opcodes") +case 0x2d: { // subtract imm32 from EAX + int32_t arg2 = imm32(); + trace(2, "run") << "subtract imm32 0x" << HEXWORD << arg2 << " from EAX" << end(); + BINARY_ARITHMETIC_OP(-, Reg[EAX].i, arg2); + break; +} + +//: + +:(scenario subtract_imm32_from_mem_at_r32) +% Reg[EBX].i = 0x60; +== 0x01 # code segment +# op ModR/M SIB displacement immediate + 81 2b 01 00 00 00 # subtract 1 from *EBX +# ModR/M in binary: 00 (indirect mode) 101 (subtract imm32) 011 (dest EBX) +== 0x60 # data segment +0a 00 00 00 # 10 ++run: combine imm32 0x00000001 with r/m32 ++run: effective address is 0x60 (EBX) ++run: subop subtract ++run: storing 0x00000009 + +:(before "End Op 81 Subops") +case 5: { + trace(2, "run") << "subop subtract" << end(); + BINARY_ARITHMETIC_OP(-, *arg1, arg2); + break; +} + +//: + +:(scenario subtract_imm32_from_r32) +% Reg[EBX].i = 10; +# op ModR/M SIB displacement immediate + 81 eb 01 00 00 00 # subtract 1 from EBX +# ModR/M in binary: 11 (direct mode) 101 (subtract imm32) 011 (dest EBX) ++run: combine imm32 0x00000001 with r/m32 ++run: r/m32 is EBX ++run: subop subtract ++run: storing 0x00000009 + +//:: and + +:(scenario and_imm32_with_eax) +% Reg[EAX].i = 0xff; +# op ModR/M SIB displacement immediate + 25 0a 0b 0c 0d # and 0x0d0c0b0a with EAX ++run: and imm32 0x0d0c0b0a with EAX ++run: storing 0x0000000a + +:(before "End Single-Byte Opcodes") +case 0x25: { // and imm32 with EAX + int32_t arg2 = imm32(); + trace(2, "run") << "and imm32 0x" << HEXWORD << arg2 << " with EAX" << end(); + BINARY_BITWISE_OP(&, Reg[EAX].i, arg2); + break; +} + +//: + +:(scenario and_imm32_with_mem_at_r32) +% Reg[EBX].i = 0x60; +== 0x01 # code segment +# op ModR/M SIB displacement immediate + 81 23 0a 0b 0c 0d # and 0x0d0c0b0a with *EBX +# ModR/M in binary: 00 (indirect mode) 100 (and imm32) 011 (dest EBX) +== 0x60 # data segment +ff 00 00 00 # 0xff ++run: combine imm32 0x0d0c0b0a with r/m32 ++run: effective address is 0x60 (EBX) ++run: subop and ++run: storing 0x0000000a + +:(before "End Op 81 Subops") +case 4: { + trace(2, "run") << "subop and" << end(); + BINARY_BITWISE_OP(&, *arg1, arg2); + break; +} + +//: + +:(scenario and_imm32_with_r32) +% Reg[EBX].i = 0xff; +# op ModR/M SIB displacement immediate + 81 e3 0a 0b 0c 0d # and 0x0d0c0b0a with EBX +# ModR/M in binary: 11 (direct mode) 100 (and imm32) 011 (dest EBX) ++run: combine imm32 0x0d0c0b0a with r/m32 ++run: r/m32 is EBX ++run: subop and ++run: storing 0x0000000a + +//:: or + +:(scenario or_imm32_with_eax) +% Reg[EAX].i = 0xd0c0b0a0; +# op ModR/M SIB displacement immediate + 0d 0a 0b 0c 0d # or 0x0d0c0b0a with EAX ++run: or imm32 0x0d0c0b0a with EAX ++run: storing 0xddccbbaa + +:(before "End Single-Byte Opcodes") +case 0x0d: { // or imm32 with EAX + int32_t arg2 = imm32(); + trace(2, "run") << "or imm32 0x" << HEXWORD << arg2 << " with EAX" << end(); + BINARY_BITWISE_OP(|, Reg[EAX].i, arg2); + break; +} + +//: + +:(scenario or_imm32_with_mem_at_r32) +% Reg[EBX].i = 0x60; +== 0x01 # code segment +# op ModR/M SIB displacement immediate + 81 0b 0a 0b 0c 0d # or 0x0d0c0b0a with *EBX +# ModR/M in binary: 00 (indirect mode) 001 (or imm32) 011 (dest EBX) +== 0x60 # data segment +a0 b0 c0 d0 # 0xd0c0b0a0 ++run: combine imm32 0x0d0c0b0a with r/m32 ++run: effective address is 0x60 (EBX) ++run: subop or ++run: storing 0xddccbbaa + +:(before "End Op 81 Subops") +case 1: { + trace(2, "run") << "subop or" << end(); + BINARY_BITWISE_OP(|, *arg1, arg2); + break; +} + +:(scenario or_imm32_with_r32) +% Reg[EBX].i = 0xd0c0b0a0; +# op ModR/M SIB displacement immediate + 81 cb 0a 0b 0c 0d # or 0x0d0c0b0a with EBX +# ModR/M in binary: 11 (direct mode) 001 (or imm32) 011 (dest EBX) ++run: combine imm32 0x0d0c0b0a with r/m32 ++run: r/m32 is EBX ++run: subop or ++run: storing 0xddccbbaa + +//:: xor + +:(scenario xor_imm32_with_eax) +% Reg[EAX].i = 0xddccb0a0; +# op ModR/M SIB displacement immediate + 35 0a 0b 0c 0d # xor 0x0d0c0b0a with EAX ++run: xor imm32 0x0d0c0b0a with EAX ++run: storing 0xd0c0bbaa + +:(before "End Single-Byte Opcodes") +case 0x35: { // xor imm32 with EAX + int32_t arg2 = imm32(); + trace(2, "run") << "xor imm32 0x" << HEXWORD << arg2 << " with EAX" << end(); + BINARY_BITWISE_OP(^, Reg[EAX].i, arg2); + break; +} + +//: + +:(scenario xor_imm32_with_mem_at_r32) +% Reg[EBX].i = 0x60; +== 0x01 # code segment +# op ModR/M SIB displacement immediate + 81 33 0a 0b 0c 0d # xor 0x0d0c0b0a with *EBX +# ModR/M in binary: 00 (indirect mode) 110 (xor imm32) 011 (dest EBX) +== 0x60 # data segment +a0 b0 c0 d0 # 0xd0c0b0a0 ++run: combine imm32 0x0d0c0b0a with r/m32 ++run: effective address is 0x60 (EBX) ++run: subop xor ++run: storing 0xddccbbaa + +:(before "End Op 81 Subops") +case 6: { + trace(2, "run") << "subop xor" << end(); + BINARY_BITWISE_OP(^, *arg1, arg2); + break; +} + +:(scenario xor_imm32_with_r32) +% Reg[EBX].i = 0xd0c0b0a0; +# op ModR/M SIB displacement immediate + 81 f3 0a 0b 0c 0d # xor 0x0d0c0b0a with EBX +# ModR/M in binary: 11 (direct mode) 110 (xor imm32) 011 (dest EBX) ++run: combine imm32 0x0d0c0b0a with r/m32 ++run: r/m32 is EBX ++run: subop xor ++run: storing 0xddccbbaa + +//:: compare (cmp) + +:(scenario compare_imm32_with_eax_greater) +% Reg[EAX].i = 0x0d0c0b0a; +# op ModR/M SIB displacement immediate + 3d 07 0b 0c 0d # compare 0x0d0c0b07 with EAX ++run: compare EAX and imm32 0x0d0c0b07 ++run: SF=0; ZF=0; OF=0 + +:(before "End Single-Byte Opcodes") +case 0x3d: { // subtract imm32 from EAX + int32_t arg1 = Reg[EAX].i; + int32_t arg2 = imm32(); + trace(2, "run") << "compare EAX and imm32 0x" << HEXWORD << arg2 << end(); + int32_t tmp1 = arg1 - arg2; + SF = (tmp1 < 0); + ZF = (tmp1 == 0); + int64_t tmp2 = arg1 - arg2; + OF = (tmp1 != tmp2); + trace(2, "run") << "SF=" << SF << "; ZF=" << ZF << "; OF=" << OF << end(); + break; +} + +:(scenario compare_imm32_with_eax_lesser) +% Reg[EAX].i = 0x0d0c0b07; +# op ModR/M SIB displacement immediate + 3d 0a 0b 0c 0d # compare 0x0d0c0b0a with EAX ++run: compare EAX and imm32 0x0d0c0b0a ++run: SF=1; ZF=0; OF=0 + +:(scenario compare_imm32_with_eax_equal) +% Reg[EAX].i = 0x0d0c0b0a; +# op ModR/M SIB displacement immediate + 3d 0a 0b 0c 0d # compare 0x0d0c0b0a with EAX ++run: compare EAX and imm32 0x0d0c0b0a ++run: SF=0; ZF=1; OF=0 + +//: + +:(scenario compare_imm32_with_r32_greater) +% Reg[EBX].i = 0x0d0c0b0a; +# op ModR/M SIB displacement immediate + 81 fb 07 0b 0c 0d # compare 0x0d0c0b07 with EBX +# ModR/M in binary: 11 (direct mode) 111 (compare imm32) 011 (dest EBX) ++run: combine imm32 0x0d0c0b07 with r/m32 ++run: r/m32 is EBX ++run: SF=0; ZF=0; OF=0 + +:(before "End Op 81 Subops") +case 7: { + trace(2, "run") << "subop compare" << end(); + int32_t tmp1 = *arg1 - arg2; + SF = (tmp1 < 0); + ZF = (tmp1 == 0); + int64_t tmp2 = *arg1 - arg2; + OF = (tmp1 != tmp2); + trace(2, "run") << "SF=" << SF << "; ZF=" << ZF << "; OF=" << OF << end(); + break; +} + +:(scenario compare_imm32_with_r32_lesser) +% Reg[EBX].i = 0x0d0c0b07; +# op ModR/M SIB displacement immediate + 81 fb 0a 0b 0c 0d # compare 0x0d0c0b0a with EBX +# ModR/M in binary: 11 (direct mode) 111 (compare imm32) 011 (dest EBX) ++run: combine imm32 0x0d0c0b0a with r/m32 ++run: r/m32 is EBX ++run: SF=1; ZF=0; OF=0 + +:(scenario compare_imm32_with_r32_equal) +% Reg[EBX].i = 0x0d0c0b0a; +# op ModR/M SIB displacement immediate + 81 fb 0a 0b 0c 0d # compare 0x0d0c0b0a with EBX +# ModR/M in binary: 11 (direct mode) 111 (compare imm32) 011 (dest EBX) ++run: combine imm32 0x0d0c0b0a with r/m32 ++run: r/m32 is EBX ++run: SF=0; ZF=1; OF=0 + +:(scenario compare_imm32_with_mem_at_r32_greater) +% Reg[EBX].i = 0x60; +== 0x01 # code segment +# op ModR/M SIB displacement immediate + 81 3b 07 0b 0c 0d # compare 0x0d0c0b07 with *EBX +# ModR/M in binary: 00 (indirect mode) 111 (compare imm32) 011 (dest EBX) +== 0x60 # data segment +0a 0b 0c 0d # 0x0d0c0b0a ++run: combine imm32 0x0d0c0b07 with r/m32 ++run: effective address is 0x60 (EBX) ++run: SF=0; ZF=0; OF=0 + +:(scenario compare_imm32_with_mem_at_r32_lesser) +% Reg[EBX].i = 0x60; +== 0x01 # code segment +# op ModR/M SIB displacement immediate + 81 3b 0a 0b 0c 0d # compare 0x0d0c0b0a with *EBX +# ModR/M in binary: 00 (indirect mode) 111 (compare imm32) 011 (dest EBX) +== 0x60 # data segment +07 0b 0c 0d # 0x0d0c0b07 ++run: combine imm32 0x0d0c0b0a with r/m32 ++run: effective address is 0x60 (EBX) ++run: SF=1; ZF=0; OF=0 + +:(scenario compare_imm32_with_mem_at_r32_equal) +% Reg[EBX].i = 0x0d0c0b0a; +% Reg[EBX].i = 0x60; +== 0x01 # code segment +# op ModR/M SIB displacement immediate + 81 3b 0a 0b 0c 0d # compare 0x0d0c0b0a with *EBX +# ModR/M in binary: 00 (indirect mode) 111 (compare imm32) 011 (dest EBX) +== 0x60 # data segment +0a 0b 0c 0d # 0x0d0c0b0a ++run: combine imm32 0x0d0c0b0a with r/m32 ++run: effective address is 0x60 (EBX) ++run: SF=0; ZF=1; OF=0 + +//:: copy (mov) + +:(scenario copy_imm32_to_r32) +# op ModR/M SIB displacement immediate + bb 0a 0b 0c 0d # copy 0x0d0c0b0a to EBX ++run: copy imm32 0x0d0c0b0a to EBX + +:(before "End Single-Byte Opcodes") +case 0xb8: +case 0xb9: +case 0xba: +case 0xbb: +case 0xbc: +case 0xbd: +case 0xbe: +case 0xbf: { // copy imm32 to r32 + uint8_t reg1 = op & 0x7; + int32_t arg2 = imm32(); + trace(2, "run") << "copy imm32 0x" << HEXWORD << arg2 << " to " << rname(reg1) << end(); + Reg[reg1].i = arg2; + break; +} + +//: + +:(scenario copy_imm32_to_mem_at_r32) +% Reg[EBX].i = 0x60; +# op ModR/M SIB displacement immediate + c7 03 0a 0b 0c 0d # copy 0x0d0c0b0a to *EBX +# ModR/M in binary: 00 (indirect mode) 000 (unused) 011 (dest EBX) ++run: copy imm32 0x0d0c0b0a to r/m32 ++run: effective address is 0x60 (EBX) + +:(before "End Single-Byte Opcodes") +case 0xc7: { // copy imm32 to r32 + uint8_t modrm = next(); + int32_t arg2 = imm32(); + trace(2, "run") << "copy imm32 0x" << HEXWORD << arg2 << " to r/m32" << end(); + int32_t* arg1 = effective_address(modrm); + *arg1 = arg2; + break; +} + +//:: push + +:(scenario push_imm32) +% Reg[ESP].u = 0x14; +# op ModR/M SIB displacement immediate + 68 af 00 00 00 # push *EAX to stack ++run: push imm32 0x000000af ++run: ESP is now 0x00000010 ++run: contents at ESP: 0x000000af + +:(before "End Single-Byte Opcodes") +case 0x68: { + int32_t val = imm32(); + trace(2, "run") << "push imm32 0x" << HEXWORD << val << end(); + Reg[ESP].u -= 4; + write_mem_i32(Reg[ESP].u, val); + trace(2, "run") << "ESP is now 0x" << HEXWORD << Reg[ESP].u << end(); + trace(2, "run") << "contents at ESP: 0x" << HEXWORD << read_mem_u32(Reg[ESP].u) << end(); + break; +} diff --git a/subx/014index_addressing.cc b/subx/014index_addressing.cc deleted file mode 100644 index 13287709..00000000 --- a/subx/014index_addressing.cc +++ /dev/null @@ -1,125 +0,0 @@ -//: operating on memory at the address provided by some register plus optional scale and offset - -:(scenario add_r32_to_mem_at_r32_with_sib) -% Reg[EBX].i = 0x10; -% Reg[EAX].i = 0x60; -== 0x1 # code segment -# op ModR/M SIB displacement immediate - 01 1c 20 # add EBX to *EAX -# ModR/M in binary: 00 (indirect mode) 011 (src EBX) 100 (dest in SIB) -# SIB in binary: 00 (scale 1) 100 (no index) 000 (base EAX) -== 0x60 # data segment -01 00 00 00 # 1 -+run: add EBX to r/m32 -+run: effective address is initially 0x60 (EAX) -+run: effective address is 0x60 -+run: storing 0x00000011 - -:(before "End Mod 0 Special-cases(addr)") -case 4: // exception: mod 0b00 rm 0b100 => incoming SIB (scale-index-base) byte - addr = effective_address_from_sib(mod); - break; -:(code) -uint32_t effective_address_from_sib(uint8_t mod) { - uint8_t sib = next(); - uint8_t base = sib&0x7; - uint32_t addr = 0; - if (base != EBP || mod != 0) { - addr = Reg[base].u; - trace(2, "run") << "effective address is initially 0x" << std::hex << addr << " (" << rname(base) << ")" << end(); - } - else { - // base == EBP && mod == 0 - addr = imm32(); // ignore base - trace(2, "run") << "effective address is initially 0x" << std::hex << addr << " (disp32)" << end(); - } - uint8_t index = (sib>>3)&0x7; - if (index == ESP) { - // ignore index and scale - trace(2, "run") << "effective address is 0x" << std::hex << addr << end(); - } - else { - uint8_t scale = (1 << (sib>>6)); - addr += Reg[index].i*scale; // treat index register as signed. Maybe base as well? But we'll always ensure it's non-negative. - trace(2, "run") << "effective address is 0x" << std::hex << addr << " (after adding " << rname(index) << "*" << NUM(scale) << ")" << end(); - } - return addr; -} - -:(scenario add_r32_to_mem_at_base_r32_index_r32) -% Reg[EBX].i = 0x10; // source -% Reg[EAX].i = 0x5e; // dest base -% Reg[ECX].i = 0x2; // dest index -== 0x1 # code segment -# op ModR/M SIB displacement immediate - 01 1c 08 # add EBX to *(EAX+ECX) -# ModR/M in binary: 00 (indirect mode) 011 (src EBX) 100 (dest in SIB) -# SIB in binary: 00 (scale 1) 001 (index ECX) 000 (base EAX) -== 0x60 # data segment -01 00 00 00 # 1 -+run: add EBX to r/m32 -+run: effective address is initially 0x5e (EAX) -+run: effective address is 0x60 (after adding ECX*1) -+run: storing 0x00000011 - -:(scenario add_r32_to_mem_at_displacement_using_sib) -% Reg[EBX].i = 0x10; // source -== 0x1 # code segment -# op ModR/M SIB displacement immediate - 01 1c 25 60 00 00 00 # add EBX to *0x60 -# ModR/M in binary: 00 (indirect mode) 011 (src EBX) 100 (dest in SIB) -# SIB in binary: 00 (scale 1) 100 (no index) 101 (not EBP but disp32) -== 0x60 # data segment -01 00 00 00 # 1 -+run: add EBX to r/m32 -+run: effective address is initially 0x60 (disp32) -+run: effective address is 0x60 -+run: storing 0x00000011 - -//: - -:(scenario add_r32_to_mem_at_base_r32_index_r32_plus_disp8) -% Reg[EBX].i = 0x10; // source -% Reg[EAX].i = 0x59; // dest base -% Reg[ECX].i = 0x5; // dest index -== 0x1 # code segment -# op ModR/M SIB displacement immediate - 01 5c 08 02 # add EBX to *(EAX+ECX+2) -# ModR/M in binary: 01 (indirect+disp8 mode) 011 (src EBX) 100 (dest in SIB) -# SIB in binary: 00 (scale 1) 001 (index ECX) 000 (base EAX) -== 0x60 # data segment -01 00 00 00 # 1 -+run: add EBX to r/m32 -+run: effective address is initially 0x59 (EAX) -+run: effective address is 0x5e (after adding ECX*1) -+run: effective address is 0x60 (after adding disp8) -+run: storing 0x00000011 - -:(before "End Mod 1 Special-cases(addr)") -case 4: // exception: mod 0b01 rm 0b100 => incoming SIB (scale-index-base) byte - addr = effective_address_from_sib(mod); - break; - -//: - -:(scenario add_r32_to_mem_at_base_r32_index_r32_plus_disp32) -% Reg[EBX].i = 0x10; // source -% Reg[EAX].i = 0x59; // dest base -% Reg[ECX].i = 0x5; // dest index -== 0x1 # code segment -# op ModR/M SIB displacement immediate - 01 9c 08 02 00 00 00 # add EBX to *(EAX+ECX+2) -# ModR/M in binary: 10 (indirect+disp32 mode) 011 (src EBX) 100 (dest in SIB) -# SIB in binary: 00 (scale 1) 001 (index ECX) 000 (base EAX) -== 0x60 # data segment -01 00 00 00 # 1 -+run: add EBX to r/m32 -+run: effective address is initially 0x59 (EAX) -+run: effective address is 0x5e (after adding ECX*1) -+run: effective address is 0x60 (after adding disp32) -+run: storing 0x00000011 - -:(before "End Mod 2 Special-cases(addr)") -case 4: // exception: mod 0b10 rm 0b100 => incoming SIB (scale-index-base) byte - addr = effective_address_from_sib(mod); - break; diff --git a/subx/015index_addressing.cc b/subx/015index_addressing.cc new file mode 100644 index 00000000..13287709 --- /dev/null +++ b/subx/015index_addressing.cc @@ -0,0 +1,125 @@ +//: operating on memory at the address provided by some register plus optional scale and offset + +:(scenario add_r32_to_mem_at_r32_with_sib) +% Reg[EBX].i = 0x10; +% Reg[EAX].i = 0x60; +== 0x1 # code segment +# op ModR/M SIB displacement immediate + 01 1c 20 # add EBX to *EAX +# ModR/M in binary: 00 (indirect mode) 011 (src EBX) 100 (dest in SIB) +# SIB in binary: 00 (scale 1) 100 (no index) 000 (base EAX) +== 0x60 # data segment +01 00 00 00 # 1 ++run: add EBX to r/m32 ++run: effective address is initially 0x60 (EAX) ++run: effective address is 0x60 ++run: storing 0x00000011 + +:(before "End Mod 0 Special-cases(addr)") +case 4: // exception: mod 0b00 rm 0b100 => incoming SIB (scale-index-base) byte + addr = effective_address_from_sib(mod); + break; +:(code) +uint32_t effective_address_from_sib(uint8_t mod) { + uint8_t sib = next(); + uint8_t base = sib&0x7; + uint32_t addr = 0; + if (base != EBP || mod != 0) { + addr = Reg[base].u; + trace(2, "run") << "effective address is initially 0x" << std::hex << addr << " (" << rname(base) << ")" << end(); + } + else { + // base == EBP && mod == 0 + addr = imm32(); // ignore base + trace(2, "run") << "effective address is initially 0x" << std::hex << addr << " (disp32)" << end(); + } + uint8_t index = (sib>>3)&0x7; + if (index == ESP) { + // ignore index and scale + trace(2, "run") << "effective address is 0x" << std::hex << addr << end(); + } + else { + uint8_t scale = (1 << (sib>>6)); + addr += Reg[index].i*scale; // treat index register as signed. Maybe base as well? But we'll always ensure it's non-negative. + trace(2, "run") << "effective address is 0x" << std::hex << addr << " (after adding " << rname(index) << "*" << NUM(scale) << ")" << end(); + } + return addr; +} + +:(scenario add_r32_to_mem_at_base_r32_index_r32) +% Reg[EBX].i = 0x10; // source +% Reg[EAX].i = 0x5e; // dest base +% Reg[ECX].i = 0x2; // dest index +== 0x1 # code segment +# op ModR/M SIB displacement immediate + 01 1c 08 # add EBX to *(EAX+ECX) +# ModR/M in binary: 00 (indirect mode) 011 (src EBX) 100 (dest in SIB) +# SIB in binary: 00 (scale 1) 001 (index ECX) 000 (base EAX) +== 0x60 # data segment +01 00 00 00 # 1 ++run: add EBX to r/m32 ++run: effective address is initially 0x5e (EAX) ++run: effective address is 0x60 (after adding ECX*1) ++run: storing 0x00000011 + +:(scenario add_r32_to_mem_at_displacement_using_sib) +% Reg[EBX].i = 0x10; // source +== 0x1 # code segment +# op ModR/M SIB displacement immediate + 01 1c 25 60 00 00 00 # add EBX to *0x60 +# ModR/M in binary: 00 (indirect mode) 011 (src EBX) 100 (dest in SIB) +# SIB in binary: 00 (scale 1) 100 (no index) 101 (not EBP but disp32) +== 0x60 # data segment +01 00 00 00 # 1 ++run: add EBX to r/m32 ++run: effective address is initially 0x60 (disp32) ++run: effective address is 0x60 ++run: storing 0x00000011 + +//: + +:(scenario add_r32_to_mem_at_base_r32_index_r32_plus_disp8) +% Reg[EBX].i = 0x10; // source +% Reg[EAX].i = 0x59; // dest base +% Reg[ECX].i = 0x5; // dest index +== 0x1 # code segment +# op ModR/M SIB displacement immediate + 01 5c 08 02 # add EBX to *(EAX+ECX+2) +# ModR/M in binary: 01 (indirect+disp8 mode) 011 (src EBX) 100 (dest in SIB) +# SIB in binary: 00 (scale 1) 001 (index ECX) 000 (base EAX) +== 0x60 # data segment +01 00 00 00 # 1 ++run: add EBX to r/m32 ++run: effective address is initially 0x59 (EAX) ++run: effective address is 0x5e (after adding ECX*1) ++run: effective address is 0x60 (after adding disp8) ++run: storing 0x00000011 + +:(before "End Mod 1 Special-cases(addr)") +case 4: // exception: mod 0b01 rm 0b100 => incoming SIB (scale-index-base) byte + addr = effective_address_from_sib(mod); + break; + +//: + +:(scenario add_r32_to_mem_at_base_r32_index_r32_plus_disp32) +% Reg[EBX].i = 0x10; // source +% Reg[EAX].i = 0x59; // dest base +% Reg[ECX].i = 0x5; // dest index +== 0x1 # code segment +# op ModR/M SIB displacement immediate + 01 9c 08 02 00 00 00 # add EBX to *(EAX+ECX+2) +# ModR/M in binary: 10 (indirect+disp32 mode) 011 (src EBX) 100 (dest in SIB) +# SIB in binary: 00 (scale 1) 001 (index ECX) 000 (base EAX) +== 0x60 # data segment +01 00 00 00 # 1 ++run: add EBX to r/m32 ++run: effective address is initially 0x59 (EAX) ++run: effective address is 0x5e (after adding ECX*1) ++run: effective address is 0x60 (after adding disp32) ++run: storing 0x00000011 + +:(before "End Mod 2 Special-cases(addr)") +case 4: // exception: mod 0b10 rm 0b100 => incoming SIB (scale-index-base) byte + addr = effective_address_from_sib(mod); + break; diff --git a/subx/015jump_relative.cc b/subx/015jump_relative.cc deleted file mode 100644 index 2d3bbb2b..00000000 --- a/subx/015jump_relative.cc +++ /dev/null @@ -1,252 +0,0 @@ -//: jump to 8-bit offset - -//:: jump - -:(scenario jump_rel8) -# op ModR/M SIB displacement immediate - eb 05 # skip 1 instruction - 05 00 00 00 01 - 05 00 00 00 02 -+run: inst: 0x00000001 -+run: jump 5 -+run: inst: 0x00000008 --run: inst: 0x00000003 - -:(before "End Single-Byte Opcodes") -case 0xeb: { // jump rel8 - int8_t offset = static_cast(next()); - trace(2, "run") << "jump " << NUM(offset) << end(); - EIP += offset; - break; -} - -//:: jump if equal/zero - -:(scenario je_rel8_success) -% ZF = true; -# op ModR/M SIB displacement immediate - 74 05 # skip 1 instruction - 05 00 00 00 01 - 05 00 00 00 02 -+run: inst: 0x00000001 -+run: jump 5 -+run: inst: 0x00000008 --run: inst: 0x00000003 - -:(before "End Single-Byte Opcodes") -case 0x74: { // jump rel8 if ZF - int8_t offset = static_cast(next()); - if (ZF) { - trace(2, "run") << "jump " << NUM(offset) << end(); - EIP += offset; - } - break; -} - -:(scenario je_rel8_fail) -% ZF = false; -# op ModR/M SIB displacement immediate - 74 05 # skip 1 instruction - 05 00 00 00 01 - 05 00 00 00 02 -+run: inst: 0x00000001 -+run: inst: 0x00000003 -+run: inst: 0x00000008 --run: jump 5 - -//:: jump if not equal/not zero - -:(scenario jne_rel8_success) -% ZF = false; -# op ModR/M SIB displacement immediate - 75 05 # skip 1 instruction - 05 00 00 00 01 - 05 00 00 00 02 -+run: inst: 0x00000001 -+run: jump 5 -+run: inst: 0x00000008 --run: inst: 0x00000003 - -:(before "End Single-Byte Opcodes") -case 0x75: { // jump rel8 unless ZF - int8_t offset = static_cast(next()); - if (!ZF) { - trace(2, "run") << "jump " << NUM(offset) << end(); - EIP += offset; - } - break; -} - -:(scenario jne_rel8_fail) -% ZF = true; -# op ModR/M SIB displacement immediate - 75 05 # skip 1 instruction - 05 00 00 00 01 - 05 00 00 00 02 -+run: inst: 0x00000001 -+run: inst: 0x00000003 -+run: inst: 0x00000008 --run: jump 5 - -//:: jump if greater - -:(scenario jg_rel8_success) -% ZF = false; -% SF = false; -% OF = false; -# op ModR/M SIB displacement immediate - 7f 05 # skip 1 instruction - 05 00 00 00 01 - 05 00 00 00 02 -+run: inst: 0x00000001 -+run: jump 5 -+run: inst: 0x00000008 --run: inst: 0x00000003 - -:(before "End Single-Byte Opcodes") -case 0x7f: { // jump rel8 if !SF and !ZF - int8_t offset = static_cast(next()); - if (!ZF && SF == OF) { - trace(2, "run") << "jump " << NUM(offset) << end(); - EIP += offset; - } - break; -} - -:(scenario jg_rel8_fail) -% ZF = false; -% SF = true; -% OF = false; -# op ModR/M SIB displacement immediate - 7f 05 # skip 1 instruction - 05 00 00 00 01 - 05 00 00 00 02 -+run: inst: 0x00000001 -+run: inst: 0x00000003 -+run: inst: 0x00000008 --run: jump 5 - -//:: jump if greater or equal - -:(scenario jge_rel8_success) -% SF = false; -% OF = false; -# op ModR/M SIB displacement immediate - 7d 05 # skip 1 instruction - 05 00 00 00 01 - 05 00 00 00 02 -+run: inst: 0x00000001 -+run: jump 5 -+run: inst: 0x00000008 --run: inst: 0x00000003 - -:(before "End Single-Byte Opcodes") -case 0x7d: { // jump rel8 if !SF - int8_t offset = static_cast(next()); - if (SF == OF) { - trace(2, "run") << "jump " << NUM(offset) << end(); - EIP += offset; - } - break; -} - -:(scenario jge_rel8_fail) -% SF = true; -% OF = false; -# op ModR/M SIB displacement immediate - 7d 05 # skip 1 instruction - 05 00 00 00 01 - 05 00 00 00 02 -+run: inst: 0x00000001 -+run: inst: 0x00000003 -+run: inst: 0x00000008 --run: jump 5 - -//:: jump if lesser - -:(scenario jl_rel8_success) -% ZF = false; -% SF = true; -% OF = false; -# op ModR/M SIB displacement immediate - 7c 05 # skip 1 instruction - 05 00 00 00 01 - 05 00 00 00 02 -+run: inst: 0x00000001 -+run: jump 5 -+run: inst: 0x00000008 --run: inst: 0x00000003 - -:(before "End Single-Byte Opcodes") -case 0x7c: { // jump rel8 if SF and !ZF - int8_t offset = static_cast(next()); - if (SF != OF) { - trace(2, "run") << "jump " << NUM(offset) << end(); - EIP += offset; - } - break; -} - -:(scenario jl_rel8_fail) -% ZF = false; -% SF = false; -% OF = false; -# op ModR/M SIB displacement immediate - 7c 05 # skip 1 instruction - 05 00 00 00 01 - 05 00 00 00 02 -+run: inst: 0x00000001 -+run: inst: 0x00000003 -+run: inst: 0x00000008 --run: jump 5 - -//:: jump if lesser or equal - -:(scenario jle_rel8_equal) -% ZF = true; -% SF = false; -% OF = false; -# op ModR/M SIB displacement immediate - 7e 05 # skip 1 instruction - 05 00 00 00 01 - 05 00 00 00 02 -+run: inst: 0x00000001 -+run: jump 5 -+run: inst: 0x00000008 --run: inst: 0x00000003 - -:(scenario jle_rel8_lesser) -% ZF = false; -% SF = true; -% OF = false; -# op ModR/M SIB displacement immediate - 7e 05 # skip 1 instruction - 05 00 00 00 01 - 05 00 00 00 02 -+run: inst: 0x00000001 -+run: jump 5 -+run: inst: 0x00000008 --run: inst: 0x00000003 - -:(before "End Single-Byte Opcodes") -case 0x7e: { // jump rel8 if SF or ZF - int8_t offset = static_cast(next()); - if (ZF || SF != OF) { - trace(2, "run") << "jump " << NUM(offset) << end(); - EIP += offset; - } - break; -} - -:(scenario jle_rel8_greater) -% ZF = false; -% SF = false; -% OF = false; -# op ModR/M SIB displacement immediate - 7e 05 # skip 1 instruction - 05 00 00 00 01 - 05 00 00 00 02 -+run: inst: 0x00000001 -+run: inst: 0x00000003 -+run: inst: 0x00000008 --run: jump 5 diff --git a/subx/016jump_relative.cc b/subx/016jump_relative.cc index 8b8452bb..2d3bbb2b 100644 --- a/subx/016jump_relative.cc +++ b/subx/016jump_relative.cc @@ -1,47 +1,41 @@ -//: jump to 16-bit offset +//: jump to 8-bit offset //:: jump -:(scenario jump_rel16) +:(scenario jump_rel8) # op ModR/M SIB displacement immediate - e9 05 00 # skip 1 instruction + eb 05 # skip 1 instruction 05 00 00 00 01 05 00 00 00 02 +run: inst: 0x00000001 +run: jump 5 -+run: inst: 0x00000009 ++run: inst: 0x00000008 -run: inst: 0x00000003 :(before "End Single-Byte Opcodes") -case 0xe9: { // jump rel8 - int16_t offset = imm16(); - trace(2, "run") << "jump " << offset << end(); +case 0xeb: { // jump rel8 + int8_t offset = static_cast(next()); + trace(2, "run") << "jump " << NUM(offset) << end(); EIP += offset; break; } -:(code) -int16_t imm16() { - int16_t result = next(); - result |= (next()<<8); - return result; -} //:: jump if equal/zero -:(scenario je_rel16_success) +:(scenario je_rel8_success) % ZF = true; -# op ModR/M SIB displacement immediate - 0f 84 05 00 # skip 1 instruction - 05 00 00 00 01 - 05 00 00 00 02 +# op ModR/M SIB displacement immediate + 74 05 # skip 1 instruction + 05 00 00 00 01 + 05 00 00 00 02 +run: inst: 0x00000001 +run: jump 5 -+run: inst: 0x0000000a --run: inst: 0x00000005 ++run: inst: 0x00000008 +-run: inst: 0x00000003 -:(before "End Two-Byte Opcodes Starting With 0f") -case 0x84: { // jump rel16 if ZF - int8_t offset = imm16(); +:(before "End Single-Byte Opcodes") +case 0x74: { // jump rel8 if ZF + int8_t offset = static_cast(next()); if (ZF) { trace(2, "run") << "jump " << NUM(offset) << end(); EIP += offset; @@ -49,33 +43,33 @@ case 0x84: { // jump rel16 if ZF break; } -:(scenario je_rel16_fail) +:(scenario je_rel8_fail) % ZF = false; -# op ModR/M SIB displacement immediate - 0f 84 05 00 # skip 1 instruction - 05 00 00 00 01 - 05 00 00 00 02 +# op ModR/M SIB displacement immediate + 74 05 # skip 1 instruction + 05 00 00 00 01 + 05 00 00 00 02 +run: inst: 0x00000001 -+run: inst: 0x00000005 -+run: inst: 0x0000000a ++run: inst: 0x00000003 ++run: inst: 0x00000008 -run: jump 5 //:: jump if not equal/not zero -:(scenario jne_rel16_success) +:(scenario jne_rel8_success) % ZF = false; -# op ModR/M SIB displacement immediate - 0f 85 05 00 # skip 1 instruction - 05 00 00 00 01 - 05 00 00 00 02 +# op ModR/M SIB displacement immediate + 75 05 # skip 1 instruction + 05 00 00 00 01 + 05 00 00 00 02 +run: inst: 0x00000001 +run: jump 5 -+run: inst: 0x0000000a --run: inst: 0x00000005 ++run: inst: 0x00000008 +-run: inst: 0x00000003 -:(before "End Two-Byte Opcodes Starting With 0f") -case 0x85: { // jump rel16 unless ZF - int8_t offset = imm16(); +:(before "End Single-Byte Opcodes") +case 0x75: { // jump rel8 unless ZF + int8_t offset = static_cast(next()); if (!ZF) { trace(2, "run") << "jump " << NUM(offset) << end(); EIP += offset; @@ -83,35 +77,35 @@ case 0x85: { // jump rel16 unless ZF break; } -:(scenario jne_rel16_fail) +:(scenario jne_rel8_fail) % ZF = true; -# op ModR/M SIB displacement immediate - 0f 85 05 00 # skip 1 instruction - 05 00 00 00 01 - 05 00 00 00 02 +# op ModR/M SIB displacement immediate + 75 05 # skip 1 instruction + 05 00 00 00 01 + 05 00 00 00 02 +run: inst: 0x00000001 -+run: inst: 0x00000005 -+run: inst: 0x0000000a ++run: inst: 0x00000003 ++run: inst: 0x00000008 -run: jump 5 //:: jump if greater -:(scenario jg_rel16_success) +:(scenario jg_rel8_success) % ZF = false; % SF = false; % OF = false; -# op ModR/M SIB displacement immediate - 0f 8f 05 00 # skip 1 instruction - 05 00 00 00 01 - 05 00 00 00 02 +# op ModR/M SIB displacement immediate + 7f 05 # skip 1 instruction + 05 00 00 00 01 + 05 00 00 00 02 +run: inst: 0x00000001 +run: jump 5 -+run: inst: 0x0000000a --run: inst: 0x00000005 ++run: inst: 0x00000008 +-run: inst: 0x00000003 -:(before "End Two-Byte Opcodes Starting With 0f") -case 0x8f: { // jump rel16 if !SF and !ZF - int8_t offset = imm16(); +:(before "End Single-Byte Opcodes") +case 0x7f: { // jump rel8 if !SF and !ZF + int8_t offset = static_cast(next()); if (!ZF && SF == OF) { trace(2, "run") << "jump " << NUM(offset) << end(); EIP += offset; @@ -119,36 +113,36 @@ case 0x8f: { // jump rel16 if !SF and !ZF break; } -:(scenario jg_rel16_fail) +:(scenario jg_rel8_fail) % ZF = false; % SF = true; % OF = false; -# op ModR/M SIB displacement immediate - 0f 8f 05 00 # skip 1 instruction - 05 00 00 00 01 - 05 00 00 00 02 +# op ModR/M SIB displacement immediate + 7f 05 # skip 1 instruction + 05 00 00 00 01 + 05 00 00 00 02 +run: inst: 0x00000001 -+run: inst: 0x00000005 -+run: inst: 0x0000000a ++run: inst: 0x00000003 ++run: inst: 0x00000008 -run: jump 5 //:: jump if greater or equal -:(scenario jge_rel16_success) +:(scenario jge_rel8_success) % SF = false; % OF = false; -# op ModR/M SIB displacement immediate - 0f 8d 05 00 # skip 1 instruction - 05 00 00 00 01 - 05 00 00 00 02 +# op ModR/M SIB displacement immediate + 7d 05 # skip 1 instruction + 05 00 00 00 01 + 05 00 00 00 02 +run: inst: 0x00000001 +run: jump 5 -+run: inst: 0x0000000a --run: inst: 0x00000005 ++run: inst: 0x00000008 +-run: inst: 0x00000003 -:(before "End Two-Byte Opcodes Starting With 0f") -case 0x8d: { // jump rel16 if !SF - int8_t offset = imm16(); +:(before "End Single-Byte Opcodes") +case 0x7d: { // jump rel8 if !SF + int8_t offset = static_cast(next()); if (SF == OF) { trace(2, "run") << "jump " << NUM(offset) << end(); EIP += offset; @@ -156,36 +150,36 @@ case 0x8d: { // jump rel16 if !SF break; } -:(scenario jge_rel16_fail) +:(scenario jge_rel8_fail) % SF = true; % OF = false; -# op ModR/M SIB displacement immediate - 0f 8d 05 00 # skip 1 instruction - 05 00 00 00 01 - 05 00 00 00 02 +# op ModR/M SIB displacement immediate + 7d 05 # skip 1 instruction + 05 00 00 00 01 + 05 00 00 00 02 +run: inst: 0x00000001 -+run: inst: 0x00000005 -+run: inst: 0x0000000a ++run: inst: 0x00000003 ++run: inst: 0x00000008 -run: jump 5 //:: jump if lesser -:(scenario jl_rel16_success) +:(scenario jl_rel8_success) % ZF = false; % SF = true; % OF = false; -# op ModR/M SIB displacement immediate - 0f 8c 05 00 # skip 1 instruction - 05 00 00 00 01 - 05 00 00 00 02 +# op ModR/M SIB displacement immediate + 7c 05 # skip 1 instruction + 05 00 00 00 01 + 05 00 00 00 02 +run: inst: 0x00000001 +run: jump 5 -+run: inst: 0x0000000a --run: inst: 0x00000005 ++run: inst: 0x00000008 +-run: inst: 0x00000003 -:(before "End Two-Byte Opcodes Starting With 0f") -case 0x8c: { // jump rel16 if SF and !ZF - int8_t offset = imm16(); +:(before "End Single-Byte Opcodes") +case 0x7c: { // jump rel8 if SF and !ZF + int8_t offset = static_cast(next()); if (SF != OF) { trace(2, "run") << "jump " << NUM(offset) << end(); EIP += offset; @@ -193,50 +187,50 @@ case 0x8c: { // jump rel16 if SF and !ZF break; } -:(scenario jl_rel16_fail) +:(scenario jl_rel8_fail) % ZF = false; % SF = false; % OF = false; -# op ModR/M SIB displacement immediate - 0f 8c 05 00 # skip 1 instruction - 05 00 00 00 01 - 05 00 00 00 02 +# op ModR/M SIB displacement immediate + 7c 05 # skip 1 instruction + 05 00 00 00 01 + 05 00 00 00 02 +run: inst: 0x00000001 -+run: inst: 0x00000005 -+run: inst: 0x0000000a ++run: inst: 0x00000003 ++run: inst: 0x00000008 -run: jump 5 //:: jump if lesser or equal -:(scenario jle_rel16_equal) +:(scenario jle_rel8_equal) % ZF = true; % SF = false; % OF = false; -# op ModR/M SIB displacement immediate - 0f 8e 05 00 # skip 1 instruction - 05 00 00 00 01 - 05 00 00 00 02 +# op ModR/M SIB displacement immediate + 7e 05 # skip 1 instruction + 05 00 00 00 01 + 05 00 00 00 02 +run: inst: 0x00000001 +run: jump 5 -+run: inst: 0x0000000a --run: inst: 0x00000005 ++run: inst: 0x00000008 +-run: inst: 0x00000003 -:(scenario jle_rel16_lesser) +:(scenario jle_rel8_lesser) % ZF = false; % SF = true; % OF = false; -# op ModR/M SIB displacement immediate - 0f 8e 05 00 # skip 1 instruction - 05 00 00 00 01 - 05 00 00 00 02 +# op ModR/M SIB displacement immediate + 7e 05 # skip 1 instruction + 05 00 00 00 01 + 05 00 00 00 02 +run: inst: 0x00000001 +run: jump 5 -+run: inst: 0x0000000a --run: inst: 0x00000005 ++run: inst: 0x00000008 +-run: inst: 0x00000003 -:(before "End Two-Byte Opcodes Starting With 0f") -case 0x8e: { // jump rel16 if SF or ZF - int8_t offset = imm16(); +:(before "End Single-Byte Opcodes") +case 0x7e: { // jump rel8 if SF or ZF + int8_t offset = static_cast(next()); if (ZF || SF != OF) { trace(2, "run") << "jump " << NUM(offset) << end(); EIP += offset; @@ -244,15 +238,15 @@ case 0x8e: { // jump rel16 if SF or ZF break; } -:(scenario jle_rel16_greater) +:(scenario jle_rel8_greater) % ZF = false; % SF = false; % OF = false; -# op ModR/M SIB displacement immediate - 0f 8e 05 00 # skip 1 instruction - 05 00 00 00 01 - 05 00 00 00 02 +# op ModR/M SIB displacement immediate + 7e 05 # skip 1 instruction + 05 00 00 00 01 + 05 00 00 00 02 +run: inst: 0x00000001 -+run: inst: 0x00000005 -+run: inst: 0x0000000a ++run: inst: 0x00000003 ++run: inst: 0x00000008 -run: jump 5 diff --git a/subx/017functions.cc b/subx/017functions.cc deleted file mode 100644 index 163894f2..00000000 --- a/subx/017functions.cc +++ /dev/null @@ -1,81 +0,0 @@ -//:: call - -:(scenario call_imm32) -% Reg[ESP].u = 0x64; -# op ModR/M SIB displacement immediate - e8 a0 00 00 00 # call function offset at 0x000000a0 - # next EIP is 6 -+run: call imm32 0x000000a0 -+run: decrementing ESP to 0x00000060 -+run: pushing value 0x00000006 -+run: jumping to 0x000000a6 - -:(before "End Single-Byte Opcodes") -case 0xe8: { // call imm32 relative to next EIP - int32_t offset = imm32(); - trace(2, "run") << "call imm32 0x" << HEXWORD << offset << end(); - push(EIP); - EIP += offset; - trace(2, "run") << "jumping to 0x" << HEXWORD << EIP << end(); - break; -} - -//: - -:(scenario call_r32) -% Reg[ESP].u = 0x64; -% Reg[EBX].u = 0x000000a0; -# op ModR/M SIB displacement immediate - ff d3 # call function offset at EBX - # next EIP is 3 -+run: call to r/m32 -+run: r/m32 is EBX -+run: decrementing ESP to 0x00000060 -+run: pushing value 0x00000003 -+run: jumping to 0x000000a3 - -:(before "End Op ff Subops") -case 2: { // call function pointer at r/m32 - trace(2, "run") << "call to r/m32" << end(); - int32_t* offset = effective_address(modrm); - push(EIP); - EIP += *offset; - trace(2, "run") << "jumping to 0x" << HEXWORD << EIP << end(); - break; -} - -:(scenario call_mem_at_r32) -% Reg[ESP].u = 0x64; -% Reg[EBX].u = 0x10; -== 0x1 # code segment -# op ModR/M SIB displacement immediate - ff 13 # call function offset at *EBX - # next EIP is 3 -== 0x10 # data segment -a0 00 00 00 # 0xa0 -+run: call to r/m32 -+run: effective address is 0x10 (EBX) -+run: decrementing ESP to 0x00000060 -+run: pushing value 0x00000003 -+run: jumping to 0x000000a3 - -//:: ret - -:(scenario ret) -% Reg[ESP].u = 0x60; -== 0x1 # code segment -# op ModR/M SIB displacement immediate - c3 -== 0x60 # data segment -10 00 00 00 # 0x10 -+run: return -+run: popping value 0x00000010 -+run: jumping to 0x00000010 - -:(before "End Single-Byte Opcodes") -case 0xc3: { // return from a call - trace(2, "run") << "return" << end(); - EIP = pop(); - trace(2, "run") << "jumping to 0x" << HEXWORD << EIP << end(); - break; -} diff --git a/subx/017jump_relative.cc b/subx/017jump_relative.cc new file mode 100644 index 00000000..8b8452bb --- /dev/null +++ b/subx/017jump_relative.cc @@ -0,0 +1,258 @@ +//: jump to 16-bit offset + +//:: jump + +:(scenario jump_rel16) +# op ModR/M SIB displacement immediate + e9 05 00 # skip 1 instruction + 05 00 00 00 01 + 05 00 00 00 02 ++run: inst: 0x00000001 ++run: jump 5 ++run: inst: 0x00000009 +-run: inst: 0x00000003 + +:(before "End Single-Byte Opcodes") +case 0xe9: { // jump rel8 + int16_t offset = imm16(); + trace(2, "run") << "jump " << offset << end(); + EIP += offset; + break; +} +:(code) +int16_t imm16() { + int16_t result = next(); + result |= (next()<<8); + return result; +} + +//:: jump if equal/zero + +:(scenario je_rel16_success) +% ZF = true; +# op ModR/M SIB displacement immediate + 0f 84 05 00 # skip 1 instruction + 05 00 00 00 01 + 05 00 00 00 02 ++run: inst: 0x00000001 ++run: jump 5 ++run: inst: 0x0000000a +-run: inst: 0x00000005 + +:(before "End Two-Byte Opcodes Starting With 0f") +case 0x84: { // jump rel16 if ZF + int8_t offset = imm16(); + if (ZF) { + trace(2, "run") << "jump " << NUM(offset) << end(); + EIP += offset; + } + break; +} + +:(scenario je_rel16_fail) +% ZF = false; +# op ModR/M SIB displacement immediate + 0f 84 05 00 # skip 1 instruction + 05 00 00 00 01 + 05 00 00 00 02 ++run: inst: 0x00000001 ++run: inst: 0x00000005 ++run: inst: 0x0000000a +-run: jump 5 + +//:: jump if not equal/not zero + +:(scenario jne_rel16_success) +% ZF = false; +# op ModR/M SIB displacement immediate + 0f 85 05 00 # skip 1 instruction + 05 00 00 00 01 + 05 00 00 00 02 ++run: inst: 0x00000001 ++run: jump 5 ++run: inst: 0x0000000a +-run: inst: 0x00000005 + +:(before "End Two-Byte Opcodes Starting With 0f") +case 0x85: { // jump rel16 unless ZF + int8_t offset = imm16(); + if (!ZF) { + trace(2, "run") << "jump " << NUM(offset) << end(); + EIP += offset; + } + break; +} + +:(scenario jne_rel16_fail) +% ZF = true; +# op ModR/M SIB displacement immediate + 0f 85 05 00 # skip 1 instruction + 05 00 00 00 01 + 05 00 00 00 02 ++run: inst: 0x00000001 ++run: inst: 0x00000005 ++run: inst: 0x0000000a +-run: jump 5 + +//:: jump if greater + +:(scenario jg_rel16_success) +% ZF = false; +% SF = false; +% OF = false; +# op ModR/M SIB displacement immediate + 0f 8f 05 00 # skip 1 instruction + 05 00 00 00 01 + 05 00 00 00 02 ++run: inst: 0x00000001 ++run: jump 5 ++run: inst: 0x0000000a +-run: inst: 0x00000005 + +:(before "End Two-Byte Opcodes Starting With 0f") +case 0x8f: { // jump rel16 if !SF and !ZF + int8_t offset = imm16(); + if (!ZF && SF == OF) { + trace(2, "run") << "jump " << NUM(offset) << end(); + EIP += offset; + } + break; +} + +:(scenario jg_rel16_fail) +% ZF = false; +% SF = true; +% OF = false; +# op ModR/M SIB displacement immediate + 0f 8f 05 00 # skip 1 instruction + 05 00 00 00 01 + 05 00 00 00 02 ++run: inst: 0x00000001 ++run: inst: 0x00000005 ++run: inst: 0x0000000a +-run: jump 5 + +//:: jump if greater or equal + +:(scenario jge_rel16_success) +% SF = false; +% OF = false; +# op ModR/M SIB displacement immediate + 0f 8d 05 00 # skip 1 instruction + 05 00 00 00 01 + 05 00 00 00 02 ++run: inst: 0x00000001 ++run: jump 5 ++run: inst: 0x0000000a +-run: inst: 0x00000005 + +:(before "End Two-Byte Opcodes Starting With 0f") +case 0x8d: { // jump rel16 if !SF + int8_t offset = imm16(); + if (SF == OF) { + trace(2, "run") << "jump " << NUM(offset) << end(); + EIP += offset; + } + break; +} + +:(scenario jge_rel16_fail) +% SF = true; +% OF = false; +# op ModR/M SIB displacement immediate + 0f 8d 05 00 # skip 1 instruction + 05 00 00 00 01 + 05 00 00 00 02 ++run: inst: 0x00000001 ++run: inst: 0x00000005 ++run: inst: 0x0000000a +-run: jump 5 + +//:: jump if lesser + +:(scenario jl_rel16_success) +% ZF = false; +% SF = true; +% OF = false; +# op ModR/M SIB displacement immediate + 0f 8c 05 00 # skip 1 instruction + 05 00 00 00 01 + 05 00 00 00 02 ++run: inst: 0x00000001 ++run: jump 5 ++run: inst: 0x0000000a +-run: inst: 0x00000005 + +:(before "End Two-Byte Opcodes Starting With 0f") +case 0x8c: { // jump rel16 if SF and !ZF + int8_t offset = imm16(); + if (SF != OF) { + trace(2, "run") << "jump " << NUM(offset) << end(); + EIP += offset; + } + break; +} + +:(scenario jl_rel16_fail) +% ZF = false; +% SF = false; +% OF = false; +# op ModR/M SIB displacement immediate + 0f 8c 05 00 # skip 1 instruction + 05 00 00 00 01 + 05 00 00 00 02 ++run: inst: 0x00000001 ++run: inst: 0x00000005 ++run: inst: 0x0000000a +-run: jump 5 + +//:: jump if lesser or equal + +:(scenario jle_rel16_equal) +% ZF = true; +% SF = false; +% OF = false; +# op ModR/M SIB displacement immediate + 0f 8e 05 00 # skip 1 instruction + 05 00 00 00 01 + 05 00 00 00 02 ++run: inst: 0x00000001 ++run: jump 5 ++run: inst: 0x0000000a +-run: inst: 0x00000005 + +:(scenario jle_rel16_lesser) +% ZF = false; +% SF = true; +% OF = false; +# op ModR/M SIB displacement immediate + 0f 8e 05 00 # skip 1 instruction + 05 00 00 00 01 + 05 00 00 00 02 ++run: inst: 0x00000001 ++run: jump 5 ++run: inst: 0x0000000a +-run: inst: 0x00000005 + +:(before "End Two-Byte Opcodes Starting With 0f") +case 0x8e: { // jump rel16 if SF or ZF + int8_t offset = imm16(); + if (ZF || SF != OF) { + trace(2, "run") << "jump " << NUM(offset) << end(); + EIP += offset; + } + break; +} + +:(scenario jle_rel16_greater) +% ZF = false; +% SF = false; +% OF = false; +# op ModR/M SIB displacement immediate + 0f 8e 05 00 # skip 1 instruction + 05 00 00 00 01 + 05 00 00 00 02 ++run: inst: 0x00000001 ++run: inst: 0x00000005 ++run: inst: 0x0000000a +-run: jump 5 diff --git a/subx/018functions.cc b/subx/018functions.cc new file mode 100644 index 00000000..163894f2 --- /dev/null +++ b/subx/018functions.cc @@ -0,0 +1,81 @@ +//:: call + +:(scenario call_imm32) +% Reg[ESP].u = 0x64; +# op ModR/M SIB displacement immediate + e8 a0 00 00 00 # call function offset at 0x000000a0 + # next EIP is 6 ++run: call imm32 0x000000a0 ++run: decrementing ESP to 0x00000060 ++run: pushing value 0x00000006 ++run: jumping to 0x000000a6 + +:(before "End Single-Byte Opcodes") +case 0xe8: { // call imm32 relative to next EIP + int32_t offset = imm32(); + trace(2, "run") << "call imm32 0x" << HEXWORD << offset << end(); + push(EIP); + EIP += offset; + trace(2, "run") << "jumping to 0x" << HEXWORD << EIP << end(); + break; +} + +//: + +:(scenario call_r32) +% Reg[ESP].u = 0x64; +% Reg[EBX].u = 0x000000a0; +# op ModR/M SIB displacement immediate + ff d3 # call function offset at EBX + # next EIP is 3 ++run: call to r/m32 ++run: r/m32 is EBX ++run: decrementing ESP to 0x00000060 ++run: pushing value 0x00000003 ++run: jumping to 0x000000a3 + +:(before "End Op ff Subops") +case 2: { // call function pointer at r/m32 + trace(2, "run") << "call to r/m32" << end(); + int32_t* offset = effective_address(modrm); + push(EIP); + EIP += *offset; + trace(2, "run") << "jumping to 0x" << HEXWORD << EIP << end(); + break; +} + +:(scenario call_mem_at_r32) +% Reg[ESP].u = 0x64; +% Reg[EBX].u = 0x10; +== 0x1 # code segment +# op ModR/M SIB displacement immediate + ff 13 # call function offset at *EBX + # next EIP is 3 +== 0x10 # data segment +a0 00 00 00 # 0xa0 ++run: call to r/m32 ++run: effective address is 0x10 (EBX) ++run: decrementing ESP to 0x00000060 ++run: pushing value 0x00000003 ++run: jumping to 0x000000a3 + +//:: ret + +:(scenario ret) +% Reg[ESP].u = 0x60; +== 0x1 # code segment +# op ModR/M SIB displacement immediate + c3 +== 0x60 # data segment +10 00 00 00 # 0x10 ++run: return ++run: popping value 0x00000010 ++run: jumping to 0x00000010 + +:(before "End Single-Byte Opcodes") +case 0xc3: { // return from a call + trace(2, "run") << "return" << end(); + EIP = pop(); + trace(2, "run") << "jumping to 0x" << HEXWORD << EIP << end(); + break; +} -- cgit 1.4.1-2-gfad0