diff options
-rw-r--r-- | subx/010---vm.cc | 40 | ||||
-rw-r--r-- | subx/011run.cc | 2 | ||||
-rw-r--r-- | subx/013direct_addressing.cc | 64 | ||||
-rw-r--r-- | subx/015immediate_addressing.cc | 26 | ||||
-rw-r--r-- | subx/030---operands.cc | 56 | ||||
-rw-r--r-- | subx/modrm.pdf | bin | 0 -> 46205 bytes | |||
-rw-r--r-- | subx/sib.pdf | bin | 0 -> 51968 bytes |
7 files changed, 113 insertions, 75 deletions
diff --git a/subx/010---vm.cc b/subx/010---vm.cc index 745d64e0..cae54aec 100644 --- a/subx/010---vm.cc +++ b/subx/010---vm.cc @@ -35,21 +35,43 @@ EIP = 1; // preserve null pointer cerr << " registers\n"; :(before "End Help Texts") put(Help, "registers", - "SubX currently supports eight 32-bit integer registers: R0 to R7.\n" - "R4 (ESP) contains the top of the stack.\n" + "SubX currently supports eight 32-bit integer registers. From 0 to 7, they are:\n" + " EAX ECX EDX EBX ESP EBP ESI EDI\n" + "ESP contains the top of the stack.\n" "\n" - "There's also a register for the address of the currently executing\n" - "instruction. It is modified by jumps.\n" + "-- 8-bit registers\n" + "Some instructions operate on eight *overlapping* 8-bit registers.\n" + "From 0 to 7, they are:\n" + " AL CL DL BL AH CH DH BH\n" + "The 8-bit registers overlap with the 32-bit ones. AL is the lowest signicant byte\n" + "of EAX, AH is the second lowest significant byte, and so on.\n" "\n" - "Various instructions modify one or more of three 1-bit 'flag' registers,\n" - "as a side-effect:\n" + "For example, if EBX contains 0x11223344, then BL contains 0x44, and BH contains 0x33.\n" + "\n" + "There is no way to access bytes within ESP, EBP, ESI or EDI.\n" + "\n" + "For complete details consult the IA-32 software developer's manual, volume 2,\n" + "table 2-2, \"32-bit addressing forms with the ModR/M byte\".\n" + "It is included in this repository as 'modrm.pdf'.\n" + "The register encodings are described in the top row of the table, but you'll need\n" + "to spend some time with it.\n" + "\n" + "-- flag registers\n" + "Various instructions (particularly 'compare') modify one or more of three 1-bit 'flag'\n" + "registers, as a side-effect:\n" "- the sign flag (SF): usually set if an arithmetic result is negative, or\n" " reset if not.\n" "- the zero flag (ZF): usually set if a result is zero, or reset if not.\n" "- the overflow flag (OF): usually set if an arithmetic result overflows.\n" "The flag bits are read by conditional jumps.\n" "\n" - "We don't support non-integer (floating-point) registers yet.\n" + "For complete details on how different instructions update the flags, consult the IA-32\n" + "manual (volume 2). There's various versions of it online, such as https://c9x.me/x86,\n" + "though of course you'll need to be careful to ignore instructions and flag registers\n" + "that SubX doesn't support.\n" + "\n" + "It isn't simple, but if this is the processor you have running on your computer,\n" + "might as well get good at it.\n" ); :(before "End Globals") @@ -366,7 +388,9 @@ if (key == "opcodes") { cerr << " f3 " << p->first << ": " << p->second << '\n'; for (map<string, string>::iterator p = name_f3_0f.begin(); p != name_f3_0f.end(); ++p) cerr << " f3 0f " << p->first << ": " << p->second << '\n'; - cerr << "Run `subx help instructions` for details on words like 'r32' and 'disp8'.\n"; + cerr << "Run `subx help instructions` for details on words like 'r32' and 'disp8'.\n" + "For complete details on these instructions, consult the IA-32 manual (volume 2).\n" + "There's various versions of it online, such as https://c9x.me/x86.\n"; return 0; } :(before "End Help Contents") diff --git a/subx/011run.cc b/subx/011run.cc index 88729871..d5d1c074 100644 --- a/subx/011run.cc +++ b/subx/011run.cc @@ -327,7 +327,7 @@ void parse_and_load(const string& text_bytes) { //:: run :(before "End Initialize Op Names(name)") -put(name, "05", "add imm32 to R0 (EAX)"); +put(name, "05", "add imm32 to EAX"); //: our first opcode :(before "End Single-Byte Opcodes") diff --git a/subx/013direct_addressing.cc b/subx/013direct_addressing.cc index 5f44d49d..2767f32b 100644 --- a/subx/013direct_addressing.cc +++ b/subx/013direct_addressing.cc @@ -385,14 +385,14 @@ case 0x87: { // exchange r32 with r/m32 //:: increment :(before "End Initialize Op Names(name)") -put(name, "40", "increment R0 (EAX)"); -put(name, "41", "increment R1 (ECX)"); -put(name, "42", "increment R2 (EDX)"); -put(name, "43", "increment R3 (EBX)"); -put(name, "44", "increment R4 (ESP)"); -put(name, "45", "increment R5 (EBP)"); -put(name, "46", "increment R6 (ESI)"); -put(name, "47", "increment R7 (EDI)"); +put(name, "40", "increment EAX"); +put(name, "41", "increment ECX"); +put(name, "42", "increment EDX"); +put(name, "43", "increment EBX"); +put(name, "44", "increment ESP"); +put(name, "45", "increment EBP"); +put(name, "46", "increment ESI"); +put(name, "47", "increment EDI"); :(scenario increment_r32) % Reg[ECX].u = 0x1f; @@ -451,14 +451,14 @@ case 0xff: { //:: decrement :(before "End Initialize Op Names(name)") -put(name, "48", "decrement R0 (EAX)"); -put(name, "49", "decrement R1 (ECX)"); -put(name, "4a", "decrement R2 (EDX)"); -put(name, "4b", "decrement R3 (EBX)"); -put(name, "4c", "decrement R4 (ESP)"); -put(name, "4d", "decrement R5 (EBP)"); -put(name, "4e", "decrement R6 (ESI)"); -put(name, "4f", "decrement R7 (EDI)"); +put(name, "48", "decrement EAX"); +put(name, "49", "decrement ECX"); +put(name, "4a", "decrement EDX"); +put(name, "4b", "decrement EBX"); +put(name, "4c", "decrement ESP"); +put(name, "4d", "decrement EBP"); +put(name, "4e", "decrement ESI"); +put(name, "4f", "decrement EDI"); :(scenario decrement_r32) % Reg[ECX].u = 0x1f; @@ -506,14 +506,14 @@ case 1: { // decrement r/m32 //:: push :(before "End Initialize Op Names(name)") -put(name, "50", "push R0 (EAX) to stack"); -put(name, "51", "push R1 (ECX) to stack"); -put(name, "52", "push R2 (EDX) to stack"); -put(name, "53", "push R3 (EBX) to stack"); -put(name, "54", "push R4 (ESP) to stack"); -put(name, "55", "push R5 (EBP) to stack"); -put(name, "56", "push R6 (ESI) to stack"); -put(name, "57", "push R7 (EDI) to stack"); +put(name, "50", "push EAX to stack"); +put(name, "51", "push ECX to stack"); +put(name, "52", "push EDX to stack"); +put(name, "53", "push EBX to stack"); +put(name, "54", "push ESP to stack"); +put(name, "55", "push EBP to stack"); +put(name, "56", "push ESI to stack"); +put(name, "57", "push EDI to stack"); :(scenario push_r32) % Reg[ESP].u = 0x64; @@ -544,14 +544,14 @@ case 0x57: { // push r32 to stack //:: pop :(before "End Initialize Op Names(name)") -put(name, "58", "pop top of stack to R0 (EAX)"); -put(name, "59", "pop top of stack to R1 (ECX)"); -put(name, "5a", "pop top of stack to R2 (EDX)"); -put(name, "5b", "pop top of stack to R3 (EBX)"); -put(name, "5c", "pop top of stack to R4 (ESP)"); -put(name, "5d", "pop top of stack to R5 (EBP)"); -put(name, "5e", "pop top of stack to R6 (ESI)"); -put(name, "5f", "pop top of stack to R7 (EDI)"); +put(name, "58", "pop top of stack to EAX"); +put(name, "59", "pop top of stack to ECX"); +put(name, "5a", "pop top of stack to EDX"); +put(name, "5b", "pop top of stack to EBX"); +put(name, "5c", "pop top of stack to ESP"); +put(name, "5d", "pop top of stack to EBP"); +put(name, "5e", "pop top of stack to ESI"); +put(name, "5f", "pop top of stack to EDI"); :(scenario pop_r32) % Reg[ESP].u = 0x2000; diff --git a/subx/015immediate_addressing.cc b/subx/015immediate_addressing.cc index 01f7e040..7f1f1a7e 100644 --- a/subx/015immediate_addressing.cc +++ b/subx/015immediate_addressing.cc @@ -55,7 +55,7 @@ case 0x81: { // combine imm32 with r/m32 //:: subtract :(before "End Initialize Op Names(name)") -put(name, "2d", "subtract imm32 from R0 (EAX)"); +put(name, "2d", "subtract imm32 from EAX"); :(scenario subtract_imm32_from_eax) % Reg[EAX].i = 0x0d0c0baa; @@ -113,7 +113,7 @@ case 5: { //:: and :(before "End Initialize Op Names(name)") -put(name, "25", "R0 = bitwise AND of imm32 with R0 (EAX)"); +put(name, "25", "EAX = bitwise AND of imm32 with EAX"); :(scenario and_imm32_with_eax) % Reg[EAX].i = 0xff; @@ -171,7 +171,7 @@ case 4: { //:: or :(before "End Initialize Op Names(name)") -put(name, "0d", "R0 = bitwise OR of imm32 with R0 (EAX)"); +put(name, "0d", "EAX = bitwise OR of imm32 with EAX"); :(scenario or_imm32_with_eax) % Reg[EAX].i = 0xd0c0b0a0; @@ -227,7 +227,7 @@ case 1: { //:: xor :(before "End Initialize Op Names(name)") -put(name, "35", "R0 = bitwise XOR of imm32 with R0 (EAX)"); +put(name, "35", "EAX = bitwise XOR of imm32 with EAX"); :(scenario xor_imm32_with_eax) % Reg[EAX].i = 0xddccb0a0; @@ -283,7 +283,7 @@ case 6: { //:: compare (cmp) :(before "End Initialize Op Names(name)") -put(name, "3d", "compare: set SF if R0 < imm32"); +put(name, "3d", "compare: set SF if EAX < imm32"); :(scenario compare_imm32_with_eax_greater) % Reg[EAX].i = 0x0d0c0b0a; @@ -413,14 +413,14 @@ case 7: { //:: copy (mov) :(before "End Initialize Op Names(name)") -put(name, "b8", "copy imm32 to R0 (EAX)"); -put(name, "b9", "copy imm32 to R1 (ECX)"); -put(name, "ba", "copy imm32 to R2 (EDX)"); -put(name, "bb", "copy imm32 to R3 (EBX)"); -put(name, "bc", "copy imm32 to R4 (ESP)"); -put(name, "bd", "copy imm32 to R5 (EBP)"); -put(name, "be", "copy imm32 to R6 (ESI)"); -put(name, "bf", "copy imm32 to R7 (EDI)"); +put(name, "b8", "copy imm32 to EAX"); +put(name, "b9", "copy imm32 to ECX"); +put(name, "ba", "copy imm32 to EDX"); +put(name, "bb", "copy imm32 to EBX"); +put(name, "bc", "copy imm32 to ESP"); +put(name, "bd", "copy imm32 to EBP"); +put(name, "be", "copy imm32 to ESI"); +put(name, "bf", "copy imm32 to EDI"); :(scenario copy_imm32_to_r32) == 0x1 diff --git a/subx/030---operands.cc b/subx/030---operands.cc index 196e8556..4015174b 100644 --- a/subx/030---operands.cc +++ b/subx/030---operands.cc @@ -72,9 +72,10 @@ void init_operand_type_help() { " Using it as an address gets more involved. For more details,\n" " try reading the help pages for 'base', 'index' and 'scale'.)\n" "\n" - "For complete details consult the IA-32 software developer's manual, table 2-2,\n" - "\"32-bit addressing forms with the ModR/M byte\".\n" - " https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf\n" + "For complete details, spend some time with two tables in the IA-32 software\n" + "developer's manual that are also included in this repo:\n" + " - modrm.pdf: volume 2, table 2-2, \"32-bit addressing with the ModR/M byte.\".\n" + " - sib.pdf: volume 2, table 2-3, \"32-bit addressing with the SIB byte.\".\n" ); put(Help, "subop", "Additional 3-bit operand for determining the instruction when the opcode is 81, 8f or ff.\n" @@ -84,34 +85,47 @@ void init_operand_type_help() { "3-bit operand specifying a register operand used directly, without any further addressing modes.\n" ); put(Help, "rm32", - "32-bit value in register or memory. The precise details of its construction depend on the eponymous 3-bit\n" - "'rm32' operand, the 'mod' operand, and also potentially the 'SIB' operands ('scale', 'index' and 'base')\n" - "and a displacement ('disp8' or 'disp32').\n" - "For complete details consult the IA-32 software developer's manual, table 2-2,\n" - "\"32-bit addressing forms with the ModR/M byte\".\n" - " https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf\n" + "32-bit value in register or memory. The precise details of its construction\n" + "depend on the eponymous 3-bit 'rm32' operand, the 'mod' operand, and also\n" + "potentially the 'SIB' operands ('scale', 'index' and 'base') and a displacement\n" + "('disp8' or 'disp32').\n" + "\n" + "For complete details, spend some time with two tables in the IA-32 software\n" + "developer's manual that are also included in this repo:\n" + " - modrm.pdf: volume 2, table 2-2, \"32-bit addressing with the ModR/M byte.\".\n" + " - sib.pdf: volume 2, table 2-3, \"32-bit addressing with the SIB byte.\".\n" ); put(Help, "base", - "Additional 3-bit operand (when 'rm32' is 4 unless 'mod' is 3) specifying the register containing an address to look up.\n" + "Additional 3-bit operand (when 'rm32' is 4, unless 'mod' is 3) specifying the\n" + "register containing an address to look up.\n" "This address may be further modified by 'index' and 'scale' operands.\n" " effective address = base + index*scale + displacement (disp8 or disp32)\n" - "For complete details consult the IA-32 software developer's manual, table 2-3,\n" - "\"32-bit addressing forms with the SIB byte\".\n" - " https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf\n" + "For complete details, spend some time with the IA-32 software developer's manual,\n" + "volume 2, table 2-3, \"32-bit addressing with the SIB byte\".\n" + "It is included in this repository as 'sib.pdf'.\n" ); put(Help, "index", - "Optional 3-bit operand (when 'rm32' is 4 unless 'mod' is 3) that can be added to the 'base' operand to compute the 'effective address' at which to look up memory.\n" + "Optional 3-bit operand (when 'rm32' is 4 unless 'mod' is 3) that can be added to\n" + "the 'base' operand to compute the 'effective address' at which to look up memory.\n" " effective address = base + index*scale + displacement (disp8 or disp32)\n" - "For complete details consult the IA-32 software developer's manual, table 2-3,\n" - "\"32-bit addressing forms with the SIB byte\".\n" - " https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf\n" + "For complete details, spend some time with the IA-32 software developer's manual,\n" + "volume 2, table 2-3, \"32-bit addressing with the SIB byte\".\n" + "It is included in this repository as 'sib.pdf'.\n" ); put(Help, "scale", - "Optional 2-bit operand (when 'rm32' is 4 unless 'mod' is 3) that can be multiplied to the 'index' operand before adding the result to the 'base' operand to compute the _effective address_ to operate on.\n" + "Optional 2-bit operand (when 'rm32' is 4 unless 'mod' is 3) that encodes a\n" + "power of 2 to be multiplied to the 'index' operand before adding the result to\n" + "the 'base' operand to compute the _effective address_ to operate on.\n" " effective address = base + index * scale + displacement (disp8 or disp32)\n" - "For complete details consult the IA-32 software developer's manual, table 2-3,\n" - "\"32-bit addressing forms with the SIB byte\".\n" - " https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf\n" + "\n" + "When scale is 0, use index unmodified.\n" + "When scale is 1, multiply index by 2.\n" + "When scale is 2, multiply index by 4.\n" + "When scale is 3, multiply index by 8.\n" + "\n" + "For complete details, spend some time with the IA-32 software developer's manual,\n" + "volume 2, table 2-3, \"32-bit addressing with the SIB byte\".\n" + "It is included in this repository as 'sib.pdf'.\n" ); put(Help, "disp8", "8-bit value to be added in many instructions.\n" diff --git a/subx/modrm.pdf b/subx/modrm.pdf new file mode 100644 index 00000000..552aec53 --- /dev/null +++ b/subx/modrm.pdf Binary files differdiff --git a/subx/sib.pdf b/subx/sib.pdf new file mode 100644 index 00000000..735a40ca --- /dev/null +++ b/subx/sib.pdf Binary files differ |