1
2
3 :(before "End Initialize Op Names(name)")
4 put(name, "01", "add r32 to rm32");
5
6 :(scenario add_r32_to_r32)
7 % Reg[EAX].i = 0x10;
8 % Reg[EBX].i = 1;
9 == 0x1
10
11 01 d8
12
13 +run: add EBX to r/m32
14 +run: r/m32 is EAX
15 +run: storing 0x00000011
16
17 :(before "End Single-Byte Opcodes")
18 case 0x01: {
19 uint8_t modrm = next();
20 uint8_t arg2 = (modrm>>3)&0x7;
21 trace(90, "run") << "add " << rname(arg2) << " to r/m32" << end();
22 int32_t* arg1 = effective_address(modrm);
23 BINARY_ARITHMETIC_OP(+, *arg1, Reg[arg2].i);
24 break;
25 }
26
27 :(code)
28
29
30
31 int32_t* effective_address(uint8_t modrm) {
32 uint8_t mod = (modrm>>6);
33
34 uint8_t rm = modrm & 0x7;
35 uint32_t addr = 0;
36 switch (mod) {
37 case 3:
38
39 trace(90, "run") << "r/m32 is " << rname(rm) << end();
40 return &Reg[rm].i;
41
42 default:
43 cerr << "unrecognized mod bits: " << NUM(mod) << '\n';
44 exit(1);
45 }
46
47 return mem_addr_i32(addr);
48 }
49
50 string rname(uint8_t r) {
51 switch (r) {
52 case 0: return "EAX";
53 case 1: return "ECX";
54 case 2: return "EDX";
55 case 3: return "EBX";
56 case 4: return "ESP";
57 case 5: return "EBP";
58 case 6: return "ESI";
59 case 7: return "EDI";
60 default: raise << "invalid register " << r << '\n' << end(); return "";
61 }
62 }
63
64
65
66 :(before "End Initialize Op Names(name)")
67 put(name, "29", "subtract r32 from rm32");
68
69 :(scenario subtract_r32_from_r32)
70 % Reg[EAX].i = 10;
71 % Reg[EBX].i = 1;
72 == 0x1
73
74 29 d8
75
76 +run: subtract EBX from r/m32
77 +run: r/m32 is EAX
78 +run: storing 0x00000009
79
80 :(before "End Single-Byte Opcodes")
81 case 0x29: {
82 uint8_t modrm = next();
83 uint8_t arg2 = (modrm>>3)&0x7;
84 trace(90, "run") << "subtract " << rname(arg2) << " from r/m32" << end();
85 int32_t* arg1 = effective_address(modrm);
86 BINARY_ARITHMETIC_OP(-, *arg1, Reg[arg2].i);
87 break;
88 }
89
90
91
92 :(before "End Initialize Op Names(name)")
93 put(name_0f, "af", "multiply rm32 into r32");
94
95 :(scenario multiply_r32_into_r32)
96 % Reg[EAX].i = 4;
97 % Reg[EBX].i = 2;
98 == 0x1
99
100 0f af d8
101
102 +run: multiply r/m32 into EBX
103 +run: r/m32 is EAX
104 +run: storing 0x00000008
105
106 :(before "End Two-Byte Opcodes Starting With 0f")
107 case 0xaf: {
108 uint8_t modrm = next();
109 uint8_t arg2 = (modrm>>3)&0x7;
110 trace(90, "run") << "multiply r/m32 into " << rname(arg2) << end();
111 int32_t* arg1 = effective_address(modrm);
112 BINARY_ARITHMETIC_OP(*, Reg[arg2].i, *arg1);
113 break;
114 }
115
116
117
118 :(before "End Initialize Op Names(name)")
119 put(name, "21", "rm32 = bitwise AND of r32 with rm32");
120
121 :(scenario and_r32_with_r32)
122 % Reg[EAX].i = 0x0a0b0c0d;
123 % Reg[EBX].i = 0x000000ff;
124 == 0x1
125
126 21 d8
127
128 +run: and EBX with r/m32
129 +run: r/m32 is EAX
130 +run: storing 0x0000000d
131
132 :(before "End Single-Byte Opcodes")
133 case 0x21: {
134 uint8_t modrm = next();
135 uint8_t arg2 = (modrm>>3)&0x7;
136 trace(90, "run") << "and " << rname(arg2) << " with r/m32" << end();
137 int32_t* arg1 = effective_address(modrm);
138 BINARY_BITWISE_OP(&, *arg1, Reg[arg2].u);
139 break;
140 }
141
142
143
144 :(before "End Initialize Op Names(name)")
145 put(name, "09", "rm32 = bitwise OR of r32 with rm32");
146
147 :(scenario or_r32_with_r32)
148 % Reg[EAX].i = 0x0a0b0c0d;
149 % Reg[EBX].i = 0xa0b0c0d0;
150 == 0x1
151
152 09 d8
153
154 +run: or EBX with r/m32
155 +run: r/m32 is EAX
156 +run: storing 0xaabbccdd
157
158 :(before "End Single-Byte Opcodes")
159 case 0x09: {
160 uint8_t modrm = next();
161 uint8_t arg2 = (modrm>>3)&0x7;
162 trace(90, "run") << "or " << rname(arg2) << " with r/m32" << end();
163 int32_t* arg1 = effective_address(modrm);
164 BINARY_BITWISE_OP(|, *arg1, Reg[arg2].u);
165 break;
166 }
167
168
169
170 :(before "End Initialize Op Names(name)")
171 put(name, "31", "rm32 = bitwise XOR of r32 with rm32");
172
173 :(scenario xor_r32_with_r32)
174 % Reg[EAX].i = 0x0a0b0c0d;
175 % Reg[EBX].i = 0xaabbc0d0;
176 == 0x1
177
178 31 d8
179
180 +run: xor EBX with r/m32
181 +run: r/m32 is EAX
182 +run: storing 0xa0b0ccdd
183
184 :(before "End Single-Byte Opcodes")
185 case 0x31: {
186 uint8_t modrm = next();
187 uint8_t arg2 = (modrm>>3)&0x7;
188 trace(90, "run") << "xor " << rname(arg2) << " with r/m32" << end();
189 int32_t* arg1 = effective_address(modrm);
190 BINARY_BITWISE_OP(^, *arg1, Reg[arg2].u);
191 break;
192 }
193
194
195
196 :(before "End Initialize Op Names(name)")
197 put(name, "f7", "bitwise complement of rm32");
198
199 :(scenario not_r32)
200 % Reg[EBX].i = 0x0f0f00ff;
201 == 0x1
202
203 f7 c3
204
205 +run: 'not' of r/m32
206 +run: r/m32 is EBX
207 +run: storing 0xf0f0ff00
208
209 :(before "End Single-Byte Opcodes")
210 case 0xf7: {
211 uint8_t modrm = next();
212 trace(90, "run") << "'not' of r/m32" << end();
213 int32_t* arg1 = effective_address(modrm);
214 *arg1 = ~(*arg1);
215 trace(90, "run") << "storing 0x" << HEXWORD << *arg1 << end();
216 SF = (*arg1 >> 31);
217 ZF = (*arg1 == 0);
218 OF = false;
219 break;
220 }
221
222
223
224 :(before "End Initialize Op Names(name)")
225 put(name, "39", "set SF if rm32 < r32");
226
227 :(scenario compare_r32_with_r32_greater)
228 % Reg[EAX].i = 0x0a0b0c0d;
229 % Reg[EBX].i = 0x0a0b0c07;
230 == 0x1
231
232 39 d8
233
234 +run: compare EBX with r/m32
235 +run: r/m32 is EAX
236 +run: SF=0; ZF=0; OF=0
237
238 :(before "End Single-Byte Opcodes")
239 case 0x39: {
240 uint8_t modrm = next();
241 uint8_t reg2 = (modrm>>3)&0x7;
242 trace(90, "run") << "compare " << rname(reg2) << " with r/m32" << end();
243 int32_t* arg1 = effective_address(modrm);
244 int32_t arg2 = Reg[reg2].i;
245 int32_t tmp1 = *arg1 - arg2;
246 SF = (tmp1 < 0);
247 ZF = (tmp1 == 0);
248 int64_t tmp2 = *arg1 - arg2;
249 OF = (tmp1 != tmp2);
250 trace(90, "run") << "SF=" << SF << "; ZF=" << ZF << "; OF=" << OF << end();
251 break;
252 }
253
254 :(scenario compare_r32_with_r32_lesser)
255 % Reg[EAX].i = 0x0a0b0c07;
256 % Reg[EBX].i = 0x0a0b0c0d;
257 == 0x1
258
259 39 d8
260
261 +run: compare EBX with r/m32
262 +run: r/m32 is EAX
263 +run: SF=1; ZF=0; OF=0
264
265 :(scenario compare_r32_with_r32_equal)
266 % Reg[EAX].i = 0x0a0b0c0d;
267 % Reg[EBX].i = 0x0a0b0c0d;
268 == 0x1
269
270 39 d8
271
272 +run: compare EBX with r/m32
273 +run: r/m32 is EAX
274 +run: SF=0; ZF=1; OF=0
275
276
277
278 :(before "End Initialize Op Names(name)")
279 put(name, "89", "copy r32 to rm32");
280
281 :(scenario copy_r32_to_r32)
282 % Reg[EBX].i = 0xaf;
283 == 0x1
284
285 89 d8
286
287 +run: copy EBX to r/m32
288 +run: r/m32 is EAX
289 +run: storing 0x000000af
290
291 :(before "End Single-Byte Opcodes")
292 case 0x89: {
293 uint8_t modrm = next();
294 uint8_t reg2 = (modrm>>3)&0x7;
295 trace(90, "run") << "copy " << rname(reg2) << " to r/m32" << end();
296 int32_t* arg1 = effective_address(modrm);
297 *arg1 = Reg[reg2].i;
298 trace(90, "run") << "storing 0x" << HEXWORD << *arg1 << end();
299 break;
300 }
301
302
303
304 :(before "End Initialize Op Names(name)")
305 put(name, "87", "swap the contents of r32 and rm32");
306
307 :(scenario xchg_r32_with_r32)
308 % Reg[EBX].i = 0xaf;
309 % Reg[EAX].i = 0x2e;
310 == 0x1
311
312 87 d8
313
314 +run: exchange EBX with r/m32
315 +run: r/m32 is EAX
316 +run: storing 0x000000af in r/m32
317 +run: storing 0x0000002e in EBX
318
319 :(before "End Single-Byte Opcodes")
320 case 0x87: {
321 uint8_t modrm = next();
322 uint8_t reg2 = (modrm>>3)&0x7;
323 trace(90, "run") << "exchange " << rname(reg2) << " with r/m32" << end();
324 int32_t* arg1 = effective_address(modrm);
325 int32_t tmp = *arg1;
326 *arg1 = Reg[reg2].i;
327 Reg[reg2].i = tmp;
328 trace(90, "run") << "storing 0x" << HEXWORD << *arg1 << " in r/m32" << end();
329 trace(90, "run") << "storing 0x" << HEXWORD << Reg[reg2].i << " in " << rname(reg2) << end();
330 break;
331 }
332
333
334
335 :(before "End Initialize Op Names(name)")
336 put(name, "50", "push R0 (EAX) to stack");
337 put(name, "51", "push R1 (ECX) to stack");
338 put(name, "52", "push R2 (EDX) to stack");
339 put(name, "53", "push R3 (EBX) to stack");
340 put(name, "54", "push R4 (ESP) to stack");
341 put(name, "55", "push R5 (EBP) to stack");
342 put(name, "56", "push R6 (ESI) to stack");
343 put(name, "57", "push R7 (EDI) to stack");
344
345 :(scenario push_r32)
346 % Reg[ESP].u = 0x64;
347 % Reg[EBX].i = 0x0000000a;
348 == 0x1
349
350 53
351 +run: push EBX
352 +run: decrementing ESP to 0x00000060
353 +run: pushing value 0x0000000a
354
355 :(before "End Single-Byte Opcodes")
356 case 0x50:
357 case 0x51:
358 case 0x52:
359 case 0x53:
360 case 0x54:
361 case 0x55:
362 case 0x56:
363 case 0x57: {
364 uint8_t reg = op & 0x7;
365 trace(90, "run") << "push " << rname(reg) << end();
366
367 push(Reg[reg].u);
368 break;
369 }
370 :(code)
371 void push(uint32_t val) {
372 Reg[ESP].u -= 4;
373 trace(90, "run") << "decrementing ESP to 0x" << HEXWORD << Reg[ESP].u << end();
374 trace(90, "run") << "pushing value 0x" << HEXWORD << val << end();
375 write_mem_u32(Reg[ESP].u, val);
376 }
377
378
379
380 :(before "End Initialize Op Names(name)")
381 put(name, "58", "pop top of stack to R0 (EAX)");
382 put(name, "59", "pop top of stack to R1 (ECX)");
383 put(name, "5a", "pop top of stack to R2 (EDX)");
384 put(name, "5b", "pop top of stack to R3 (EBX)");
385 put(name, "5c", "pop top of stack to R4 (ESP)");
386 put(name, "5d", "pop top of stack to R5 (EBP)");
387 put(name, "5e", "pop top of stack to R6 (ESI)");
388 put(name, "5f", "pop top of stack to R7 (EDI)");
389
390 :(scenario pop_r32)
391 % Reg[ESP].u = 0x60;
392 % write_mem_i32(0x60, 0x0000000a);
393 == 0x1
394
395 5b
396 == 0x60
397 0a 00 00 00
398 +run: pop into EBX
399 +run: popping value 0x0000000a
400 +run: incrementing ESP to 0x00000064
401
402 :(before "End Single-Byte Opcodes")
403 case 0x58:
404 case 0x59:
405 case 0x5a:
406 case 0x5b:
407 case 0x5c:
408 case 0x5d:
409 case 0x5e:
410 case 0x5f: {
411 uint8_t reg = op & 0x7;
412 trace(90, "run") << "pop into " << rname(reg) << end();
413
414 Reg[reg].u = pop();
415
416 break;
417 }
418 :(code)
419 uint32_t pop() {
420 uint32_t result = read_mem_u32(Reg[ESP].u);
421 trace(90, "run") << "popping value 0x" << HEXWORD << result << end();
422 Reg[ESP].u += 4;
423 trace(90, "run") << "incrementing ESP to 0x" << HEXWORD << Reg[ESP].u << end();
424 return result;
425 }