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