From 95e5511ab8736f6fd9953fe66a05096b79afae16 Mon Sep 17 00:00:00 2001 From: "Kartik K. Agaram" Date: Sun, 15 Oct 2017 01:59:11 -0700 Subject: 4069 subx: unconditional 'jump' --- html/subx/010core.cc.html | 252 +++++++++++++++--------------- html/subx/011direct_addressing.cc.html | 38 ++--- html/subx/012indirect_addressing.cc.html | 81 +++++++--- html/subx/013immediate_addressing.cc.html | 153 +++++++++++------- 4 files changed, 303 insertions(+), 221 deletions(-) (limited to 'html/subx') diff --git a/html/subx/010core.cc.html b/html/subx/010core.cc.html index 75843a12..bea957fc 100644 --- a/html/subx/010core.cc.html +++ b/html/subx/010core.cc.html @@ -105,7 +105,7 @@ if ('onhashchange' in window) { 42 /* arg1 and arg2 must be signed */ \ 43 int64_t tmp = arg1 op arg2; \ 44 arg1 = arg1 op arg2; \ - 45 trace(2, "run") << "storing 0x" << HEXWORD << arg1 << end(); \ + 45 trace(2, "run") << "storing 0x" << HEXWORD << arg1 << end(); \ 46 SF = (arg1 < 0); \ 47 ZF = (arg1 == 0); \ 48 OF = (arg1 != tmp); \ @@ -116,7 +116,7 @@ if ('onhashchange' in window) { 53 #define BINARY_BITWISE_OP(op, arg1, arg2) { \ 54 /* arg1 and arg2 must be unsigned */ \ 55 arg1 = arg1 op arg2; \ - 56 trace(2, "run") << "storing 0x" << HEXWORD << arg1 << end(); \ + 56 trace(2, "run") << "storing 0x" << HEXWORD << arg1 << end(); \ 57 SF = (arg1 >> 31); \ 58 ZF = (arg1 == 0); \ 59 OF = false; \ @@ -153,14 +153,14 @@ if ('onhashchange' in window) { 90 +load: 3 -> 0b 91 +load: 4 -> 0c 92 +load: 5 -> 0d - 93 +run: add imm32 0x0d0c0b0a to reg EAX + 93 +run: add imm32 0x0d0c0b0a to reg EAX 94 +run: storing 0x0d0c0b0a 95 96 :(code) 97 // helper for tests: load a program into memory from a textual representation 98 // of its bytes, and run it 99 void run(const string& text_bytes) { -100 load_program(text_bytes); +100 load_program(text_bytes); 101 EIP = 1; // preserve null pointer 102 while (EIP < End_of_program) 103 ¦ run_one_instruction(); @@ -169,127 +169,129 @@ if ('onhashchange' in window) { 106 // skeleton of how x86 instructions are decoded 107 void run_one_instruction() { 108 uint8_t op=0, op2=0, op3=0; -109 switch (op = next()) { -110 case 0xf4: // hlt -111 ¦ EIP = End_of_program; -112 ¦ break; -113 // our first opcode -114 case 0x05: { // add imm32 to EAX -115 ¦ int32_t arg2 = imm32(); -116 ¦ trace(2, "run") << "add imm32 0x" << HEXWORD << arg2 << " to reg EAX" << end(); -117 ¦ BINARY_ARITHMETIC_OP(+, Reg[EAX].i, arg2); -118 ¦ break; -119 } -120 // End Single-Byte Opcodes -121 case 0x0f: -122 ¦ switch(op2 = next()) { -123 ¦ // End Two-Byte Opcodes Starting With 0f -124 ¦ default: -125 ¦ ¦ cerr << "unrecognized second opcode after 0f: " << HEXBYTE << NUM(op2) << '\n'; -126 ¦ ¦ exit(1); -127 ¦ } -128 ¦ break; -129 case 0xf3: -130 ¦ switch(op2 = next()) { -131 ¦ // End Two-Byte Opcodes Starting With f3 -132 ¦ case 0x0f: -133 ¦ ¦ switch(op3 = next()) { -134 ¦ ¦ // End Three-Byte Opcodes Starting With f3 0f -135 ¦ ¦ default: -136 ¦ ¦ ¦ cerr << "unrecognized third opcode after f3 0f: " << HEXBYTE << NUM(op3) << '\n'; -137 ¦ ¦ ¦ exit(1); -138 ¦ ¦ } -139 ¦ ¦ break; -140 ¦ default: -141 ¦ ¦ cerr << "unrecognized second opcode after f3: " << HEXBYTE << NUM(op2) << '\n'; -142 ¦ ¦ exit(1); -143 ¦ } -144 ¦ break; -145 default: -146 ¦ cerr << "unrecognized opcode: " << HEXBYTE << NUM(op) << '\n'; -147 ¦ exit(1); -148 } -149 } -150 -151 void load_program(const string& text_bytes) { -152 uint32_t addr = 1; -153 istringstream in(text_bytes); -154 in >> std::noskipws; -155 while (has_data(in)) { -156 ¦ char c1 = next_hex_byte(in); -157 ¦ if (c1 == '\0') break; -158 ¦ if (!has_data(in)) { -159 ¦ ¦ raise << "input program truncated mid-byte\n" << end(); -160 ¦ ¦ return; -161 ¦ } -162 ¦ char c2 = next_hex_byte(in); -163 ¦ if (c2 == '\0') { -164 ¦ ¦ raise << "input program truncated mid-byte\n" << end(); -165 ¦ ¦ return; -166 ¦ } -167 ¦ Mem.at(addr) = to_byte(c1, c2); -168 ¦ trace(99, "load") << addr << " -> " << HEXBYTE << NUM(Mem.at(addr)) << end(); -169 ¦ addr++; -170 } -171 End_of_program = addr; -172 } -173 -174 char next_hex_byte(istream& in) { -175 while (has_data(in)) { -176 ¦ char c = '\0'; -177 ¦ in >> c; -178 ¦ if (c == ' ' || c == '\n') continue; -179 ¦ while (c == '#') { -180 ¦ ¦ while (has_data(in)) { -181 ¦ ¦ ¦ in >> c; -182 ¦ ¦ ¦ if (c == '\n') { -183 ¦ ¦ ¦ ¦ in >> c; -184 ¦ ¦ ¦ ¦ break; -185 ¦ ¦ ¦ } -186 ¦ ¦ } -187 ¦ } -188 ¦ if (c >= '0' && c <= '9') return c; -189 ¦ if (c >= 'a' && c <= 'f') return c; -190 ¦ if (c >= 'A' && c <= 'F') return tolower(c); -191 ¦ // disallow any non-hex characters, including a '0x' prefix -192 ¦ if (!isspace(c)) { -193 ¦ ¦ raise << "invalid non-hex character " << NUM(c) << "\n" << end(); -194 ¦ ¦ break; -195 ¦ } -196 } -197 return '\0'; -198 } -199 -200 uint8_t to_byte(char hex_byte1, char hex_byte2) { -201 return to_hex_num(hex_byte1)*16 + to_hex_num(hex_byte2); -202 } -203 uint8_t to_hex_num(char c) { -204 if (c >= '0' && c <= '9') return c - '0'; -205 if (c >= 'a' && c <= 'f') return c - 'a' + 10; -206 assert(false); -207 return 0; -208 } -209 -210 inline uint8_t next() { -211 return Mem.at(EIP++); -212 } -213 -214 // read a 32-bit immediate in little-endian order from the instruction stream -215 int32_t imm32() { -216 int32_t result = next(); -217 result |= (next()<<8); -218 result |= (next()<<16); -219 result |= (next()<<24); -220 return result; -221 } -222 -223 :(before "End Includes") -224 #include <iomanip> -225 #define HEXBYTE std::hex << std::setw(2) << std::setfill('0') -226 #define HEXWORD std::hex << std::setw(8) << std::setfill('0') -227 // ugly that iostream doesn't print uint8_t as an integer -228 #define NUM(X) static_cast<int>(X) -229 #include <stdint.h> +109 trace(2, "run") << "inst: 0x" << HEXWORD << EIP << end(); +110 switch (op = next()) { +111 case 0xf4: // hlt +112 ¦ EIP = End_of_program; +113 ¦ break; +114 // our first opcode +115 case 0x05: { // add imm32 to EAX +116 ¦ int32_t arg2 = imm32(); +117 ¦ trace(2, "run") << "add imm32 0x" << HEXWORD << arg2 << " to reg EAX" << end(); +118 ¦ BINARY_ARITHMETIC_OP(+, Reg[EAX].i, arg2); +119 ¦ break; +120 } +121 // End Single-Byte Opcodes +122 case 0x0f: +123 ¦ switch(op2 = next()) { +124 ¦ // End Two-Byte Opcodes Starting With 0f +125 ¦ default: +126 ¦ ¦ cerr << "unrecognized second opcode after 0f: " << HEXBYTE << NUM(op2) << '\n'; +127 ¦ ¦ exit(1); +128 ¦ } +129 ¦ break; +130 case 0xf3: +131 ¦ switch(op2 = next()) { +132 ¦ // End Two-Byte Opcodes Starting With f3 +133 ¦ case 0x0f: +134 ¦ ¦ switch(op3 = next()) { +135 ¦ ¦ // End Three-Byte Opcodes Starting With f3 0f +136 ¦ ¦ default: +137 ¦ ¦ ¦ cerr << "unrecognized third opcode after f3 0f: " << HEXBYTE << NUM(op3) << '\n'; +138 ¦ ¦ ¦ exit(1); +139 ¦ ¦ } +140 ¦ ¦ break; +141 ¦ default: +142 ¦ ¦ cerr << "unrecognized second opcode after f3: " << HEXBYTE << NUM(op2) << '\n'; +143 ¦ ¦ exit(1); +144 ¦ } +145 ¦ break; +146 default: +147 ¦ cerr << "unrecognized opcode: " << HEXBYTE << NUM(op) << '\n'; +148 ¦ exit(1); +149 } +150 } +151 +152 void load_program(const string& text_bytes) { +153 uint32_t addr = 1; +154 istringstream in(text_bytes); +155 in >> std::noskipws; +156 while (has_data(in)) { +157 ¦ char c1 = next_hex_byte(in); +158 ¦ if (c1 == '\0') break; +159 ¦ if (!has_data(in)) { +160 ¦ ¦ raise << "input program truncated mid-byte\n" << end(); +161 ¦ ¦ return; +162 ¦ } +163 ¦ char c2 = next_hex_byte(in); +164 ¦ if (c2 == '\0') { +165 ¦ ¦ raise << "input program truncated mid-byte\n" << end(); +166 ¦ ¦ return; +167 ¦ } +168 ¦ Mem.at(addr) = to_byte(c1, c2); +169 ¦ trace(99, "load") << addr << " -> " << HEXBYTE << NUM(Mem.at(addr)) << end(); +170 ¦ addr++; +171 } +172 End_of_program = addr; +173 } +174 +175 char next_hex_byte(istream& in) { +176 while (has_data(in)) { +177 ¦ char c = '\0'; +178 ¦ in >> c; +179 ¦ if (c == ' ' || c == '\n') continue; +180 ¦ while (c == '#') { +181 ¦ ¦ while (has_data(in)) { +182 ¦ ¦ ¦ in >> c; +183 ¦ ¦ ¦ if (c == '\n') { +184 ¦ ¦ ¦ ¦ in >> c; +185 ¦ ¦ ¦ ¦ break; +186 ¦ ¦ ¦ } +187 ¦ ¦ } +188 ¦ } +189 ¦ if (c == '\0') return c; +190 ¦ if (c >= '0' && c <= '9') return c; +191 ¦ if (c >= 'a' && c <= 'f') return c; +192 ¦ if (c >= 'A' && c <= 'F') return tolower(c); +193 ¦ // disallow any non-hex characters, including a '0x' prefix +194 ¦ if (!isspace(c)) { +195 ¦ ¦ raise << "invalid non-hex character " << NUM(c) << "\n" << end(); +196 ¦ ¦ break; +197 ¦ } +198 } +199 return '\0'; +200 } +201 +202 uint8_t to_byte(char hex_byte1, char hex_byte2) { +203 return to_hex_num(hex_byte1)*16 + to_hex_num(hex_byte2); +204 } +205 uint8_t to_hex_num(char c) { +206 if (c >= '0' && c <= '9') return c - '0'; +207 if (c >= 'a' && c <= 'f') return c - 'a' + 10; +208 assert(false); +209 return 0; +210 } +211 +212 inline uint8_t next() { +213 return Mem.at(EIP++); +214 } +215 +216 // read a 32-bit immediate in little-endian order from the instruction stream +217 int32_t imm32() { +218 int32_t result = next(); +219 result |= (next()<<8); +220 result |= (next()<<16); +221 result |= (next()<<24); +222 return result; +223 } +224 +225 :(before "End Includes") +226 #include <iomanip> +227 #define HEXBYTE std::hex << std::setw(2) << std::setfill('0') +228 #define HEXWORD std::hex << std::setw(8) << std::setfill('0') +229 // ugly that iostream doesn't print uint8_t as an integer +230 #define NUM(X) static_cast<int>(X) +231 #include <stdint.h> diff --git a/html/subx/011direct_addressing.cc.html b/html/subx/011direct_addressing.cc.html index b8d9a853..ee7d3ce3 100644 --- a/html/subx/011direct_addressing.cc.html +++ b/html/subx/011direct_addressing.cc.html @@ -76,9 +76,9 @@ if ('onhashchange' in window) { 11 12 :(before "End Single-Byte Opcodes") 13 case 0x01: { // add r32 to r/m32 - 14 uint8_t modrm = next(); + 14 uint8_t modrm = next(); 15 uint8_t arg2 = (modrm>>3)&0x7; - 16 trace(2, "run") << "add reg " << NUM(arg2) << " to effective address" << end(); + 16 trace(2, "run") << "add reg " << NUM(arg2) << " to effective address" << end(); 17 int32_t* arg1 = effective_address(modrm); 18 BINARY_ARITHMETIC_OP(+, *arg1, Reg[arg2].i); 19 break; @@ -96,12 +96,12 @@ if ('onhashchange' in window) { 31 switch (mod) { 32 case 3: 33 ¦ // mod 3 is just register direct addressing - 34 ¦ trace(2, "run") << "effective address is reg " << NUM(rm) << end(); + 34 ¦ trace(2, "run") << "effective address is reg " << NUM(rm) << end(); 35 ¦ result = &Reg[rm].i; 36 ¦ break; 37 // End Mod Special-cases 38 default: - 39 ¦ cerr << "unrecognized mod bits: " << NUM(mod) << '\n'; + 39 ¦ cerr << "unrecognized mod bits: " << NUM(mod) << '\n'; 40 ¦ exit(1); 41 } 42 return result; @@ -120,9 +120,9 @@ if ('onhashchange' in window) { 55 56 :(before "End Single-Byte Opcodes") 57 case 0x29: { // subtract r32 from r/m32 - 58 uint8_t modrm = next(); + 58 uint8_t modrm = next(); 59 uint8_t arg2 = (modrm>>3)&0x7; - 60 trace(2, "run") << "subtract reg " << NUM(arg2) << " from effective address" << end(); + 60 trace(2, "run") << "subtract reg " << NUM(arg2) << " from effective address" << end(); 61 int32_t* arg1 = effective_address(modrm); 62 BINARY_ARITHMETIC_OP(-, *arg1, Reg[arg2].i); 63 break; @@ -141,9 +141,9 @@ if ('onhashchange' in window) { 76 77 :(before "End Single-Byte Opcodes") 78 case 0x21: { // and r32 with r/m32 - 79 uint8_t modrm = next(); + 79 uint8_t modrm = next(); 80 uint8_t arg2 = (modrm>>3)&0x7; - 81 trace(2, "run") << "and reg " << NUM(arg2) << " with effective address" << end(); + 81 trace(2, "run") << "and reg " << NUM(arg2) << " with effective address" << end(); 82 int32_t* arg1 = effective_address(modrm); 83 BINARY_BITWISE_OP(&, *arg1, Reg[arg2].u); 84 break; @@ -162,9 +162,9 @@ if ('onhashchange' in window) { 97 98 :(before "End Single-Byte Opcodes") 99 case 0x09: { // or r32 with r/m32 -100 uint8_t modrm = next(); +100 uint8_t modrm = next(); 101 uint8_t arg2 = (modrm>>3)&0x7; -102 trace(2, "run") << "or reg " << NUM(arg2) << " with effective address" << end(); +102 trace(2, "run") << "or reg " << NUM(arg2) << " with effective address" << end(); 103 int32_t* arg1 = effective_address(modrm); 104 BINARY_BITWISE_OP(|, *arg1, Reg[arg2].u); 105 break; @@ -183,9 +183,9 @@ if ('onhashchange' in window) { 118 119 :(before "End Single-Byte Opcodes") 120 case 0x31: { // xor r32 with r/m32 -121 uint8_t modrm = next(); +121 uint8_t modrm = next(); 122 uint8_t arg2 = (modrm>>3)&0x7; -123 trace(2, "run") << "xor reg " << NUM(arg2) << " with effective address" << end(); +123 trace(2, "run") << "xor reg " << NUM(arg2) << " with effective address" << end(); 124 int32_t* arg1 = effective_address(modrm); 125 BINARY_BITWISE_OP(^, *arg1, Reg[arg2].u); 126 break; @@ -203,11 +203,11 @@ if ('onhashchange' in window) { 138 139 :(before "End Single-Byte Opcodes") 140 case 0xf7: { // xor r32 with r/m32 -141 uint8_t modrm = next(); +141 uint8_t modrm = next(); 142 trace(2, "run") << "'not' of effective address" << end(); 143 int32_t* arg1 = effective_address(modrm); 144 *arg1 = ~(*arg1); -145 trace(2, "run") << "storing 0x" << HEXWORD << *arg1 << end(); +145 trace(2, "run") << "storing 0x" << HEXWORD << *arg1 << end(); 146 SF = (*arg1 >> 31); 147 ZF = (*arg1 == 0); 148 OF = false; @@ -227,9 +227,9 @@ if ('onhashchange' in window) { 162 163 :(before "End Single-Byte Opcodes") 164 case 0x39: { // set SF if r/m32 < r32 -165 uint8_t modrm = next(); +165 uint8_t modrm = next(); 166 uint8_t reg2 = (modrm>>3)&0x7; -167 trace(2, "run") << "compare reg " << NUM(reg2) << " with effective address" << end(); +167 trace(2, "run") << "compare reg " << NUM(reg2) << " with effective address" << end(); 168 int32_t* arg1 = effective_address(modrm); 169 int32_t arg2 = Reg[reg2].i; 170 int32_t tmp1 = *arg1 - arg2; @@ -271,12 +271,12 @@ if ('onhashchange' in window) { 206 207 :(before "End Single-Byte Opcodes") 208 case 0x89: { // copy r32 to r/m32 -209 uint8_t modrm = next(); +209 uint8_t modrm = next(); 210 uint8_t reg2 = (modrm>>3)&0x7; -211 trace(2, "run") << "copy reg " << NUM(reg2) << " to effective address" << end(); +211 trace(2, "run") << "copy reg " << NUM(reg2) << " to effective address" << end(); 212 int32_t* arg1 = effective_address(modrm); 213 *arg1 = Reg[reg2].i; -214 trace(2, "run") << "storing 0x" << HEXWORD << *arg1 << end(); +214 trace(2, "run") << "storing 0x" << HEXWORD << *arg1 << end(); 215 break; 216 } diff --git a/html/subx/012indirect_addressing.cc.html b/html/subx/012indirect_addressing.cc.html index b43a2098..8bf288af 100644 --- a/html/subx/012indirect_addressing.cc.html +++ b/html/subx/012indirect_addressing.cc.html @@ -15,19 +15,20 @@ body { font-size: 12pt; font-family: monospace; color: #aaaaaa; background-color a { color:#eeeeee; text-decoration: none; } a:hover { text-decoration: underline; } * { font-size: 12pt; font-size: 1em; } -.Constant { color: #00a0a0; } -.Special { color: #c00000; } -.Conceal { color: #4e4e4e; } .SalientComment { color: #00ffff; } +.LineNr { color: #444444; } +.Error { color: #ffffff; background-color: #ff6060; padding-bottom: 1px; } +.traceAbsent { color: #c00000; } +.Delimiter { color: #800080; } +.Normal { color: #aaaaaa; background-color: #080808; padding-bottom: 1px; } +.traceContains { color: #008000; } +.Conceal { color: #4e4e4e; } .Comment { color: #9090ff; } .Comment a { color:#0000ee; text-decoration:underline; } -.Delimiter { color: #800080; } -.LineNr { color: #444444; } +.Constant { color: #00a0a0; } +.Special { color: #c00000; } .Identifier { color: #c0a020; } -.Normal { color: #aaaaaa; background-color: #080808; padding-bottom: 1px; } .PreProc { color: #800080; } -.Error { color: #ffffff; background-color: #ff6060; padding-bottom: 1px; } -.traceContains { color: #008000; } --> @@ -79,7 +80,7 @@ if ('onhashchange' in window) { 15 // mod 0 is usually indirect addressing 16 switch (rm) { 17 default: - 18 ¦ trace(2, "run") << "effective address is mem at address 0x" << std::hex << Reg[rm].u << " (reg " << NUM(rm) << ")" << end(); + 18 ¦ trace(2, "run") << "effective address is mem at address 0x" << std::hex << Reg[rm].u << " (reg " << NUM(rm) << ")" << end(); 19 ¦ assert(Reg[rm].u + sizeof(int32_t) <= Mem.size()); 20 ¦ result = reinterpret_cast<int32_t*>(&Mem.at(Reg[rm].u)); // rely on the host itself being in little-endian order 21 ¦ break; @@ -101,9 +102,9 @@ if ('onhashchange' in window) { 37 38 :(before "End Single-Byte Opcodes") 39 case 0x03: { // add r/m32 to r32 - 40 uint8_t modrm = next(); + 40 uint8_t modrm = next(); 41 uint8_t arg1 = (modrm>>3)&0x7; - 42 trace(2, "run") << "add effective address to reg " << NUM(arg1) << end(); + 42 trace(2, "run") << "add effective address to reg " << NUM(arg1) << end(); 43 const int32_t* arg2 = effective_address(modrm); 44 BINARY_ARITHMETIC_OP(+, Reg[arg1].i, *arg2); 45 break; @@ -135,9 +136,9 @@ if ('onhashchange' in window) { 71 72 :(before "End Single-Byte Opcodes") 73 case 0x2b: { // subtract r/m32 from r32 - 74 uint8_t modrm = next(); + 74 uint8_t modrm = next(); 75 uint8_t arg1 = (modrm>>3)&0x7; - 76 trace(2, "run") << "subtract effective address from reg " << NUM(arg1) << end(); + 76 trace(2, "run") << "subtract effective address from reg " << NUM(arg1) << end(); 77 const int32_t* arg2 = effective_address(modrm); 78 BINARY_ARITHMETIC_OP(-, Reg[arg1].i, *arg2); 79 break; @@ -169,9 +170,9 @@ if ('onhashchange' in window) { 105 106 :(before "End Single-Byte Opcodes") 107 case 0x23: { // and r/m32 with r32 -108 uint8_t modrm = next(); +108 uint8_t modrm = next(); 109 uint8_t arg1 = (modrm>>3)&0x7; -110 trace(2, "run") << "and effective address with reg " << NUM(arg1) << end(); +110 trace(2, "run") << "and effective address with reg " << NUM(arg1) << end(); 111 const int32_t* arg2 = effective_address(modrm); 112 BINARY_BITWISE_OP(&, Reg[arg1].u, *arg2); 113 break; @@ -203,9 +204,9 @@ if ('onhashchange' in window) { 139 140 :(before "End Single-Byte Opcodes") 141 case 0x0b: { // or r/m32 with r32 -142 uint8_t modrm = next(); +142 uint8_t modrm = next(); 143 uint8_t arg1 = (modrm>>3)&0x7; -144 trace(2, "run") << "or effective address with reg " << NUM(arg1) << end(); +144 trace(2, "run") << "or effective address with reg " << NUM(arg1) << end(); 145 const int32_t* arg2 = effective_address(modrm); 146 BINARY_BITWISE_OP(|, Reg[arg1].u, *arg2); 147 break; @@ -237,9 +238,9 @@ if ('onhashchange' in window) { 173 174 :(before "End Single-Byte Opcodes") 175 case 0x33: { // xor r/m32 with r32 -176 uint8_t modrm = next(); +176 uint8_t modrm = next(); 177 uint8_t arg1 = (modrm>>3)&0x7; -178 trace(2, "run") << "xor effective address with reg " << NUM(arg1) << end(); +178 trace(2, "run") << "xor effective address with reg " << NUM(arg1) << end(); 179 const int32_t* arg2 = effective_address(modrm); 180 BINARY_BITWISE_OP(|, Reg[arg1].u, *arg2); 181 break; @@ -303,9 +304,9 @@ if ('onhashchange' in window) { 239 240 :(before "End Single-Byte Opcodes") 241 case 0x3b: { // set SF if r32 < r/m32 -242 uint8_t modrm = next(); +242 uint8_t modrm = next(); 243 uint8_t reg1 = (modrm>>3)&0x7; -244 trace(2, "run") << "compare effective address with reg " << NUM(reg1) << end(); +244 trace(2, "run") << "compare effective address with reg " << NUM(reg1) << end(); 245 int32_t arg1 = Reg[reg1].i; 246 int32_t* arg2 = effective_address(modrm); 247 int32_t tmp1 = arg1 - *arg2; @@ -361,14 +362,46 @@ if ('onhashchange' in window) { 297 298 :(before "End Single-Byte Opcodes") 299 case 0x8b: { // copy r32 to r/m32 -300 uint8_t modrm = next(); +300 uint8_t modrm = next(); 301 uint8_t reg1 = (modrm>>3)&0x7; -302 trace(2, "run") << "copy effective address to reg " << NUM(reg1) << end(); +302 trace(2, "run") << "copy effective address to reg " << NUM(reg1) << end(); 303 int32_t* arg2 = effective_address(modrm); 304 Reg[reg1].i = *arg2; -305 trace(2, "run") << "storing 0x" << HEXWORD << *arg2 << end(); +305 trace(2, "run") << "storing 0x" << HEXWORD << *arg2 << end(); 306 break; 307 } +308 +309 //:: jump +310 +311 :(scenario jump_mem_at_r32) +312 % Reg[0].i = 0x60; +313 % SET_WORD_IN_MEM(0x60, 8); +314 # op ModRM SIB displacement immediate +315 ff 20 # jump to *EAX (reg 0) +316 05 00 00 00 01 +317 05 00 00 00 02 +318 +run: inst: 0x00000001 +319 +run: jump to effective address +320 +run: effective address is mem at address 0x60 (reg 0) +321 +run: jumping to 0x00000008 +322 +run: inst: 0x00000008 +323 -run: inst: 0x00000003 +324 +325 :(before "End Single-Byte Opcodes") +326 case 0xff: { // jump to r/m32 +327 uint8_t modrm = next(); +328 uint8_t subop = (modrm>>3)&0x7; // middle 3 'reg opcode' bits +329 switch (subop) { +330 case 4: +331 ¦ trace(2, "run") << "jump to effective address" << end(); +332 ¦ int32_t* arg2 = effective_address(modrm); +333 ¦ EIP = *arg2; +334 ¦ trace(2, "run") << "jumping to 0x" << HEXWORD << EIP << end(); +335 ¦ break; +336 // End Op ff Subops +337 } +338 break; +339 } diff --git a/html/subx/013immediate_addressing.cc.html b/html/subx/013immediate_addressing.cc.html index f7bb47f4..8b5be4ba 100644 --- a/html/subx/013immediate_addressing.cc.html +++ b/html/subx/013immediate_addressing.cc.html @@ -15,19 +15,20 @@ body { font-size: 12pt; font-family: monospace; color: #aaaaaa; background-color a { color:#eeeeee; text-decoration: none; } a:hover { text-decoration: underline; } * { font-size: 12pt; font-size: 1em; } -.Constant { color: #00a0a0; } -.Special { color: #c00000; } -.Conceal { color: #4e4e4e; } .SalientComment { color: #00ffff; } +.LineNr { color: #444444; } +.traceContains { color: #008000; } +.traceAbsent { color: #c00000; } +.Delimiter { color: #800080; } +.Normal { color: #aaaaaa; background-color: #080808; padding-bottom: 1px; } +.cSpecial { color: #008000; } +.Conceal { color: #4e4e4e; } .Comment { color: #9090ff; } .Comment a { color:#0000ee; text-decoration:underline; } -.Delimiter { color: #800080; } -.LineNr { color: #444444; } +.Constant { color: #00a0a0; } +.Special { color: #c00000; } .Identifier { color: #c0a020; } -.Normal { color: #aaaaaa; background-color: #080808; padding-bottom: 1px; } .PreProc { color: #800080; } -.cSpecial { color: #008000; } -.traceContains { color: #008000; } --> @@ -68,16 +69,16 @@ if ('onhashchange' in window) { 4 % Reg[3].i = 1; 5 # op ModRM SIB displacement immediate 6 81 c3 0a 0b 0c 0d # add 0x0d0c0b0a to EBX (reg 3) - 7 +run: combine imm32 0x0d0c0b0a with effective address + 7 +run: combine imm32 0x0d0c0b0a with effective address 8 +run: effective address is reg 3 9 +run: subop add 10 +run: storing 0x0d0c0b0b 11 12 :(before "End Single-Byte Opcodes") 13 case 0x81: { // combine imm32 with r/m32 - 14 uint8_t modrm = next(); - 15 int32_t arg2 = imm32(); - 16 trace(2, "run") << "combine imm32 0x" << HEXWORD << arg2 << " with effective address" << end(); + 14 uint8_t modrm = next(); + 15 int32_t arg2 = imm32(); + 16 trace(2, "run") << "combine imm32 0x" << HEXWORD << arg2 << " with effective address" << end(); 17 int32_t* arg1 = effective_address(modrm); 18 uint8_t subop = (modrm>>3)&0x7; // middle 3 'reg opcode' bits 19 switch (subop) { @@ -87,7 +88,7 @@ if ('onhashchange' in window) { 23 ¦ break; 24 // End Op 81 Subops 25 default: - 26 ¦ cerr << "unrecognized sub-opcode after 81: " << NUM(subop) << '\n'; + 26 ¦ cerr << "unrecognized sub-opcode after 81: " << NUM(subop) << '\n'; 27 ¦ exit(1); 28 } 29 break; @@ -100,7 +101,7 @@ if ('onhashchange' in window) { 36 % SET_WORD_IN_MEM(0x60, 1); 37 # op ModR/M SIB displacement immediate 38 81 03 0a 0b 0c 0d # add 0x0d0c0b0a to *EBX (reg 3) - 39 +run: combine imm32 0x0d0c0b0a with effective address + 39 +run: combine imm32 0x0d0c0b0a with effective address 40 +run: effective address is mem at address 0x60 (reg 3) 41 +run: subop add 42 +run: storing 0x0d0c0b0b @@ -111,13 +112,13 @@ if ('onhashchange' in window) { 47 % Reg[EAX].i = 0x0d0c0baa; 48 # op ModR/M SIB displacement immediate 49 2d 0a 0b 0c 0d # subtract 0x0d0c0b0a from EAX (reg 0) - 50 +run: subtract imm32 0x0d0c0b0a from reg EAX + 50 +run: subtract imm32 0x0d0c0b0a from reg EAX 51 +run: storing 0x000000a0 52 53 :(before "End Single-Byte Opcodes") 54 case 0x2d: { // subtract imm32 from EAX - 55 int32_t arg2 = imm32(); - 56 trace(2, "run") << "subtract imm32 0x" << HEXWORD << arg2 << " from reg EAX" << end(); + 55 int32_t arg2 = imm32(); + 56 trace(2, "run") << "subtract imm32 0x" << HEXWORD << arg2 << " from reg EAX" << end(); 57 BINARY_ARITHMETIC_OP(-, Reg[EAX].i, arg2); 58 break; 59 } @@ -129,7 +130,7 @@ if ('onhashchange' in window) { 65 % SET_WORD_IN_MEM(0x60, 10); 66 # op ModRM SIB displacement immediate 67 81 2b 01 00 00 00 # subtract 1 from *EBX (reg 3) - 68 +run: combine imm32 0x00000001 with effective address + 68 +run: combine imm32 0x00000001 with effective address 69 +run: effective address is mem at address 0x60 (reg 3) 70 +run: subop subtract 71 +run: storing 0x00000009 @@ -140,7 +141,7 @@ if ('onhashchange' in window) { 76 % Reg[3].i = 10; 77 # op ModRM SIB displacement immediate 78 81 eb 01 00 00 00 # subtract 1 from EBX (reg 3) - 79 +run: combine imm32 0x00000001 with effective address + 79 +run: combine imm32 0x00000001 with effective address 80 +run: effective address is reg 3 81 +run: subop subtract 82 +run: storing 0x00000009 @@ -158,13 +159,13 @@ if ('onhashchange' in window) { 94 % Reg[EAX].i = 0xff; 95 # op ModR/M SIB displacement immediate 96 25 0a 0b 0c 0d # and 0x0d0c0b0a with EAX (reg 0) - 97 +run: and imm32 0x0d0c0b0a with reg EAX + 97 +run: and imm32 0x0d0c0b0a with reg EAX 98 +run: storing 0x0000000a 99 100 :(before "End Single-Byte Opcodes") 101 case 0x25: { // and imm32 with EAX -102 int32_t arg2 = imm32(); -103 trace(2, "run") << "and imm32 0x" << HEXWORD << arg2 << " with reg EAX" << end(); +102 int32_t arg2 = imm32(); +103 trace(2, "run") << "and imm32 0x" << HEXWORD << arg2 << " with reg EAX" << end(); 104 BINARY_BITWISE_OP(&, Reg[EAX].i, arg2); 105 break; 106 } @@ -176,7 +177,7 @@ if ('onhashchange' in window) { 112 % SET_WORD_IN_MEM(0x60, 0x000000ff); 113 # op ModRM SIB displacement immediate 114 81 23 0a 0b 0c 0d # and 0x0d0c0b0a with *EBX (reg 3) -115 +run: combine imm32 0x0d0c0b0a with effective address +115 +run: combine imm32 0x0d0c0b0a with effective address 116 +run: effective address is mem at address 0x60 (reg 3) 117 +run: subop and 118 +run: storing 0x0000000a @@ -187,7 +188,7 @@ if ('onhashchange' in window) { 123 % Reg[3].i = 0xff; 124 # op ModRM SIB displacement immediate 125 81 e3 0a 0b 0c 0d # and 0x0d0c0b0a with EBX (reg 3) -126 +run: combine imm32 0x0d0c0b0a with effective address +126 +run: combine imm32 0x0d0c0b0a with effective address 127 +run: effective address is reg 3 128 +run: subop and 129 +run: storing 0x0000000a @@ -205,13 +206,13 @@ if ('onhashchange' in window) { 141 % Reg[EAX].i = 0xd0c0b0a0; 142 # op ModR/M SIB displacement immediate 143 0d 0a 0b 0c 0d # or 0x0d0c0b0a with EAX (reg 0) -144 +run: or imm32 0x0d0c0b0a with reg EAX +144 +run: or imm32 0x0d0c0b0a with reg EAX 145 +run: storing 0xddccbbaa 146 147 :(before "End Single-Byte Opcodes") 148 case 0x0d: { // or imm32 with EAX -149 int32_t arg2 = imm32(); -150 trace(2, "run") << "or imm32 0x" << HEXWORD << arg2 << " with reg EAX" << end(); +149 int32_t arg2 = imm32(); +150 trace(2, "run") << "or imm32 0x" << HEXWORD << arg2 << " with reg EAX" << end(); 151 BINARY_BITWISE_OP(|, Reg[EAX].i, arg2); 152 break; 153 } @@ -223,7 +224,7 @@ if ('onhashchange' in window) { 159 % SET_WORD_IN_MEM(0x60, 0xd0c0b0a0); 160 # op ModRM SIB displacement immediate 161 81 0b 0a 0b 0c 0d # or 0x0d0c0b0a with *EBX (reg 3) -162 +run: combine imm32 0x0d0c0b0a with effective address +162 +run: combine imm32 0x0d0c0b0a with effective address 163 +run: effective address is mem at address 0x60 (reg 3) 164 +run: subop or 165 +run: storing 0xddccbbaa @@ -234,7 +235,7 @@ if ('onhashchange' in window) { 170 % Reg[3].i = 0xd0c0b0a0; 171 # op ModRM SIB displacement immediate 172 81 cb 0a 0b 0c 0d # or 0x0d0c0b0a with EBX (reg 3) -173 +run: combine imm32 0x0d0c0b0a with effective address +173 +run: combine imm32 0x0d0c0b0a with effective address 174 +run: effective address is reg 3 175 +run: subop or 176 +run: storing 0xddccbbaa @@ -252,13 +253,13 @@ if ('onhashchange' in window) { 188 % Reg[EAX].i = 0xddccb0a0; 189 # op ModR/M SIB displacement immediate 190 35 0a 0b 0c 0d # xor 0x0d0c0b0a with EAX (reg 0) -191 +run: xor imm32 0x0d0c0b0a with reg EAX +191 +run: xor imm32 0x0d0c0b0a with reg EAX 192 +run: storing 0xd0c0bbaa 193 194 :(before "End Single-Byte Opcodes") 195 case 0x35: { // xor imm32 with EAX -196 int32_t arg2 = imm32(); -197 trace(2, "run") << "xor imm32 0x" << HEXWORD << arg2 << " with reg EAX" << end(); +196 int32_t arg2 = imm32(); +197 trace(2, "run") << "xor imm32 0x" << HEXWORD << arg2 << " with reg EAX" << end(); 198 BINARY_BITWISE_OP(^, Reg[EAX].i, arg2); 199 break; 200 } @@ -270,7 +271,7 @@ if ('onhashchange' in window) { 206 % SET_WORD_IN_MEM(0x60, 0xd0c0b0a0); 207 # op ModRM SIB displacement immediate 208 81 33 0a 0b 0c 0d # xor 0x0d0c0b0a with *EBX (reg 3) -209 +run: combine imm32 0x0d0c0b0a with effective address +209 +run: combine imm32 0x0d0c0b0a with effective address 210 +run: effective address is mem at address 0x60 (reg 3) 211 +run: subop xor 212 +run: storing 0xddccbbaa @@ -281,7 +282,7 @@ if ('onhashchange' in window) { 217 % Reg[3].i = 0xd0c0b0a0; 218 # op ModRM SIB displacement immediate 219 81 f3 0a 0b 0c 0d # xor 0x0d0c0b0a with EBX (reg 3) -220 +run: combine imm32 0x0d0c0b0a with effective address +220 +run: combine imm32 0x0d0c0b0a with effective address 221 +run: effective address is reg 3 222 +run: subop xor 223 +run: storing 0xddccbbaa @@ -299,14 +300,14 @@ if ('onhashchange' in window) { 235 % Reg[0].i = 0x0d0c0b0a; 236 # op ModRM SIB displacement immediate 237 3d 07 0b 0c 0d # compare 0x0d0c0b07 with EAX (reg 0) -238 +run: compare reg EAX and imm32 0x0d0c0b07 +238 +run: compare reg EAX and imm32 0x0d0c0b07 239 +run: SF=0; ZF=0; OF=0 240 241 :(before "End Single-Byte Opcodes") 242 case 0x3d: { // subtract imm32 from EAX 243 int32_t arg1 = Reg[EAX].i; -244 int32_t arg2 = imm32(); -245 trace(2, "run") << "compare reg EAX and imm32 0x" << HEXWORD << arg2 << end(); +244 int32_t arg2 = imm32(); +245 trace(2, "run") << "compare reg EAX and imm32 0x" << HEXWORD << arg2 << end(); 246 int32_t tmp1 = arg1 - arg2; 247 SF = (tmp1 < 0); 248 ZF = (tmp1 == 0); @@ -320,14 +321,14 @@ if ('onhashchange' in window) { 256 % Reg[0].i = 0x0d0c0b07; 257 # op ModRM SIB displacement immediate 258 3d 0a 0b 0c 0d # compare 0x0d0c0b0a with EAX (reg 0) -259 +run: compare reg EAX and imm32 0x0d0c0b0a +259 +run: compare reg EAX and imm32 0x0d0c0b0a 260 +run: SF=1; ZF=0; OF=0 261 262 :(scenario compare_imm32_with_eax_equal) 263 % Reg[0].i = 0x0d0c0b0a; 264 # op ModRM SIB displacement immediate 265 3d 0a 0b 0c 0d # compare 0x0d0c0b0a with EAX (reg 0) -266 +run: compare reg EAX and imm32 0x0d0c0b0a +266 +run: compare reg EAX and imm32 0x0d0c0b0a 267 +run: SF=0; ZF=1; OF=0 268 269 //: @@ -336,7 +337,7 @@ if ('onhashchange' in window) { 272 % Reg[3].i = 0x0d0c0b0a; 273 # op ModRM SIB displacement immediate 274 81 fb 07 0b 0c 0d # compare 0x0d0c0b07 with EBX (reg 3) -275 +run: combine imm32 0x0d0c0b07 with effective address +275 +run: combine imm32 0x0d0c0b07 with effective address 276 +run: effective address is reg 3 277 +run: SF=0; ZF=0; OF=0 278 @@ -356,7 +357,7 @@ if ('onhashchange' in window) { 292 % Reg[3].i = 0x0d0c0b07; 293 # op ModRM SIB displacement immediate 294 81 fb 0a 0b 0c 0d # compare 0x0d0c0b0a with EBX (reg 3) -295 +run: combine imm32 0x0d0c0b0a with effective address +295 +run: combine imm32 0x0d0c0b0a with effective address 296 +run: effective address is reg 3 297 +run: SF=1; ZF=0; OF=0 298 @@ -364,7 +365,7 @@ if ('onhashchange' in window) { 300 % Reg[3].i = 0x0d0c0b0a; 301 # op ModRM SIB displacement immediate 302 81 fb 0a 0b 0c 0d # compare 0x0d0c0b0a with EBX (reg 3) -303 +run: combine imm32 0x0d0c0b0a with effective address +303 +run: combine imm32 0x0d0c0b0a with effective address 304 +run: effective address is reg 3 305 +run: SF=0; ZF=1; OF=0 306 @@ -373,7 +374,7 @@ if ('onhashchange' in window) { 309 % SET_WORD_IN_MEM(0x60, 0x0d0c0b0a); 310 # op ModRM SIB displacement immediate 311 81 3b 07 0b 0c 0d # compare 0x0d0c0b07 with *EBX (reg 3) -312 +run: combine imm32 0x0d0c0b07 with effective address +312 +run: combine imm32 0x0d0c0b07 with effective address 313 +run: effective address is mem at address 0x60 (reg 3) 314 +run: SF=0; ZF=0; OF=0 315 @@ -382,7 +383,7 @@ if ('onhashchange' in window) { 318 % SET_WORD_IN_MEM(0x60, 0x0d0c0b07); 319 # op ModRM SIB displacement immediate 320 81 3b 0a 0b 0c 0d # compare 0x0d0c0b0a with *EBX (reg 3) -321 +run: combine imm32 0x0d0c0b0a with effective address +321 +run: combine imm32 0x0d0c0b0a with effective address 322 +run: effective address is mem at address 0x60 (reg 3) 323 +run: SF=1; ZF=0; OF=0 324 @@ -392,7 +393,7 @@ if ('onhashchange' in window) { 328 % SET_WORD_IN_MEM(0x60, 0x0d0c0b0a); 329 # op ModRM SIB displacement immediate 330 81 3b 0a 0b 0c 0d # compare 0x0d0c0b0a with *EBX (reg 3) -331 +run: combine imm32 0x0d0c0b0a with effective address +331 +run: combine imm32 0x0d0c0b0a with effective address 332 +run: effective address is mem at address 0x60 (reg 3) 333 +run: SF=0; ZF=1; OF=0 334 @@ -401,14 +402,14 @@ if ('onhashchange' in window) { 337 :(scenario copy_imm32_to_r32) 338 # op ModRM SIB displacement immediate 339 b8 03 0a 0b 0c 0d # copy 0x0d0c0b0a to EBX (reg 3) -340 +run: copy imm32 0x0d0c0b0a to reg 3 +340 +run: copy imm32 0x0d0c0b0a to reg 3 341 342 :(before "End Single-Byte Opcodes") 343 case 0xb8: { // copy imm32 to r32 -344 uint8_t modrm = next(); -345 int32_t arg2 = imm32(); +344 uint8_t modrm = next(); +345 int32_t arg2 = imm32(); 346 uint8_t reg1 = modrm&0x7; // ignore mod bits -347 trace(2, "run") << "copy imm32 0x" << HEXWORD << arg2 << " to reg " << NUM(reg1) << end(); +347 trace(2, "run") << "copy imm32 0x" << HEXWORD << arg2 << " to reg " << NUM(reg1) << end(); 348 Reg[reg1].i = arg2; 349 break; 350 } @@ -418,18 +419,64 @@ if ('onhashchange' in window) { 354 % Reg[3].i = 0x60; 355 # op ModRM SIB displacement immediate 356 c7 03 0a 0b 0c 0d # copy 0x0d0c0b0a to *EBX (reg 3) -357 +run: copy imm32 0x0d0c0b0a to effective address +357 +run: copy imm32 0x0d0c0b0a to effective address 358 +run: effective address is mem at address 0x60 (reg 3) 359 360 :(before "End Single-Byte Opcodes") 361 case 0xc7: { // copy imm32 to r32 -362 uint8_t modrm = next(); -363 int32_t arg2 = imm32(); -364 trace(2, "run") << "copy imm32 0x" << HEXWORD << arg2 << " to effective address" << end(); +362 uint8_t modrm = next(); +363 int32_t arg2 = imm32(); +364 trace(2, "run") << "copy imm32 0x" << HEXWORD << arg2 << " to effective address" << end(); 365 int32_t* arg1 = effective_address(modrm); 366 *arg1 = arg2; 367 break; 368 } +369 +370 //:: jump +371 +372 :(scenario jump_rel8) +373 # op ModRM SIB displacement immediate +374 eb 05 # skip 1 instruction +375 05 00 00 00 01 +376 05 00 00 00 02 +377 +run: inst: 0x00000001 +378 +run: jump 5 +379 +run: inst: 0x00000008 +380 -run: inst: 0x00000003 +381 +382 :(before "End Single-Byte Opcodes") +383 case 0xeb: { // jump rel8 +384 int8_t offset = static_cast<int>(next()); +385 trace(2, "run") << "jump " << NUM(offset) << end(); +386 EIP += offset; +387 break; +388 } +389 +390 //: +391 +392 :(scenario jump_rel16) +393 # op ModRM SIB displacement immediate +394 e9 05 00 # skip 1 instruction +395 05 00 00 00 01 +396 05 00 00 00 02 +397 +run: inst: 0x00000001 +398 +run: jump 5 +399 +run: inst: 0x00000009 +400 -run: inst: 0x00000003 +401 +402 :(before "End Single-Byte Opcodes") +403 case 0xe9: { // jump rel8 +404 int16_t offset = imm16(); +405 trace(2, "run") << "jump " << offset << end(); +406 EIP += offset; +407 break; +408 } +409 :(code) +410 int16_t imm16() { +411 int16_t result = next(); +412 result |= (next()<<8); +413 return result; +414 } -- cgit 1.4.1-2-gfad0