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