1
2
3 :(scenario add_r32_to_r32)
4 % Reg[0].i = 0x10;
5 % Reg[3].i = 1;
6
7 01 d8
8
9 +run: add EBX to r/m32
10 +run: r/m32 is EAX
11 +run: storing 0x00000011
12
13 :(before "End Single-Byte Opcodes")
14 case 0x01: {
15 uint8_t modrm = next();
16 uint8_t arg2 = (modrm>>3)&0x7;
17 trace(2, "run") << "add " << rname(arg2) << " to r/m32" << end();
18 int32_t* arg1 = effective_address(modrm);
19 BINARY_ARITHMETIC_OP(+, *arg1, Reg[arg2].i);
20 break;
21 }
22
23 :(code)
24
25
26
27 int32_t* effective_address(uint8_t modrm) {
28 uint8_t mod = (modrm>>6);
29
30 uint8_t rm = modrm & 0x7;
31 uint32_t addr = 0;
32 switch (mod) {
33 case 3:
34
35 trace(2, "run") << "r/m32 is " << rname(rm) << end();
36 return &Reg[rm].i;
37
38 default:
39 cerr << "unrecognized mod bits: " << NUM(mod) << '\n';
40 exit(1);
41 }
42
43 assert(addr > 0);
44 assert(addr + sizeof(int32_t) <= Mem.size());
45 return reinterpret_cast<int32_t*>(&Mem.at(addr));
46 }
47
48
49
50 :(scenario subtract_r32_from_r32)
51 % Reg[0].i = 10;
52 % Reg[3].i = 1;
53
54 29 d8
55
56 +run: subtract EBX from r/m32
57 +run: r/m32 is EAX
58 +run: storing 0x00000009
59
60 :(before "End Single-Byte Opcodes")
61 case 0x29: {
62 uint8_t modrm = next();
63 uint8_t arg2 = (modrm>>3)&0x7;
64 trace(2, "run") << "subtract " << rname(arg2) << " from r/m32" << end();
65 int32_t* arg1 = effective_address(modrm);
66 BINARY_ARITHMETIC_OP(-, *arg1, Reg[arg2].i);
67 break;
68 }
69
70
71
72 :(scenario and_r32_with_r32)
73 % Reg[0].i = 0x0a0b0c0d;
74 % Reg[3].i = 0x000000ff;
75
76 21 d8
77
78 +run: and EBX with r/m32
79 +run: r/m32 is EAX
80 +run: storing 0x0000000d
81
82 :(before "End Single-Byte Opcodes")
83 case 0x21: {
84 uint8_t modrm = next();
85 uint8_t arg2 = (modrm>>3)&0x7;
86 trace(2, "run") << "and " << rname(arg2) << " with r/m32" << end();
87 int32_t* arg1 = effective_address(modrm);
88 BINARY_BITWISE_OP(&, *arg1, Reg[arg2].u);
89 break;
90 }
91
92
93
94 :(scenario or_r32_with_r32)
95 % Reg[0].i = 0x0a0b0c0d;
96 % Reg[3].i = 0xa0b0c0d0;
97
98 09 d8
99
100 +run: or EBX with r/m32
101 +run: r/m32 is EAX
102 +run: storing 0xaabbccdd
103
104 :(before "End Single-Byte Opcodes")
105 case 0x09: {
106 uint8_t modrm = next();
107 uint8_t arg2 = (modrm>>3)&0x7;
108 trace(2, "run") << "or " << rname(arg2) << " with r/m32" << end();
109 int32_t* arg1 = effective_address(modrm);
110 BINARY_BITWISE_OP(|, *arg1, Reg[arg2].u);
111 break;
112 }
113
114
115
116 :(scenario xor_r32_with_r32)
117 % Reg[0].i = 0x0a0b0c0d;
118 % Reg[3].i = 0xaabbc0d0;
119
120 31 d8
121
122 +run: xor EBX with r/m32
123 +run: r/m32 is EAX
124 +run: storing 0xa0b0ccdd
125
126 :(before "End Single-Byte Opcodes")
127 case 0x31: {
128 uint8_t modrm = next();
129 uint8_t arg2 = (modrm>>3)&0x7;
130 trace(2, "run") << "xor " << rname(arg2) << " with r/m32" << end();
131 int32_t* arg1 = effective_address(modrm);
132 BINARY_BITWISE_OP(^, *arg1, Reg[arg2].u);
133 break;
134 }
135
136
137
138 :(scenario not_r32)
139 % Reg[3].i = 0x0f0f00ff;
140
141 f7 c3
142
143 +run: 'not' of r/m32
144 +run: r/m32 is EBX
145 +run: storing 0xf0f0ff00
146
147 :(before "End Single-Byte Opcodes")
148 case 0xf7: {
149 uint8_t modrm = next();
150 trace(2, "run") << "'not' of r/m32" << end();
151 int32_t* arg1 = effective_address(modrm);
152 *arg1 = ~(*arg1);
153 trace(2, "run") << "storing 0x" << HEXWORD << *arg1 << end();
154 SF = (*arg1 >> 31);
155 ZF = (*arg1 == 0);
156 OF = false;
157 break;
158 }
159
160
161
162 :(scenario compare_r32_with_r32_greater)
163 % Reg[0].i = 0x0a0b0c0d;
164 % Reg[3].i = 0x0a0b0c07;
165
166 39 d8
167
168 +run: compare EBX with r/m32
169 +run: r/m32 is EAX
170 +run: SF=0; ZF=0; OF=0
171
172 :(before "End Single-Byte Opcodes")
173 case 0x39: {
174 uint8_t modrm = next();
175 uint8_t reg2 = (modrm>>3)&0x7;
176 trace(2, "run") << "compare " << rname(reg2) << " with r/m32" << end();
177 int32_t* arg1 = effective_address(modrm);
178 int32_t arg2 = Reg[reg2].i;
179 int32_t tmp1 = *arg1 - arg2;
180 SF = (tmp1 < 0);
181 ZF = (tmp1 == 0);
182 int64_t tmp2 = *arg1 - arg2;
183 OF = (tmp1 != tmp2);
184 trace(2, "run") << "SF=" << SF << "; ZF=" << ZF << "; OF=" << OF << end();
185 break;
186 }
187
188 :(scenario compare_r32_with_r32_lesser)
189 % Reg[0].i = 0x0a0b0c07;
190 % Reg[3].i = 0x0a0b0c0d;
191
192 39 d8
193
194 +run: compare EBX with r/m32
195 +run: r/m32 is EAX
196 +run: SF=1; ZF=0; OF=0
197
198 :(scenario compare_r32_with_r32_equal)
199 % Reg[0].i = 0x0a0b0c0d;
200 % Reg[3].i = 0x0a0b0c0d;
201
202 39 d8
203
204 +run: compare EBX with r/m32
205 +run: r/m32 is EAX
206 +run: SF=0; ZF=1; OF=0
207
208
209
210 :(scenario copy_r32_to_r32)
211 % Reg[3].i = 0xaf;
212
213 89 d8
214
215 +run: copy EBX to r/m32
216 +run: r/m32 is EAX
217 +run: storing 0x000000af
218
219 :(before "End Single-Byte Opcodes")
220 case 0x89: {
221 uint8_t modrm = next();
222 uint8_t reg2 = (modrm>>3)&0x7;
223 trace(2, "run") << "copy " << rname(reg2) << " to r/m32" << end();
224 int32_t* arg1 = effective_address(modrm);
225 *arg1 = Reg[reg2].i;
226 trace(2, "run") << "storing 0x" << HEXWORD << *arg1 << end();
227 break;
228 }
229
230
231
232 :(scenario xchg_r32_with_r32)
233 % Reg[3].i = 0xaf;
234 % Reg[0].i = 0x2e;
235
236 87 d8
237
238 +run: exchange EBX with r/m32
239 +run: r/m32 is EAX
240 +run: storing 0x000000af in r/m32
241 +run: storing 0x0000002e in EBX
242
243 :(before "End Single-Byte Opcodes")
244 case 0x87: {
245 uint8_t modrm = next();
246 uint8_t reg2 = (modrm>>3)&0x7;
247 trace(2, "run") << "exchange " << rname(reg2) << " with r/m32" << end();
248 int32_t* arg1 = effective_address(modrm);
249 int32_t tmp = *arg1;
250 *arg1 = Reg[reg2].i;
251 Reg[reg2].i = tmp;
252 trace(2, "run") << "storing 0x" << HEXWORD << *arg1 << " in r/m32" << end();
253 trace(2, "run") << "storing 0x" << HEXWORD << Reg[reg2].i << " in " << rname(reg2) << end();
254 break;
255 }
256
257
258
259 :(scenario push_r32)
260 % Reg[ESP].u = 0x64;
261 % Reg[EBX].i = 0x0000000a;
262
263 53
264 +run: push EBX
265 +run: decrementing ESP to 0x00000060
266 +run: pushing value 0x0000000a
267
268 :(before "End Single-Byte Opcodes")
269 case 0x50:
270 case 0x51:
271 case 0x52:
272 case 0x53:
273 case 0x54:
274 case 0x55:
275 case 0x56:
276 case 0x57: {
277 uint8_t reg = op & 0x7;
278 trace(2, "run") << "push " << rname(reg) << end();
279 push(Reg[reg].u);
280 break;
281 }
282 :(code)
283 void push(uint32_t val) {
284 Reg[ESP].u -= 4;
285 trace(2, "run") << "decrementing ESP to 0x" << HEXWORD << Reg[ESP].u << end();
286 trace(2, "run") << "pushing value 0x" << HEXWORD << val << end();
287 *reinterpret_cast<uint32_t*>(&Mem.at(Reg[ESP].u)) = val;
288 }
289
290
291
292 :(scenario pop_r32)
293 % Reg[ESP].u = 0x60;
294 % SET_WORD_IN_MEM(0x60, 0x0000000a);
295
296 5b
297 +run: pop into EBX
298 +run: popping value 0x0000000a
299 +run: incrementing ESP to 0x00000064
300
301 :(before "End Single-Byte Opcodes")
302 case 0x58:
303 case 0x59:
304 case 0x5a:
305 case 0x5b:
306 case 0x5c:
307 case 0x5d:
308 case 0x5e:
309 case 0x5f: {
310 uint8_t reg = op & 0x7;
311 trace(2, "run") << "pop into " << rname(reg) << end();
312 Reg[reg].u = pop();
313 break;
314 }
315 :(code)
316 uint32_t pop() {
317 uint32_t result = *reinterpret_cast<uint32_t*>(&Mem.at(Reg[ESP].u));
318 trace(2, "run") << "popping value 0x" << HEXWORD << result << end();
319 Reg[ESP].u += 4;
320 trace(2, "run") << "incrementing ESP to 0x" << HEXWORD << Reg[ESP].u << end();
321 return result;
322 }