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, "21", "rm32 = bitwise AND of r32 with rm32");
94
95 :(scenario and_r32_with_r32)
96 % Reg[EAX].i = 0x0a0b0c0d;
97 % Reg[EBX].i = 0x000000ff;
98 == 0x1
99
100 21 d8
101
102 +run: and EBX with r/m32
103 +run: r/m32 is EAX
104 +run: storing 0x0000000d
105
106 :(before "End Single-Byte Opcodes")
107 case 0x21: {
108 uint8_t modrm = next();
109 uint8_t arg2 = (modrm>>3)&0x7;
110 trace(90, "run") << "and " << rname(arg2) << " with r/m32" << end();
111 int32_t* arg1 = effective_address(modrm);
112 BINARY_BITWISE_OP(&, *arg1, Reg[arg2].u);
113 break;
114 }
115
116
117
118 :(before "End Initialize Op Names(name)")
119 put(name, "09", "rm32 = bitwise OR of r32 with rm32");
120
121 :(scenario or_r32_with_r32)
122 % Reg[EAX].i = 0x0a0b0c0d;
123 % Reg[EBX].i = 0xa0b0c0d0;
124 == 0x1
125
126 09 d8
127
128 +run: or EBX with r/m32
129 +run: r/m32 is EAX
130 +run: storing 0xaabbccdd
131
132 :(before "End Single-Byte Opcodes")
133 case 0x09: {
134 uint8_t modrm = next();
135 uint8_t arg2 = (modrm>>3)&0x7;
136 trace(90, "run") << "or " << 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, "31", "rm32 = bitwise XOR of r32 with rm32");
146
147 :(scenario xor_r32_with_r32)
148 % Reg[EAX].i = 0x0a0b0c0d;
149 % Reg[EBX].i = 0xaabbc0d0;
150 == 0x1
151
152 31 d8
153
154 +run: xor EBX with r/m32
155 +run: r/m32 is EAX
156 +run: storing 0xa0b0ccdd
157
158 :(before "End Single-Byte Opcodes")
159 case 0x31: {
160 uint8_t modrm = next();
161 uint8_t arg2 = (modrm>>3)&0x7;
162 trace(90, "run") << "xor " << 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, "f7", "bitwise complement of rm32");
172
173 :(scenario not_r32)
174 % Reg[EBX].i = 0x0f0f00ff;
175 == 0x1
176
177 f7 c3
178
179 +run: 'not' of r/m32
180 +run: r/m32 is EBX
181 +run: storing 0xf0f0ff00
182
183 :(before "End Single-Byte Opcodes")
184 case 0xf7: {
185 uint8_t modrm = next();
186 trace(90, "run") << "'not' of r/m32" << end();
187 int32_t* arg1 = effective_address(modrm);
188 *arg1 = ~(*arg1);
189 trace(90, "run") << "storing 0x" << HEXWORD << *arg1 << end();
190 SF = (*arg1 >> 31);
191 ZF = (*arg1 == 0);
192 OF = false;
193 break;
194 }
195
196
197
198 :(before "End Initialize Op Names(name)")
199 put(name, "39", "set SF if rm32 < r32");
200
201 :(scenario compare_r32_with_r32_greater)
202 % Reg[EAX].i = 0x0a0b0c0d;
203 % Reg[EBX].i = 0x0a0b0c07;
204 == 0x1
205
206 39 d8
207
208 +run: compare EBX with r/m32
209 +run: r/m32 is EAX
210 +run: SF=0; ZF=0; OF=0
211
212 :(before "End Single-Byte Opcodes")
213 case 0x39: {
214 uint8_t modrm = next();
215 uint8_t reg2 = (modrm>>3)&0x7;
216 trace(90, "run") << "compare " << rname(reg2) << " with r/m32" << end();
217 int32_t* arg1 = effective_address(modrm);
218 int32_t arg2 = Reg[reg2].i;
219 int32_t tmp1 = *arg1 - arg2;
220 SF = (tmp1 < 0);
221 ZF = (tmp1 == 0);
222 int64_t tmp2 = *arg1 - arg2;
223 OF = (tmp1 != tmp2);
224 trace(90, "run") << "SF=" << SF << "; ZF=" << ZF << "; OF=" << OF << end();
225 break;
226 }
227
228 :(scenario compare_r32_with_r32_lesser)
229 % Reg[EAX].i = 0x0a0b0c07;
230 % Reg[EBX].i = 0x0a0b0c0d;
231 == 0x1
232
233 39 d8
234
235 +run: compare EBX with r/m32
236 +run: r/m32 is EAX
237 +run: SF=1; ZF=0; OF=0
238
239 :(scenario compare_r32_with_r32_equal)
240 % Reg[EAX].i = 0x0a0b0c0d;
241 % Reg[EBX].i = 0x0a0b0c0d;
242 == 0x1
243
244 39 d8
245
246 +run: compare EBX with r/m32
247 +run: r/m32 is EAX
248 +run: SF=0; ZF=1; OF=0
249
250
251
252 :(before "End Initialize Op Names(name)")
253 put(name, "89", "copy r32 to rm32");
254
255 :(scenario copy_r32_to_r32)
256 % Reg[EBX].i = 0xaf;
257 == 0x1
258
259 89 d8
260
261 +run: copy EBX to r/m32
262 +run: r/m32 is EAX
263 +run: storing 0x000000af
264
265 :(before "End Single-Byte Opcodes")
266 case 0x89: {
267 uint8_t modrm = next();
268 uint8_t reg2 = (modrm>>3)&0x7;
269 trace(90, "run") << "copy " << rname(reg2) << " to r/m32" << end();
270 int32_t* arg1 = effective_address(modrm);
271 *arg1 = Reg[reg2].i;
272 trace(90, "run") << "storing 0x" << HEXWORD << *arg1 << end();
273 break;
274 }
275
276
277
278 :(before "End Initialize Op Names(name)")
279 put(name, "87", "swap the contents of r32 and rm32");
280
281 :(scenario xchg_r32_with_r32)
282 % Reg[EBX].i = 0xaf;
283 % Reg[EAX].i = 0x2e;
284 == 0x1
285
286 87 d8
287
288 +run: exchange EBX with r/m32
289 +run: r/m32 is EAX
290 +run: storing 0x000000af in r/m32
291 +run: storing 0x0000002e in EBX
292
293 :(before "End Single-Byte Opcodes")
294 case 0x87: {
295 uint8_t modrm = next();
296 uint8_t reg2 = (modrm>>3)&0x7;
297 trace(90, "run") << "exchange " << rname(reg2) << " with r/m32" << end();
298 int32_t* arg1 = effective_address(modrm);
299 int32_t tmp = *arg1;
300 *arg1 = Reg[reg2].i;
301 Reg[reg2].i = tmp;
302 trace(90, "run") << "storing 0x" << HEXWORD << *arg1 << " in r/m32" << end();
303 trace(90, "run") << "storing 0x" << HEXWORD << Reg[reg2].i << " in " << rname(reg2) << end();
304 break;
305 }
306
307
308
309 :(before "End Initialize Op Names(name)")
310 put(name, "50", "push R0 (EAX) to stack");
311 put(name, "51", "push R1 (ECX) to stack");
312 put(name, "52", "push R2 (EDX) to stack");
313 put(name, "53", "push R3 (EBX) to stack");
314 put(name, "54", "push R4 (ESP) to stack");
315 put(name, "55", "push R5 (EBP) to stack");
316 put(name, "56", "push R6 (ESI) to stack");
317 put(name, "57", "push R7 (EDI) to stack");
318
319 :(scenario push_r32)
320 % Reg[ESP].u = 0x64;
321 % Reg[EBX].i = 0x0000000a;
322 == 0x1
323
324 53
325 +run: push EBX
326 +run: decrementing ESP to 0x00000060
327 +run: pushing value 0x0000000a
328
329 :(before "End Single-Byte Opcodes")
330 case 0x50:
331 case 0x51:
332 case 0x52:
333 case 0x53:
334 case 0x54:
335 case 0x55:
336 case 0x56:
337 case 0x57: {
338 uint8_t reg = op & 0x7;
339 trace(90, "run") << "push " << rname(reg) << end();
340 push(Reg[reg].u);
341 break;
342 }
343 :(code)
344 void push(uint32_t val) {
345 Reg[ESP].u -= 4;
346 trace(90, "run") << "decrementing ESP to 0x" << HEXWORD << Reg[ESP].u << end();
347 trace(90, "run") << "pushing value 0x" << HEXWORD << val << end();
348 write_mem_u32(Reg[ESP].u, val);
349 }
350
351
352
353 :(before "End Initialize Op Names(name)")
354 put(name, "58", "pop top of stack to R0 (EAX)");
355 put(name, "59", "pop top of stack to R1 (ECX)");
356 put(name, "5a", "pop top of stack to R2 (EDX)");
357 put(name, "5b", "pop top of stack to R3 (EBX)");
358 put(name, "5c", "pop top of stack to R4 (ESP)");
359 put(name, "5d", "pop top of stack to R5 (EBP)");
360 put(name, "5e", "pop top of stack to R6 (ESI)");
361 put(name, "5f", "pop top of stack to R7 (EDI)");
362
363 :(scenario pop_r32)
364 % Reg[ESP].u = 0x60;
365 % write_mem_i32(0x60, 0x0000000a);
366 == 0x1
367
368 5b
369 == 0x60
370 0a 00 00 00
371 +run: pop into EBX
372 +run: popping value 0x0000000a
373 +run: incrementing ESP to 0x00000064
374
375 :(before "End Single-Byte Opcodes")
376 case 0x58:
377 case 0x59:
378 case 0x5a:
379 case 0x5b:
380 case 0x5c:
381 case 0x5d:
382 case 0x5e:
383 case 0x5f: {
384 uint8_t reg = op & 0x7;
385 trace(90, "run") << "pop into " << rname(reg) << end();
386 Reg[reg].u = pop();
387 break;
388 }
389 :(code)
390 uint32_t pop() {
391 uint32_t result = read_mem_u32(Reg[ESP].u);
392 trace(90, "run") << "popping value 0x" << HEXWORD << result << end();
393 Reg[ESP].u += 4;
394 trace(90, "run") << "incrementing ESP to 0x" << HEXWORD << Reg[ESP].u << end();
395 return result;
396 }