1
2
3 :(before "End Types")
4 enum {
5 EAX,
6 ECX,
7 EDX,
8 EBX,
9 ESP,
10 EBP,
11 ESI,
12 EDI,
13 NUM_INT_REGISTERS,
14 };
15 union reg {
16 int32_t i;
17 uint32_t u;
18 };
19 :(before "End Globals")
20 reg Reg[NUM_INT_REGISTERS] = { {0} };
21 uint32_t EIP = 0;
22 :(before "End Reset")
23 bzero(Reg, sizeof(Reg));
24 EIP = 0;
25
26
27
28 :(before "End Globals")
29 bool SF = false;
30 bool ZF = false;
31 bool OF = false;
32 :(before "End Reset")
33 SF = ZF = OF = false;
34
35
36
37 :(before "End Includes")
38
39
40
41 #define BINARY_ARITHMETIC_OP(op, arg1, arg2) { \
42 \
43 int64_t tmp = arg1 op arg2; \
44 arg1 = arg1 op arg2; \
45 trace(2, "run") << "storing 0x" << HEXWORD << arg1 << end(); \
46 SF = (arg1 < 0); \
47 ZF = (arg1 == 0); \
48 OF = (arg1 != tmp); \
49 }
50
51
52
53 #define BINARY_BITWISE_OP(op, arg1, arg2) { \
54 \
55 arg1 = arg1 op arg2; \
56 trace(2, "run") << "storing 0x" << HEXWORD << arg1 << end(); \
57 SF = (arg1 >> 31); \
58 ZF = (arg1 == 0); \
59 OF = false; \
60 }
61
62
63
64 :(before "End Globals")
65 vector<uint8_t> Mem;
66 uint32_t End_of_program = 0;
67 :(before "End Reset")
68 Mem.clear();
69 Mem.resize(1024);
70 End_of_program = 0;
71 :(before "End Includes")
72
73
74 #define SET_WORD_IN_MEM(addr, val) *reinterpret_cast<int32_t*>(&Mem.at(addr)) = val;
75
76
77
78 :(scenario add_imm32_to_eax)
79
80
81 #
82
83
84
85
86 ¦ 05 0a 0b 0c 0d
87
88 +load: 1 -> 05
89 +load: 2 -> 0a
90 +load: 3 -> 0b
91 +load: 4 -> 0c
92 +load: 5 -> 0d
93 +run: add imm32 0x0d0c0b0a to reg EAX
94 +run: storing 0x0d0c0b0a
95
96 :(code)
97
98
99 void run(const string& text_bytes) {
100 load_program(text_bytes);
101 EIP = 1;
102 while (EIP < End_of_program)
103 ¦ run_one_instruction();
104 }
105
106
107 void run_one_instruction() {
108 uint8_t op=0, op2=0, op3=0;
109 trace(2, "run") << "inst: 0x" << HEXWORD << EIP << end();
110 switch (op = next()) {
111 case 0xf4:
112 ¦ EIP = End_of_program;
113 ¦ break;
114
115 case 0x05: {
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
122 case 0x0f:
123 ¦ switch(op2 = next()) {
124 ¦
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 ¦
133 ¦ case 0x0f:
134 ¦ ¦ switch(op3 = next()) {
135 ¦ ¦
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 ¦
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
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
230 #define NUM(X) static_cast<int>(X)
231 #include <stdint.h>