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, "f7", "test/negate/mul/div rm32 (with EAX if necessary) depending on subop");
94
95 :(scenario multiply_eax_by_r32)
96 % Reg[EAX].i = 4;
97 % Reg[ECX].i = 3;
98 == 0x1
99
100 f7 e1
101
102 +run: operate on r/m32
103 +run: r/m32 is ECX
104 +run: subop: multiply EAX by r/m32
105 +run: storing 0x0000000c
106
107 :(before "End Single-Byte Opcodes")
108 case 0xf7: {
109 uint8_t modrm = next();
110 trace(90, "run") << "operate on r/m32" << end();
111 int32_t* arg1 = effective_address(modrm);
112 uint8_t subop = (modrm>>3)&0x7;
113 switch (subop) {
114 case 4: {
115 trace(90, "run") << "subop: multiply EAX by r/m32" << end();
116 uint64_t result = Reg[EAX].u * static_cast<uint32_t>(*arg1);
117 Reg[EAX].u = result & 0xffffffff;
118 Reg[EDX].u = result >> 32;
119 OF = (Reg[EDX].u != 0);
120 trace(90, "run") << "storing 0x" << HEXWORD << Reg[EAX].u << end();
121 break;
122 }
123
124 default:
125 cerr << "unrecognized sub-opcode after f7: " << NUM(subop) << '\n';
126 exit(1);
127 }
128 break;
129 }
130
131
132
133 :(before "End Initialize Op Names(name)")
134 put(name_0f, "af", "multiply rm32 into r32");
135
136 :(scenario multiply_r32_into_r32)
137 % Reg[EAX].i = 4;
138 % Reg[EBX].i = 2;
139 == 0x1
140
141 0f af d8
142
143 +run: multiply r/m32 into EBX
144 +run: r/m32 is EAX
145 +run: storing 0x00000008
146
147 :(before "End Two-Byte Opcodes Starting With 0f")
148 case 0xaf: {
149 uint8_t modrm = next();
150 uint8_t arg2 = (modrm>>3)&0x7;
151 trace(90, "run") << "multiply r/m32 into " << rname(arg2) << end();
152 int32_t* arg1 = effective_address(modrm);
153 BINARY_ARITHMETIC_OP(*, Reg[arg2].i, *arg1);
154 break;
155 }
156
157
158
159 :(before "End Initialize Op Names(name)")
160 put(name, "21", "rm32 = bitwise AND of r32 with rm32");
161
162 :(scenario and_r32_with_r32)
163 % Reg[EAX].i = 0x0a0b0c0d;
164 % Reg[EBX].i = 0x000000ff;
165 == 0x1
166
167 21 d8
168
169 +run: and EBX with r/m32
170 +run: r/m32 is EAX
171 +run: storing 0x0000000d
172
173 :(before "End Single-Byte Opcodes")
174 case 0x21: {
175 uint8_t modrm = next();
176 uint8_t arg2 = (modrm>>3)&0x7;
177 trace(90, "run") << "and " << rname(arg2) << " with r/m32" << end();
178 int32_t* arg1 = effective_address(modrm);
179 BINARY_BITWISE_OP(&, *arg1, Reg[arg2].u);
180 break;
181 }
182
183
184
185 :(before "End Initialize Op Names(name)")
186 put(name, "09", "rm32 = bitwise OR of r32 with rm32");
187
188 :(scenario or_r32_with_r32)
189 % Reg[EAX].i = 0x0a0b0c0d;
190 % Reg[EBX].i = 0xa0b0c0d0;
191 == 0x1
192
193 09 d8
194
195 +run: or EBX with r/m32
196 +run: r/m32 is EAX
197 +run: storing 0xaabbccdd
198
199 :(before "End Single-Byte Opcodes")
200 case 0x09: {
201 uint8_t modrm = next();
202 uint8_t arg2 = (modrm>>3)&0x7;
203 trace(90, "run") << "or " << rname(arg2) << " with r/m32" << end();
204 int32_t* arg1 = effective_address(modrm);
205 BINARY_BITWISE_OP(|, *arg1, Reg[arg2].u);
206 break;
207 }
208
209
210
211 :(before "End Initialize Op Names(name)")
212 put(name, "31", "rm32 = bitwise XOR of r32 with rm32");
213
214 :(scenario xor_r32_with_r32)
215 % Reg[EAX].i = 0x0a0b0c0d;
216 % Reg[EBX].i = 0xaabbc0d0;
217 == 0x1
218
219 31 d8
220
221 +run: xor EBX with r/m32
222 +run: r/m32 is EAX
223 +run: storing 0xa0b0ccdd
224
225 :(before "End Single-Byte Opcodes")
226 case 0x31: {
227 uint8_t modrm = next();
228 uint8_t arg2 = (modrm>>3)&0x7;
229 trace(90, "run") << "xor " << rname(arg2) << " with r/m32" << end();
230 int32_t* arg1 = effective_address(modrm);
231 BINARY_BITWISE_OP(^, *arg1, Reg[arg2].u);
232 break;
233 }
234
235
236
237 :(before "End Initialize Op Names(name)")
238 put(name, "f7", "bitwise complement of rm32");
239
240 :(scenario not_r32)
241 % Reg[EBX].i = 0x0f0f00ff;
242 == 0x1
243
244 f7 d3
245
246 +run: operate on r/m32
247 +run: r/m32 is EBX
248 +run: subop: not
249 +run: storing 0xf0f0ff00
250
251 :(before "End Op f7 Subops")
252 case 2: {
253 trace(90, "run") << "subop: not" << end();
254 *arg1 = ~(*arg1);
255 trace(90, "run") << "storing 0x" << HEXWORD << *arg1 << end();
256 SF = (*arg1 >> 31);
257 ZF = (*arg1 == 0);
258 OF = false;
259 break;
260 }
261
262
263
264 :(before "End Initialize Op Names(name)")
265 put(name, "39", "set SF if rm32 < r32");
266
267 :(scenario compare_r32_with_r32_greater)
268 % Reg[EAX].i = 0x0a0b0c0d;
269 % Reg[EBX].i = 0x0a0b0c07;
270 == 0x1
271
272 39 d8
273
274 +run: compare EBX with r/m32
275 +run: r/m32 is EAX
276 +run: SF=0; ZF=0; OF=0
277
278 :(before "End Single-Byte Opcodes")
279 case 0x39: {
280 uint8_t modrm = next();
281 uint8_t reg2 = (modrm>>3)&0x7;
282 trace(90, "run") << "compare " << rname(reg2) << " with r/m32" << end();
283 int32_t* arg1 = effective_address(modrm);
284 int32_t arg2 = Reg[reg2].i;
285 int32_t tmp1 = *arg1 - arg2;
286 SF = (tmp1 < 0);
287 ZF = (tmp1 == 0);
288 int64_t tmp2 = *arg1 - arg2;
289 OF = (tmp1 != tmp2);
290 trace(90, "run") << "SF=" << SF << "; ZF=" << ZF << "; OF=" << OF << end();
291 break;
292 }
293
294 :(scenario compare_r32_with_r32_lesser)
295 % Reg[EAX].i = 0x0a0b0c07;
296 % Reg[EBX].i = 0x0a0b0c0d;
297 == 0x1
298
299 39 d8
300
301 +run: compare EBX with r/m32
302 +run: r/m32 is EAX
303 +run: SF=1; ZF=0; OF=0
304
305 :(scenario compare_r32_with_r32_equal)
306 % Reg[EAX].i = 0x0a0b0c0d;
307 % Reg[EBX].i = 0x0a0b0c0d;
308 == 0x1
309
310 39 d8
311
312 +run: compare EBX with r/m32
313 +run: r/m32 is EAX
314 +run: SF=0; ZF=1; OF=0
315
316
317
318 :(before "End Initialize Op Names(name)")
319 put(name, "89", "copy r32 to rm32");
320
321 :(scenario copy_r32_to_r32)
322 % Reg[EBX].i = 0xaf;
323 == 0x1
324
325 89 d8
326
327 +run: copy EBX to r/m32
328 +run: r/m32 is EAX
329 +run: storing 0x000000af
330
331 :(before "End Single-Byte Opcodes")
332 case 0x89: {
333 uint8_t modrm = next();
334 uint8_t reg2 = (modrm>>3)&0x7;
335 trace(90, "run") << "copy " << rname(reg2) << " to r/m32" << end();
336 int32_t* arg1 = effective_address(modrm);
337 *arg1 = Reg[reg2].i;
338 trace(90, "run") << "storing 0x" << HEXWORD << *arg1 << end();
339 break;
340 }
341
342
343
344 :(before "End Initialize Op Names(name)")
345 put(name, "87", "swap the contents of r32 and rm32");
346
347 :(scenario xchg_r32_with_r32)
348 % Reg[EBX].i = 0xaf;
349 % Reg[EAX].i = 0x2e;
350 == 0x1
351
352 87 d8
353
354 +run: exchange EBX with r/m32
355 +run: r/m32 is EAX
356 +run: storing 0x000000af in r/m32
357 +run: storing 0x0000002e in EBX
358
359 :(before "End Single-Byte Opcodes")
360 case 0x87: {
361 uint8_t modrm = next();
362 uint8_t reg2 = (modrm>>3)&0x7;
363 trace(90, "run") << "exchange " << rname(reg2) << " with r/m32" << end();
364 int32_t* arg1 = effective_address(modrm);
365 int32_t tmp = *arg1;
366 *arg1 = Reg[reg2].i;
367 Reg[reg2].i = tmp;
368 trace(90, "run") << "storing 0x" << HEXWORD << *arg1 << " in r/m32" << end();
369 trace(90, "run") << "storing 0x" << HEXWORD << Reg[reg2].i << " in " << rname(reg2) << end();
370 break;
371 }
372
373
374
375 :(before "End Initialize Op Names(name)")
376 put(name, "50", "push R0 (EAX) to stack");
377 put(name, "51", "push R1 (ECX) to stack");
378 put(name, "52", "push R2 (EDX) to stack");
379 put(name, "53", "push R3 (EBX) to stack");
380 put(name, "54", "push R4 (ESP) to stack");
381 put(name, "55", "push R5 (EBP) to stack");
382 put(name, "56", "push R6 (ESI) to stack");
383 put(name, "57", "push R7 (EDI) to stack");
384
385 :(scenario push_r32)
386 % Reg[ESP].u = 0x64;
387 % Reg[EBX].i = 0x0000000a;
388 == 0x1
389
390 53
391 +run: push EBX
392 +run: decrementing ESP to 0x00000060
393 +run: pushing value 0x0000000a
394
395 :(before "End Single-Byte Opcodes")
396 case 0x50:
397 case 0x51:
398 case 0x52:
399 case 0x53:
400 case 0x54:
401 case 0x55:
402 case 0x56:
403 case 0x57: {
404 uint8_t reg = op & 0x7;
405 trace(90, "run") << "push " << rname(reg) << end();
406
407 push(Reg[reg].u);
408 break;
409 }
410
411
412
413 :(before "End Initialize Op Names(name)")
414 put(name, "58", "pop top of stack to R0 (EAX)");
415 put(name, "59", "pop top of stack to R1 (ECX)");
416 put(name, "5a", "pop top of stack to R2 (EDX)");
417 put(name, "5b", "pop top of stack to R3 (EBX)");
418 put(name, "5c", "pop top of stack to R4 (ESP)");
419 put(name, "5d", "pop top of stack to R5 (EBP)");
420 put(name, "5e", "pop top of stack to R6 (ESI)");
421 put(name, "5f", "pop top of stack to R7 (EDI)");
422
423 :(scenario pop_r32)
424 % Reg[ESP].u = 0x60;
425 % write_mem_i32(0x60, 0x0000000a);
426 == 0x1
427
428 5b
429 == 0x60
430 0a 00 00 00
431 +run: pop into EBX
432 +run: popping value 0x0000000a
433 +run: incrementing ESP to 0x00000064
434
435 :(before "End Single-Byte Opcodes")
436 case 0x58:
437 case 0x59:
438 case 0x5a:
439 case 0x5b:
440 case 0x5c:
441 case 0x5d:
442 case 0x5e:
443 case 0x5f: {
444 uint8_t reg = op & 0x7;
445 trace(90, "run") << "pop into " << rname(reg) << end();
446
447 Reg[reg].u = pop();
448
449 break;
450 }
451 :(code)
452 uint32_t pop() {
453 uint32_t result = read_mem_u32(Reg[ESP].u);
454 trace(90, "run") << "popping value 0x" << HEXWORD << result << end();
455 Reg[ESP].u += 4;
456 trace(90, "run") << "incrementing ESP to 0x" << HEXWORD << Reg[ESP].u << end();
457 return result;
458 }