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
72
73
74 :(scenario add_imm32_to_eax)
75
76
77 #
78
79
80
81
82 ¦ 05 0a 0b 0c 0d
83
84 +load: 1 -> 05
85 +load: 2 -> 0a
86 +load: 3 -> 0b
87 +load: 4 -> 0c
88 +load: 5 -> 0d
89 +run: add imm32 0x0d0c0b0a to reg EAX
90 +run: storing 0x0d0c0b0a
91
92 :(code)
93
94
95 void run(const string& text_bytes) {
96 load_program(text_bytes);
97 EIP = 1;
98 while (EIP < End_of_program)
99 ¦ run_one_instruction();
100 }
101
102
103 void run_one_instruction() {
104 uint8_t op=0, op2=0, op3=0;
105 switch (op = next()) {
106 case 0xf4:
107 ¦ EIP = End_of_program;
108 ¦ break;
109
110 case 0x05: {
111 ¦ int32_t arg2 = imm32();
112 ¦ trace(2, "run") << "add imm32 0x" << HEXWORD << arg2 << " to reg EAX" << end();
113 ¦ BINARY_ARITHMETIC_OP(+, Reg[EAX].i, arg2);
114 ¦ break;
115 }
116
117 case 0x0f:
118 ¦ switch(op2 = next()) {
119 ¦
120 ¦ default:
121 ¦ ¦ cerr << "unrecognized second opcode after 0f: " << HEXBYTE << NUM(op2) << '\n';
122 ¦ ¦ exit(1);
123 ¦ }
124 ¦ break;
125 case 0xf3:
126 ¦ switch(op2 = next()) {
127 ¦
128 ¦ case 0x0f:
129 ¦ ¦ switch(op3 = next()) {
130 ¦ ¦
131 ¦ ¦ default:
132 ¦ ¦ ¦ cerr << "unrecognized third opcode after f3 0f: " << HEXBYTE << NUM(op3) << '\n';
133 ¦ ¦ ¦ exit(1);
134 ¦ ¦ }
135 ¦ ¦ break;
136 ¦ default:
137 ¦ ¦ cerr << "unrecognized second opcode after f3: " << HEXBYTE << NUM(op2) << '\n';
138 ¦ ¦ exit(1);
139 ¦ }
140 ¦ break;
141 default:
142 ¦ cerr << "unrecognized opcode: " << HEXBYTE << NUM(op) << '\n';
143 ¦ exit(1);
144 }
145 }
146
147 void load_program(const string& text_bytes) {
148 uint32_t addr = 1;
149 istringstream in(text_bytes);
150 in >> std::noskipws;
151 while (has_data(in)) {
152 ¦ char c1 = next_hex_byte(in);
153 ¦ if (c1 == '\0') break;
154 ¦ if (!has_data(in)) {
155 ¦ ¦ raise << "input program truncated mid-byte\n" << end();
156 ¦ ¦ return;
157 ¦ }
158 ¦ char c2 = next_hex_byte(in);
159 ¦ if (c2 == '\0') {
160 ¦ ¦ raise << "input program truncated mid-byte\n" << end();
161 ¦ ¦ return;
162 ¦ }
163 ¦ Mem.at(addr) = to_byte(c1, c2);
164 ¦ trace(99, "load") << addr << " -> " << HEXBYTE << NUM(Mem.at(addr)) << end();
165 ¦ addr++;
166 }
167 End_of_program = addr;
168 }
169
170 char next_hex_byte(istream& in) {
171 while (has_data(in)) {
172 ¦ char c = '\0';
173 ¦ in >> c;
174 ¦ if (c == ' ' || c == '\n') continue;
175 ¦ while (c == '#') {
176 ¦ ¦ while (has_data(in)) {
177 ¦ ¦ ¦ in >> c;
178 ¦ ¦ ¦ if (c == '\n') {
179 ¦ ¦ ¦ ¦ in >> c;
180 ¦ ¦ ¦ ¦ break;
181 ¦ ¦ ¦ }
182 ¦ ¦ }
183 ¦ }
184 ¦ if (c >= '0' && c <= '9') return c;
185 ¦ else if (c >= 'a' && c <= 'f') return c;
186 ¦ else if (c >= 'A' && c <= 'F') return tolower(c);
187 ¦
188 ¦ if (!isspace(c)) {
189 ¦ ¦ raise << "invalid non-hex character '" << c << "'\n" << end();
190 ¦ ¦ break;
191 ¦ }
192 }
193 return '\0';
194 }
195
196 uint8_t to_byte(char hex_byte1, char hex_byte2) {
197 return to_hex_num(hex_byte1)*16 + to_hex_num(hex_byte2);
198 }
199 uint8_t to_hex_num(char c) {
200 if (c >= '0' && c <= '9') return c - '0';
201 if (c >= 'a' && c <= 'f') return c - 'a' + 10;
202 assert(false);
203 return 0;
204 }
205
206 inline uint8_t next() {
207 return Mem.at(EIP++);
208 }
209
210
211 int32_t imm32() {
212 int32_t result = next();
213 result |= (next()<<8);
214 result |= (next()<<16);
215 result |= (next()<<24);
216 return result;
217 }
218
219 :(before "End Includes")
220 #include <iomanip>
221 #define HEXBYTE std::hex << std::setw(2) << std::setfill('0')
222 #define HEXWORD std::hex << std::setw(8) << std::setfill('0')
223
224 #define NUM(X) static_cast<int>(X)
225 #include <stdint.h>