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   if (mod == 3) {
 36     // mod 3 is just register direct addressing
 37     trace(90, "run") << "r/m32 is " << rname(rm) << end();
 38     return &Reg[rm].i;
 39   }
 40   return mem_addr_i32(effective_address_number(modrm));
 41 }
 42 
 43 uint32_t effective_address_number(uint8_t modrm) {
 44   uint8_t mod = (modrm>>6);
 45   // ignore middle 3 'reg opcode' bits
 46   uint8_t rm = modrm & 0x7;
 47   uint32_t addr = 0;
 48   switch (mod) {
 49   case 3:
 50     // mod 3 is just register direct addressing
 51     raise << "unexpected direct addressing mode\n" << end();
 52     return 0;
 53   // End Mod Special-cases(addr)
 54   default:
 55     cerr << "unrecognized mod bits: " << NUM(mod) << '\n';
 56     exit(1);
 57   }
 58   //: other mods are indirect, and they'll set addr appropriately
 59   return addr;
 60 }
 61 
 62 string rname(uint8_t r) {
 63   switch (r) {
 64   case 0: return "EAX";
 65   case 1: return "ECX";
 66   case 2: return "EDX";
 67   case 3: return "EBX";
 68   case 4: return "ESP";
 69   case 5: return "EBP";
 70   case 6: return "ESI";
 71   case 7: return "EDI";
 72   default: raise << "invalid register " << r << '\n' << end();  return "";
 73   }
 74 }
 75 
 76 //:: subtract
 77 
 78 :(before "End Initialize Op Names(name)")
 79 put(name, "29", "subtract r32 from rm32");
 80 
 81 :(scenario subtract_r32_from_r32)
 82 % Reg[EAX].i = 10;
 83 % Reg[EBX].i = 1;
 84 == 0x1
 85 # op  ModR/M  SIB   displacement  immediate
 86   29  d8                                      # subtract EBX from EAX
 87 # ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
 88 +run: subtract EBX from r/m32
 89 +run: r/m32 is EAX
 90 +run: storing 0x00000009
 91 
 92 :(before "End Single-Byte Opcodes")
 93 case 0x29: {  // subtract r32 from r/m32
 94   uint8_t modrm = next();
 95   uint8_t arg2 = (modrm>>3)&0x7;
 96   trace(90, "run") << "subtract " << rname(arg2) << " from r/m32" << end();
 97   int32_t* arg1 = effective_address(modrm);
 98   BINARY_ARITHMETIC_OP(-, *arg1, Reg[arg2].i);
 99   break;
100 }
101 
102 //:: multiply
103 
104 :(before "End Initialize Op Names(name)")
105 put(name, "f7", "test/negate/mul/div rm32 (with EAX if necessary) depending on subop");
106 
107 :(scenario multiply_eax_by_r32)
108 % Reg[EAX].i = 4;
109 % Reg[ECX].i = 3;
110 == 0x1
111 # op      ModR/M  SIB   displacement  immediate
112   f7      e1                                      # multiply EAX by ECX
113 # ModR/M in binary: 11 (direct mode) 100 (subop mul) 001 (src ECX)
114 +run: operate on r/m32
115 +run: r/m32 is ECX
116 +run: subop: multiply EAX by r/m32
117 +run: storing 0x0000000c
118 
119 :(before "End Single-Byte Opcodes")
120 case 0xf7: {  // xor r32 with r/m32
121   uint8_t modrm = next();
122   trace(90, "run") << "operate on r/m32" << end();
123   int32_t* arg1 = effective_address(modrm);
124   uint8_t subop = (modrm>>3)&0x7;  // middle 3 'reg opcode' bits
125   switch (subop) {
126   case 4: {  // mul unsigned EAX by r/m32
127     trace(90, "run") << "subop: multiply EAX by r/m32" << end();
128     uint64_t result = Reg[EAX].u * static_cast<uint32_t>(*arg1);
129     Reg[EAX].u = result & 0xffffffff;
130     Reg[EDX].u = result >> 32;
131     OF = (Reg[EDX].u != 0);
132     trace(90, "run") << "storing 0x" << HEXWORD << Reg[EAX].u << end();
133     break;
134   }
135   // End Op f7 Subops
136   default:
137     cerr << "unrecognized sub-opcode after f7: " << NUM(subop) << '\n';
138     exit(1);
139   }
140   break;
141 }
142 
143 //:
144 
145 :(before "End Initialize Op Names(name)")
146 put(name_0f, "af", "multiply rm32 into r32");
147 
148 :(scenario multiply_r32_into_r32)
149 % Reg[EAX].i = 4;
150 % Reg[EBX].i = 2;
151 == 0x1
152 # op      ModR/M  SIB   displacement  immediate
153   0f af   d8                                      # subtract EBX into EAX
154 # ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
155 +run: multiply r/m32 into EBX
156 +run: r/m32 is EAX
157 +run: storing 0x00000008
158 
159 :(before "End Two-Byte Opcodes Starting With 0f")
160 case 0xaf: {  // multiply r32 into r/m32
161   uint8_t modrm = next();
162   uint8_t arg2 = (modrm>>3)&0x7;
163   trace(90, "run") << "multiply r/m32 into " << rname(arg2) << end();
164   int32_t* arg1 = effective_address(modrm);
165   BINARY_ARITHMETIC_OP(*, Reg[arg2].i, *arg1);
166   break;
167 }
168 
169 //:: and
170 
171 :(before "End Initialize Op Names(name)")
172 put(name, "21", "rm32 = bitwise AND of r32 with rm32");
173 
174 :(scenario and_r32_with_r32)
175 % Reg[EAX].i = 0x0a0b0c0d;
176 % Reg[EBX].i = 0x000000ff;
177 == 0x1
178 # op  ModR/M  SIB   displacement  immediate
179   21  d8                                      # and EBX with destination EAX
180 # ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
181 +run: and EBX with r/m32
182 +run: r/m32 is EAX
183 +run: storing 0x0000000d
184 
185 :(before "End Single-Byte Opcodes")
186 case 0x21: {  // and r32 with r/m32
187   uint8_t modrm = next();
188   uint8_t arg2 = (modrm>>3)&0x7;
189   trace(90, "run") << "and " << rname(arg2) << " with r/m32" << end();
190   int32_t* arg1 = effective_address(modrm);
191   BINARY_BITWISE_OP(&, *arg1, Reg[arg2].u);
192   break;
193 }
194 
195 //:: or
196 
197 :(before "End Initialize Op Names(name)")
198 put(name, "09", "rm32 = bitwise OR of r32 with rm32");
199 
200 :(scenario or_r32_with_r32)
201 % Reg[EAX].i = 0x0a0b0c0d;
202 % Reg[EBX].i = 0xa0b0c0d0;
203 == 0x1
204 # op  ModR/M  SIB   displacement  immediate
205   09  d8                                      # or EBX with destination EAX
206 # ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
207 +run: or EBX with r/m32
208 +run: r/m32 is EAX
209 +run: storing 0xaabbccdd
210 
211 :(before "End Single-Byte Opcodes")
212 case 0x09: {  // or r32 with r/m32
213   uint8_t modrm = next();
214   uint8_t arg2 = (modrm>>3)&0x7;
215   trace(90, "run") << "or " << rname(arg2) << " with r/m32" << end();
216   int32_t* arg1 = effective_address(modrm);
217   BINARY_BITWISE_OP(|, *arg1, Reg[arg2].u);
218   break;
219 }
220 
221 //:: xor
222 
223 :(before "End Initialize Op Names(name)")
224 put(name, "31", "rm32 = bitwise XOR of r32 with rm32");
225 
226 :(scenario xor_r32_with_r32)
227 % Reg[EAX].i = 0x0a0b0c0d;
228 % Reg[EBX].i = 0xaabbc0d0;
229 == 0x1
230 # op  ModR/M  SIB   displacement  immediate
231   31  d8                                      # xor EBX with destination EAX
232 # ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
233 +run: xor EBX with r/m32
234 +run: r/m32 is EAX
235 +run: storing 0xa0b0ccdd
236 
237 :(before "End Single-Byte Opcodes")
238 case 0x31: {  // xor r32 with r/m32
239   uint8_t modrm = next();
240   uint8_t arg2 = (modrm>>3)&0x7;
241   trace(90, "run") << "xor " << rname(arg2) << " with r/m32" << end();
242   int32_t* arg1 = effective_address(modrm);
243   BINARY_BITWISE_OP(^, *arg1, Reg[arg2].u);
244   break;
245 }
246 
247 //:: not
248 
249 :(before "End Initialize Op Names(name)")
250 put(name, "f7", "bitwise complement of rm32");
251 
252 :(scenario not_r32)
253 % Reg[EBX].i = 0x0f0f00ff;
254 == 0x1
255 # op  ModR/M  SIB   displacement  immediate
256   f7  d3                                      # not EBX
257 # ModR/M in binary: 11 (direct mode) 010 (subop not) 011 (dest EBX)
258 +run: operate on r/m32
259 +run: r/m32 is EBX
260 +run: subop: not
261 +run: storing 0xf0f0ff00
262 
263 :(before "End Op f7 Subops")
264 case 2: {  // not r/m32
265   trace(90, "run") << "subop: not" << end();
266   *arg1 = ~(*arg1);
267   trace(90, "run") << "storing 0x" << HEXWORD << *arg1 << end();
268   SF = (*arg1 >> 31);
269   ZF = (*arg1 == 0);
270   OF = false;
271   break;
272 }
273 
274 //:: compare (cmp)
275 
276 :(before "End Initialize Op Names(name)")
277 put(name, "39", "compare: set SF if rm32 < r32");
278 
279 :(scenario compare_r32_with_r32_greater)
280 % Reg[EAX].i = 0x0a0b0c0d;
281 % Reg[EBX].i = 0x0a0b0c07;
282 == 0x1
283 # op  ModR/M  SIB   displacement  immediate
284   39  d8                                      # compare EBX with EAX
285 # ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
286 +run: compare EBX with r/m32
287 +run: r/m32 is EAX
288 +run: SF=0; ZF=0; OF=0
289 
290 :(before "End Single-Byte Opcodes")
291 case 0x39: {  // set SF if r/m32 < r32
292   uint8_t modrm = next();
293   uint8_t reg2 = (modrm>>3)&0x7;
294   trace(90, "run") << "compare " << rname(reg2) << " with r/m32" << end();
295   int32_t* arg1 = effective_address(modrm);
296   int32_t arg2 = Reg[reg2].i;
297   int32_t tmp1 = *arg1 - arg2;
298   SF = (tmp1 < 0);
299   ZF = (tmp1 == 0);
300   int64_t tmp2 = *arg1 - arg2;
301   OF = (tmp1 != tmp2);
302   trace(90, "run") << "SF=" << SF << "; ZF=" << ZF << "; OF=" << OF << end();
303   break;
304 }
305 
306 :(scenario compare_r32_with_r32_lesser)
307 % Reg[EAX].i = 0x0a0b0c07;
308 % Reg[EBX].i = 0x0a0b0c0d;
309 == 0x1
310 # op  ModR/M  SIB   displacement  immediate
311   39  d8                                      # compare EBX with EAX
312 # ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
313 +run: compare EBX with r/m32
314 +run: r/m32 is EAX
315 +run: SF=1; ZF=0; OF=0
316 
317 :(scenario compare_r32_with_r32_equal)
318 % Reg[EAX].i = 0x0a0b0c0d;
319 % Reg[EBX].i = 0x0a0b0c0d;
320 == 0x1
321 # op  ModR/M  SIB   displacement  immediate
322   39  d8                                      # compare EBX with EAX
323 # ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
324 +run: compare EBX with r/m32
325 +run: r/m32 is EAX
326 +run: SF=0; ZF=1; OF=0
327 
328 //:: copy (mov)
329 
330 :(before "End Initialize Op Names(name)")
331 put(name, <dl><dt><a name="Widget-contains_point"><strong>contains_point</strong></a>(self, y, x)</dt><dd><tt>Test&nbsp;whether&nbsp;the&nbsp;point&nbsp;(with&nbsp;absolute&nbsp;coordinates)&nbsp;lies<br>
within&nbsp;the&nbsp;boundaries&nbsp;of&nbsp;this&nbsp;object.</tt></dd></dl>

<dl><dt><a name="Widget-destroy"><strong>destroy</strong></a>(self)</dt><dd><tt>Called&nbsp;when&nbsp;the&nbsp;object&nbsp;is&nbsp;destroyed.<br>
Override&nbsp;this!</tt></dd></dl>

<dl><dt><a name="Widget-draw"><strong>draw</strong></a>(self)</dt><dd><tt>Draw&nbsp;the&nbsp;object.&nbsp;Called&nbsp;on&nbsp;every&nbsp;main&nbsp;iteration&nbsp;if&nbsp;visible.<br>
Containers&nbsp;should&nbsp;call&nbsp;<a href="#Widget-draw">draw</a>()&nbsp;on&nbsp;their&nbsp;contained&nbsp;objects&nbsp;here.<br>
Override&nbsp;this!</tt></dd></dl>

<dl><dt><a name="Widget-finalize"><strong>finalize</strong></a>(self)</dt><dd><tt>Called&nbsp;after&nbsp;every&nbsp;displayable&nbsp;is&nbsp;done&nbsp;drawing.<br>
Override&nbsp;this!</tt></dd></dl>

<dl><dt><a name="Widget-poke"><strong>poke</strong></a>(self)</dt><dd><tt>Called&nbsp;before&nbsp;drawing,&nbsp;even&nbsp;if&nbsp;invisible</tt></dd></dl>

<dl><dt><a name="Widget-press"><strong>press</strong></a>(self, key)</dt><dd><tt>Called&nbsp;when&nbsp;a&nbsp;key&nbsp;is&nbsp;pressed&nbsp;and&nbsp;self.<strong>focused</strong>&nbsp;is&nbsp;True.<br>
Override&nbsp;this!</tt></dd></dl>

<dl><dt><a name="Widget-resize"><strong>resize</strong></a>(self, y, x, hei<font color="#909090">=None</font>, wid<font color="#909090">=None</font>)</dt><dd><tt>Resize&nbsp;the&nbsp;widget</tt></dd></dl>

<hr>
Data and other attributes inherited from <a href="ranger.shared.html#EnvironmentAware">ranger.shared.EnvironmentAware</a>:<br>
<dl><dt><strong>env</strong> = None</dl>

<hr>
Data and other attributes inherited from <a href="ranger.shared.html#FileManagerAware">ranger.shared.FileManagerAware</a>:<br>
<dl><dt><strong>fm</strong> = None</dl>

<hr>
Data descriptors inherited from <a href="ranger.shared.html#Awareness">ranger.shared.Awareness</a>:<br>
<dl><dt><strong>__dict__</strong></dt>
<dd><tt>dictionary&nbsp;for&nbsp;instance&nbsp;variables&nbsp;(if&nbsp;defined)</tt></dd>
</dl>
<dl><dt><strong>__weakref__</strong></dt>
<dd><tt>list&nbsp;of&nbsp;weak&nbsp;references&nbsp;to&nbsp;the&nbsp;object&nbsp;(if&nbsp;defined)</tt></dd>
</dl>
<hr>
Methods inherited from <a href="ranger.gui.curses_shortcuts.html#CursesShortcuts">ranger.gui.curses_shortcuts.CursesShortcuts</a>:<br>
<dl><dt><a name="Widget-addnstr"><strong>addnstr</strong></a>(self, *args)</dt></dl>

<dl><dt><a name="Widget-addstr"><strong>addstr</strong></a>(self, *args)</dt></dl>

<dl><dt><a name="Widget-color"><strong>color</strong></a>(self, *keys)</dt><dd><tt>Change&nbsp;the&nbsp;colors&nbsp;from&nbsp;now&nbsp;on.</tt></dd></dl>

<dl><dt><a name="Widget-color_at"><strong>color_at</strong></a>(self, y, x, wid, *keys)</dt><dd><tt>Change&nbsp;the&nbsp;colors&nbsp;at&nbsp;the&nbsp;specified&nbsp;position</tt></dd></dl>

<dl><dt><a name="Widget-color_reset"><strong>color_reset</strong></a>(self)</dt><dd><tt>Change&nbsp;the&nbsp;colors&nbsp;to&nbsp;the&nbsp;default&nbsp;colors</tt></dd></dl>

<hr>
Data and other attributes inherited from <a href="ranger.shared.settings.html#SettingsAware">ranger.shared.settings.SettingsAware</a>:<br>
<dl><dt><strong>settings</strong> = {}</dl>

</td></tr></table></td></tr></table>
</body></html>
ss="LineNr">456 put(name, "4a", "decrement R2 (EDX)"); 457 put(name, "4b", "decrement R3 (EBX)"); 458 put(name, "4c", "decrement R4 (ESP)"); 459 put(name, "4d", "decrement R5 (EBP)"); 460 put(name, "4e", "decrement R6 (ESI)"); 461 put(name, "4f", "decrement R7 (EDI)"); 462 463 :(scenario decrement_r32) 464 % Reg[ECX].u = 0x1f; 465 == 0x1 # code segment 466 # op ModR/M SIB displacement immediate 467 49 # decrement ECX 468 +run: decrement ECX 469 +run: storing value 0x0000001e 470 471 :(before "End Single-Byte Opcodes") 472 case 0x48: 473 case 0x49: 474 case 0x4a: 475 case 0x4b: 476 case 0x4c: 477 case 0x4d: 478 case 0x4e: 479 case 0x4f: { // decrement r32 480 uint8_t reg = op & 0x7; 481 trace(90, "run") << "decrement " << rname(reg) << end(); 482 --Reg[reg].u; 483 trace(90, "run") << "storing value 0x" << HEXWORD << Reg[reg].u << end(); 484 break; 485 } 486 487 :(scenario decrement_rm32) 488 % Reg[EAX].u = 0x20; 489 == 0x1 # code segment 490 # op ModR/M SIB displacement immediate 491 ff c8 # decrement EAX 492 # ModR/M in binary: 11 (direct mode) 001 (subop inc) 000 (EAX) 493 +run: decrement r/m32 494 +run: r/m32 is EAX 495 +run: storing value 0x0000001f 496 497 :(before "End Op ff Subops") 498 case 1: { // decrement r/m32 499 trace(90, "run") << "decrement r/m32" << end(); 500 int32_t* arg = effective_address(modrm); 501 --*arg; 502 trace(90, "run") << "storing value 0x" << HEXWORD << *arg << end(); 503 break; 504 } 505 506 //:: push 507 508 :(before "End Initialize Op Names(name)") 509 put(name, "50", "push R0 (EAX) to stack"); 510 put(name, "51", "push R1 (ECX) to stack"); 511 put(name, "52", "push R2 (EDX) to stack"); 512 put(name, "53", "push R3 (EBX) to stack"); 513 put(name, "54", "push R4 (ESP) to stack"); 514 put(name, "55", "push R5 (EBP) to stack"); 515 put(name, "56", "push R6 (ESI) to stack"); 516 put(name, "57", "push R7 (EDI) to stack"); 517 518 :(scenario push_r32) 519 % Reg[ESP].u = 0x64; 520 % Reg[EBX].i = 0x0000000a; 521 == 0x1 522 # op ModR/M SIB displacement immediate 523 53 # push EBX to stack 524 +run: push EBX 525 +run: decrementing ESP to 0x00000060 526 +run: pushing value 0x0000000a 527 528 :(before "End Single-Byte Opcodes") 529 case 0x50: 530 case 0x51: 531 case 0x52: 532 case 0x53: 533 case 0x54: 534 case 0x55: 535 case 0x56: 536 case 0x57: { // push r32 to stack 537 uint8_t reg = op & 0x7; 538 trace(90, "run") << "push " << rname(reg) << end(); 539 //? cerr << "push: " << NUM(reg) << ": " << Reg[reg].u << " => " << Reg[ESP].u << '\n'; 540 push(Reg[reg].u); 541 break; 542 } 543 544 //:: pop 545 546 :(before "End Initialize Op Names(name)") 547 put(name, "58", "pop top of stack to R0 (EAX)"); 548 put(name, "59", "pop top of stack to R1 (ECX)"); 549 put(name, "5a", "pop top of stack to R2 (EDX)"); 550 put(name, "5b", "pop top of stack to R3 (EBX)"); 551 put(name, "5c", "pop top of stack to R4 (ESP)"); 552 put(name, "5d", "pop top of stack to R5 (EBP)"); 553 put(name, "5e", "pop top of stack to R6 (ESI)"); 554 put(name, "5f", "pop top of stack to R7 (EDI)"); 555 556 :(scenario pop_r32) 557 % Reg[ESP].u = 0x60; 558 % write_mem_i32(0x60, 0x0000000a); 559 == 0x1 # code segment 560 # op ModR/M SIB displacement immediate 561 5b # pop stack to EBX 562 == 0x60 # data segment 563 0a 00 00 00 # 0x0a 564 +run: pop into EBX 565 +run: popping value 0x0000000a 566 +run: incrementing ESP to 0x00000064 567 568 :(before "End Single-Byte Opcodes") 569 case 0x58: 570 case 0x59: 571 case 0x5a: 572 case 0x5b: 573 case 0x5c: 574 case 0x5d: 575 case 0x5e: 576 case 0x5f: { // pop stack into r32 577 uint8_t reg = op & 0x7; 578 trace(90, "run") << "pop into " << rname(reg) << end(); 579 //? cerr << "pop from " << Reg[ESP].u << '\n'; 580 Reg[reg].u = pop(); 581 //? cerr << "=> " << NUM(reg) << ": " << Reg[reg].u << '\n'; 582 break; 583 } 584 :(code) 585 uint32_t pop() { 586 uint32_t result = read_mem_u32(Reg[ESP].u); 587 trace(90, "run") << "popping value 0x" << HEXWORD << result << end(); 588 Reg[ESP].u += 4; 589 trace(90, "run") << "incrementing ESP to 0x" << HEXWORD << Reg[ESP].u << end(); 590 return result; 591 }