1 //: operating directly on a register
  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 # op  ModR/M  SIB   displacement  immediate
 11   01  d8                                      # add EBX to EAX
 12 # ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
 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: {  // add r32 to r/m32
 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 // Implement tables 2-2 and 2-3 in the Intel manual, Volume 2.
 29 // We return a pointer so that instructions can write to multiple bytes in
 30 // 'Mem' at once.
 31 int32_t* effective_address(uint8_t modrm) {
 32   uint8_t mod = (modrm>>6);
 33   // ignore middle 3 'reg opcode' bits
 34   uint8_t rm = modrm & 0x7;
 35   uint32_t addr = 0;
 36   switch (mod) {
 37   case 3:
 38     // mod 3 is just register direct addressing
 39     trace(90, "run") << "r/m32 is " << rname(rm) << end();
 40     return &Reg[rm].i;
 41   // End Mod Special-cases(addr)
 42   default:
 43     cerr << "unrecognized mod bits: " << NUM(mod) << '\n';
 44     exit(1);
 45   }
 46   //: other mods are indirect, and they'll set addr appropriately
 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 //:: subtract
 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 # op  ModR/M  SIB   displacement  immediate
 74   29  d8                                      # subtract EBX from EAX
 75 # ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
 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: {  // subtract r32 from r/m32
 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 //:: multiply
 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 # op      ModR/M  SIB   displacement  immediate
100   0f af   d8                                      # subtract EBX into EAX
101 # ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
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: {  // multiply r32 into r/m32
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 //:: and
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 # op  ModR/M  SIB   displacement  immediate
126   21  d8                                      # and EBX with destination EAX
127 # ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
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: {  // and r32 with r/m32
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 //:: or
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 # op  ModR/M  SIB   displacement  immediate
152   09  d8                                      # or EBX with destination EAX
153 # ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
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: {  // or r32 with r/m32
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 //:: xor
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 # op  ModR/M  SIB   displacement  immediate
178   31  d8                                      # xor EBX with destination EAX
179 # ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
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: {  // xor r32 with r/m32
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 //:: not
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 # op  ModR/M  SIB   displacement  immediate
203   f7  c3                                      # not EBX
204 # ModR/M in binary: 11 (direct mode) 000 (unused) 011 (dest EBX)
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: {  // xor r32 with r/m32
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 //:: compare (cmp)
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 # op  ModR/M  SIB   displacement  immediate
232   39  d8                                      # compare EBX with EAX
233 # ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
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: {  // set SF if r/m32 < r32
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 # op  ModR/M  SIB   displacement  immediate
259   39  d8                                      # compare EBX with EAX
260 # ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
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 # op  ModR/M  SIB   displacement  immediate
270   39  d8                                      # compare EBX with EAX
271 # ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
272 +run: compare EBX with r/m32
273 +run: r/m32 is EAX
274 +run: SF=0; ZF=1; OF=0
275 
276 //:: copy (mov)
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 # op  ModR/M  SIB   displacement  immediate
285   89  d8                                      # copy EBX to EAX
286 # ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
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: {  // copy r32 to r/m32
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 //:: xchg
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 # op  ModR/M  SIB   displacement  immediate
312   87  d8                                      # exchange EBX with EAX
313 # ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
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: {  // exchange r32 with r/m32
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 //:: push
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 # op  ModR/M  SIB   displacement  immediate
350   53                                          # push EBX to stack
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: {  // push r32 to stack
364   uint8_t reg = op & 0x7;
365   trace(90, "run") << "push " << rname(reg) << end();
366 //?   cerr << "push: " << NUM(reg) << ": " << Reg[reg].u << " => " << Reg[ESP].u << '\n';
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 //:: pop
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  # code segment
394 # op  ModR/M  SIB   displacement  immediate
395   5b                                          # pop stack to EBX
396 == 0x60  # data segment
397 0a 00 00 00  # 0x0a
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: {  // pop stack into r32
411   uint8_t reg = op & 0x7;
412   trace(90, "run") << "pop into " << rname(reg) << end();
413 //?   cerr << "pop from " << Reg[ESP].u << '\n';
414   Reg[reg].u = pop();
415 //?   cerr << "=> " << NUM(reg) << ": " << Reg[reg].u << '\n';
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 }