From c762564bd754884e847922c99172076fde4d646e Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Fri, 7 Sep 2018 22:42:23 -0700 Subject: 4539 --- html/subx/014indirect_addressing.cc.html | 827 ++++++++++++++++--------------- 1 file changed, 414 insertions(+), 413 deletions(-) (limited to 'html/subx/014indirect_addressing.cc.html') diff --git a/html/subx/014indirect_addressing.cc.html b/html/subx/014indirect_addressing.cc.html index 79362ee9..3f08e713 100644 --- a/html/subx/014indirect_addressing.cc.html +++ b/html/subx/014indirect_addressing.cc.html @@ -291,425 +291,426 @@ if ('onhashchange' in window) { 227 228 //:: not 229 -230 :(scenario not_r32_with_mem_at_r32) +230 :(scenario not_of_mem_at_r32) 231 % Reg[EBX].i = 0x60; 232 == 0x1 # code segment 233 # op ModR/M SIB displacement immediate -234 f7 03 # negate *EBX -235 # ModR/M in binary: 00 (indirect mode) 000 (unused) 011 (dest EBX) +234 f7 13 # negate *EBX +235 # ModR/M in binary: 00 (indirect mode) 010 (subop not) 011 (dest EBX) 236 == 0x60 # data segment 237 ff 00 0f 0f # 0x0f0f00ff -238 +run: 'not' of r/m32 +238 +run: operate on r/m32 239 +run: effective address is 0x60 (EBX) -240 +run: storing 0xf0f0ff00 -241 -242 //:: compare (cmp) -243 -244 :(scenario compare_mem_at_r32_with_r32_greater) -245 % Reg[EAX].i = 0x60; -246 % Reg[EBX].i = 0x0a0b0c07; -247 == 0x1 # code segment -248 # op ModR/M SIB displacement immediate -249 39 18 # compare EBX with *EAX -250 # ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) -251 == 0x60 # data segment -252 0d 0c 0b 0a # 0x0a0b0c0d -253 +run: compare EBX with r/m32 -254 +run: effective address is 0x60 (EAX) -255 +run: SF=0; ZF=0; OF=0 -256 -257 :(scenario compare_mem_at_r32_with_r32_lesser) -258 % Reg[EAX].i = 0x60; -259 % Reg[EBX].i = 0x0a0b0c0d; -260 == 0x1 # code segment -261 # op ModR/M SIB displacement immediate -262 39 18 # compare EBX with *EAX -263 # ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) -264 == 0x60 # data segment -265 07 0c 0b 0a # 0x0a0b0c0d -266 +run: compare EBX with r/m32 -267 +run: effective address is 0x60 (EAX) -268 +run: SF=1; ZF=0; OF=0 -269 -270 :(scenario compare_mem_at_r32_with_r32_equal) -271 % Reg[EAX].i = 0x60; -272 % Reg[EBX].i = 0x0a0b0c0d; -273 == 0x1 # code segment -274 # op ModR/M SIB displacement immediate -275 39 18 # compare EBX with *EAX -276 # ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) -277 == 0x60 # data segment -278 0d 0c 0b 0a # 0x0a0b0c0d -279 +run: compare EBX with r/m32 -280 +run: effective address is 0x60 (EAX) -281 +run: SF=0; ZF=1; OF=0 -282 -283 //: -284 -285 :(before "End Initialize Op Names(name)") -286 put(name, "3b", "set SF if rm32 > r32"); -287 -288 :(scenario compare_r32_with_mem_at_r32_greater) -289 % Reg[EAX].i = 0x60; -290 % Reg[EBX].i = 0x0a0b0c0d; -291 == 0x1 # code segment -292 # op ModR/M SIB displacement immediate -293 3b 18 # compare *EAX with EBX -294 # ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) -295 == 0x60 # data segment -296 07 0c 0b 0a # 0x0a0b0c0d -297 +run: compare r/m32 with EBX -298 +run: effective address is 0x60 (EAX) -299 +run: SF=0; ZF=0; OF=0 -300 -301 :(before "End Single-Byte Opcodes") -302 case 0x3b: { // set SF if r32 < r/m32 -303 uint8_t modrm = next(); -304 uint8_t reg1 = (modrm>>3)&0x7; -305 trace(90, "run") << "compare r/m32 with " << rname(reg1) << end(); -306 int32_t arg1 = Reg[reg1].i; -307 int32_t* arg2 = effective_address(modrm); -308 int32_t tmp1 = arg1 - *arg2; -309 SF = (tmp1 < 0); -310 ZF = (tmp1 == 0); -311 int64_t tmp2 = arg1 - *arg2; -312 OF = (tmp1 != tmp2); -313 trace(90, "run") << "SF=" << SF << "; ZF=" << ZF << "; OF=" << OF << end(); -314 break; -315 } -316 -317 :(scenario compare_r32_with_mem_at_r32_lesser) -318 % Reg[EAX].i = 0x60; -319 % Reg[EBX].i = 0x0a0b0c07; -320 == 0x1 # code segment -321 # op ModR/M SIB displacement immediate -322 3b 18 # compare *EAX with EBX -323 # ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) -324 == 0x60 # data segment -325 0d 0c 0b 0a # 0x0a0b0c0d -326 +run: compare r/m32 with EBX -327 +run: effective address is 0x60 (EAX) -328 +run: SF=1; ZF=0; OF=0 -329 -330 :(scenario compare_r32_with_mem_at_r32_equal) -331 % Reg[EAX].i = 0x60; -332 % Reg[EBX].i = 0x0a0b0c0d; -333 == 0x1 # code segment -334 # op ModR/M SIB displacement immediate -335 3b 18 # compare *EAX with EBX -336 # ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) -337 == 0x60 # data segment -338 0d 0c 0b 0a # 0x0a0b0c0d -339 +run: compare r/m32 with EBX -340 +run: effective address is 0x60 (EAX) -341 +run: SF=0; ZF=1; OF=0 -342 -343 //:: copy (mov) -344 -345 :(scenario copy_r32_to_mem_at_r32) -346 % Reg[EBX].i = 0xaf; -347 % Reg[EAX].i = 0x60; -348 == 0x1 -349 # op ModR/M SIB displacement immediate -350 89 18 # copy EBX to *EAX -351 # ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) -352 +run: copy EBX to r/m32 -353 +run: effective address is 0x60 (EAX) -354 +run: storing 0x000000af -355 -356 //: -357 -358 :(before "End Initialize Op Names(name)") -359 put(name, "8b", "copy rm32 to r32"); -360 -361 :(scenario copy_mem_at_r32_to_r32) -362 % Reg[EAX].i = 0x60; -363 == 0x1 # code segment -364 # op ModR/M SIB displacement immediate -365 8b 18 # copy *EAX to EBX -366 # ModR/M in binary: 00 (indirect mode) 011 (src EBX) 000 (dest EAX) -367 == 0x60 # data segment -368 af 00 00 00 # 0xaf -369 +run: copy r/m32 to EBX -370 +run: effective address is 0x60 (EAX) -371 +run: storing 0x000000af -372 -373 :(before "End Single-Byte Opcodes") -374 case 0x8b: { // copy r32 to r/m32 -375 uint8_t modrm = next(); -376 uint8_t reg1 = (modrm>>3)&0x7; -377 trace(90, "run") << "copy r/m32 to " << rname(reg1) << end(); -378 int32_t* arg2 = effective_address(modrm); -379 Reg[reg1].i = *arg2; -380 trace(90, "run") << "storing 0x" << HEXWORD << *arg2 << end(); -381 break; -382 } -383 -384 //: -385 -386 :(before "End Initialize Op Names(name)") -387 put(name, "88", "copy r8 (lowermost byte of r32) to r8/m8-at-r32"); -388 -389 :(scenario copy_r8_to_mem_at_r32) -390 % Reg[EBX].i = 0xafafafaf; -391 % Reg[EAX].i = 0x60; -392 == 0x1 -393 # op ModR/M SIB displacement immediate -394 88 18 # copy just the lowermost byte of EBX to the byte at *EAX -395 # ModR/M in binary: 00 (indirect mode) 011 (src EBX) 000 (dest EAX) -396 +run: copy lowermost byte of EBX to r8/m8-at-r32 -397 +run: effective address is 0x60 (EAX) -398 +run: storing 0xaf -399 % CHECK_EQ(0x000000af, read_mem_u32(0x60)); -400 -401 :(before "End Single-Byte Opcodes") -402 case 0x88: { // copy r/m8 to r8 -403 uint8_t modrm = next(); -404 uint8_t reg2 = (modrm>>3)&0x7; -405 trace(90, "run") << "copy lowermost byte of " << rname(reg2) << " to r8/m8-at-r32" << end(); -406 // use unsigned to zero-extend 8-bit value to 32 bits -407 uint8_t* arg1 = reinterpret_cast<uint8_t*>(effective_address(modrm)); -408 *arg1 = Reg[reg2].u; -409 trace(90, "run") << "storing 0x" << HEXBYTE << NUM(*arg1) << end(); -410 break; -411 } -412 -413 //: -414 -415 :(before "End Initialize Op Names(name)") -416 put(name, "8a", "copy r8/m8-at-r32 to r8 (lowermost byte of r32)"); -417 -418 :(scenario copy_mem_at_r32_to_r8) -419 % Reg[EBX].i = 0xaf; -420 % Reg[EAX].i = 0x60; -421 == 0x1 -422 # op ModR/M SIB displacement immediate -423 8a 18 # copy just the byte at *EAX to lowermost byte of EBX (clearing remaining bytes) -424 # ModR/M in binary: 00 (indirect mode) 011 (dest EBX) 000 (src EAX) -425 == 0x60 # data segment -426 af ff ff ff # 0xaf with more data in following bytes -427 +run: copy r8/m8-at-r32 to lowermost byte of EBX -428 +run: effective address is 0x60 (EAX) -429 +run: storing 0xaf -430 -431 :(before "End Single-Byte Opcodes") -432 case 0x8a: { // copy r/m8 to r8 -433 uint8_t modrm = next(); -434 uint8_t reg1 = (modrm>>3)&0x7; -435 trace(90, "run") << "copy r8/m8-at-r32 to lowermost byte of " << rname(reg1) << end(); -436 // use unsigned to zero-extend 8-bit value to 32 bits -437 uint8_t* arg2 = reinterpret_cast<uint8_t*>(effective_address(modrm)); -438 Reg[reg1].u = static_cast<uint32_t>(*arg2); -439 trace(90, "run") << "storing 0x" << HEXBYTE << NUM(*arg2) << end(); -440 break; -441 } -442 -443 //:: jump -444 -445 :(before "End Initialize Op Names(name)") -446 put(name, "ff", "jump/push/call rm32 based on subop"); -447 -448 :(scenario jump_mem_at_r32) -449 % Reg[EAX].i = 0x60; -450 == 0x1 # code segment -451 # op ModR/M SIB displacement immediate -452 ff 20 # jump to *EAX -453 # ModR/M in binary: 00 (indirect mode) 100 (jump to r/m32) 000 (src EAX) -454 05 00 00 00 01 -455 05 00 00 00 02 -456 == 0x60 # data segment -457 08 00 00 00 # 8 -458 +run: inst: 0x00000001 -459 +run: jump to r/m32 -460 +run: effective address is 0x60 (EAX) -461 +run: jumping to 0x00000008 -462 +run: inst: 0x00000008 -463 -run: inst: 0x00000003 -464 -465 :(before "End Single-Byte Opcodes") -466 case 0xff: { -467 uint8_t modrm = next(); -468 uint8_t subop = (modrm>>3)&0x7; // middle 3 'reg opcode' bits -469 switch (subop) { -470 case 4: { // jump to r/m32 -471 trace(90, "run") << "jump to r/m32" << end(); -472 int32_t* arg2 = effective_address(modrm); -473 EIP = *arg2; -474 trace(90, "run") << "jumping to 0x" << HEXWORD << EIP << end(); -475 break; -476 } -477 // End Op ff Subops -478 } -479 break; -480 } -481 -482 //:: push -483 -484 :(scenario push_mem_at_r32) -485 % Reg[EAX].i = 0x60; -486 % Reg[ESP].u = 0x14; -487 == 0x1 # code segment -488 # op ModR/M SIB displacement immediate -489 ff 30 # push *EAX to stack -490 # ModR/M in binary: 00 (indirect mode) 110 (push r/m32) 000 (src EAX) -491 == 0x60 # data segment -492 af 00 00 00 # 0xaf -493 +run: push r/m32 -494 +run: effective address is 0x60 (EAX) -495 +run: decrementing ESP to 0x00000010 -496 +run: pushing value 0x000000af -497 -498 :(before "End Op ff Subops") -499 case 6: { // push r/m32 to stack -500 trace(90, "run") << "push r/m32" << end(); -501 const int32_t* val = effective_address(modrm); -502 push(*val); -503 break; -504 } -505 -506 //:: pop -507 -508 :(before "End Initialize Op Names(name)") -509 put(name, "8f", "pop top of stack to rm32"); -510 -511 :(scenario pop_mem_at_r32) -512 % Reg[EAX].i = 0x60; -513 % Reg[ESP].u = 0x10; -514 == 0x1 # code segment -515 # op ModR/M SIB displacement immediate -516 8f 00 # pop stack into *EAX -517 # ModR/M in binary: 00 (indirect mode) 000 (pop r/m32) 000 (dest EAX) -518 == 0x10 # data segment -519 30 00 00 00 # 0x30 -520 +run: pop into r/m32 -521 +run: effective address is 0x60 (EAX) -522 +run: popping value 0x00000030 -523 +run: incrementing ESP to 0x00000014 -524 -525 :(before "End Single-Byte Opcodes") -526 case 0x8f: { // pop stack into r/m32 -527 uint8_t modrm = next(); -528 uint8_t subop = (modrm>>3)&0x7; -529 switch (subop) { -530 case 0: { -531 trace(90, "run") << "pop into r/m32" << end(); -532 int32_t* dest = effective_address(modrm); -533 *dest = pop(); -534 break; -535 } -536 } -537 break; -538 } -539 -540 //:: special-case for loading address from disp32 rather than register -541 -542 :(scenario add_r32_to_mem_at_displacement) -543 % Reg[EBX].i = 0x10; // source -544 == 0x1 # code segment -545 # op ModR/M SIB displacement immediate -546 01 1d 60 00 00 00 # add EBX to *0x60 -547 # ModR/M in binary: 00 (indirect mode) 011 (src EBX) 101 (dest in disp32) -548 == 0x60 # data segment -549 01 00 00 00 # 1 -550 +run: add EBX to r/m32 -551 +run: effective address is 0x60 (disp32) -552 +run: storing 0x00000011 -553 -554 :(before "End Mod 0 Special-cases(addr)") -555 case 5: // exception: mod 0b00 rm 0b101 => incoming disp32 -556 addr = imm32(); -557 trace(90, "run") << "effective address is 0x" << std::hex << addr << " (disp32)" << end(); -558 break; -559 -560 //: -561 -562 :(scenario add_r32_to_mem_at_r32_plus_disp8) -563 % Reg[EBX].i = 0x10; // source -564 % Reg[EAX].i = 0x5e; // dest -565 == 0x1 # code segment -566 # op ModR/M SIB displacement immediate -567 01 58 02 # add EBX to *(EAX+2) -568 # ModR/M in binary: 01 (indirect+disp8 mode) 011 (src EBX) 000 (dest EAX) -569 == 0x60 # data segment -570 01 00 00 00 # 1 -571 +run: add EBX to r/m32 -572 +run: effective address is initially 0x5e (EAX) -573 +run: effective address is 0x60 (after adding disp8) -574 +run: storing 0x00000011 -575 -576 :(before "End Mod Special-cases(addr)") -577 case 1: // indirect + disp8 addressing -578 switch (rm) { -579 default: -580 addr = Reg[rm].u; -581 trace(90, "run") << "effective address is initially 0x" << std::hex << addr << " (" << rname(rm) << ")" << end(); -582 break; -583 // End Mod 1 Special-cases(addr) -584 } -585 if (addr > 0) { -586 addr += static_cast<int8_t>(next()); -587 trace(90, "run") << "effective address is 0x" << std::hex << addr << " (after adding disp8)" << end(); -588 } -589 break; -590 -591 :(scenario add_r32_to_mem_at_r32_plus_negative_disp8) -592 % Reg[EBX].i = 0x10; // source -593 % Reg[EAX].i = 0x61; // dest -594 == 0x1 # code segment -595 # op ModR/M SIB displacement immediate -596 01 58 ff # add EBX to *(EAX-1) -597 # ModR/M in binary: 01 (indirect+disp8 mode) 011 (src EBX) 000 (dest EAX) -598 == 0x60 # data segment -599 01 00 00 00 # 1 -600 +run: add EBX to r/m32 -601 +run: effective address is initially 0x61 (EAX) -602 +run: effective address is 0x60 (after adding disp8) -603 +run: storing 0x00000011 -604 -605 //: -606 -607 :(scenario add_r32_to_mem_at_r32_plus_disp32) -608 % Reg[EBX].i = 0x10; // source -609 % Reg[EAX].i = 0x5e; // dest -610 == 0x1 # code segment -611 # op ModR/M SIB displacement immediate -612 01 98 02 00 00 00 # add EBX to *(EAX+2) -613 # ModR/M in binary: 10 (indirect+disp32 mode) 011 (src EBX) 000 (dest EAX) -614 == 0x60 # data segment -615 01 00 00 00 # 1 -616 +run: add EBX to r/m32 -617 +run: effective address is initially 0x5e (EAX) -618 +run: effective address is 0x60 (after adding disp32) -619 +run: storing 0x00000011 -620 -621 :(before "End Mod Special-cases(addr)") -622 case 2: // indirect + disp32 addressing -623 switch (rm) { -624 default: -625 addr = Reg[rm].u; -626 trace(90, "run") << "effective address is initially 0x" << std::hex << addr << " (" << rname(rm) << ")" << end(); -627 break; -628 // End Mod 2 Special-cases(addr) -629 } -630 if (addr > 0) { -631 addr += imm32(); -632 trace(90, "run") << "effective address is 0x" << std::hex << addr << " (after adding disp32)" << end(); -633 } -634 break; -635 -636 :(scenario add_r32_to_mem_at_r32_plus_negative_disp32) -637 % Reg[EBX].i = 0x10; // source -638 % Reg[EAX].i = 0x61; // dest -639 == 0x1 # code segment -640 # op ModR/M SIB displacement immediate -641 01 98 ff ff ff ff # add EBX to *(EAX-1) -642 # ModR/M in binary: 10 (indirect+disp32 mode) 011 (src EBX) 000 (dest EAX) -643 == 0x60 # data segment -644 01 00 00 00 # 1 -645 +run: add EBX to r/m32 -646 +run: effective address is initially 0x61 (EAX) -647 +run: effective address is 0x60 (after adding disp32) -648 +run: storing 0x00000011 +240 +run: subop: not +241 +run: storing 0xf0f0ff00 +242 +243 //:: compare (cmp) +244 +245 :(scenario compare_mem_at_r32_with_r32_greater) +246 % Reg[EAX].i = 0x60; +247 % Reg[EBX].i = 0x0a0b0c07; +248 == 0x1 # code segment +249 # op ModR/M SIB displacement immediate +250 39 18 # compare EBX with *EAX +251 # ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) +252 == 0x60 # data segment +253 0d 0c 0b 0a # 0x0a0b0c0d +254 +run: compare EBX with r/m32 +255 +run: effective address is 0x60 (EAX) +256 +run: SF=0; ZF=0; OF=0 +257 +258 :(scenario compare_mem_at_r32_with_r32_lesser) +259 % Reg[EAX].i = 0x60; +260 % Reg[EBX].i = 0x0a0b0c0d; +261 == 0x1 # code segment +262 # op ModR/M SIB displacement immediate +263 39 18 # compare EBX with *EAX +264 # ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) +265 == 0x60 # data segment +266 07 0c 0b 0a # 0x0a0b0c0d +267 +run: compare EBX with r/m32 +268 +run: effective address is 0x60 (EAX) +269 +run: SF=1; ZF=0; OF=0 +270 +271 :(scenario compare_mem_at_r32_with_r32_equal) +272 % Reg[EAX].i = 0x60; +273 % Reg[EBX].i = 0x0a0b0c0d; +274 == 0x1 # code segment +275 # op ModR/M SIB displacement immediate +276 39 18 # compare EBX with *EAX +277 # ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) +278 == 0x60 # data segment +279 0d 0c 0b 0a # 0x0a0b0c0d +280 +run: compare EBX with r/m32 +281 +run: effective address is 0x60 (EAX) +282 +run: SF=0; ZF=1; OF=0 +283 +284 //: +285 +286 :(before "End Initialize Op Names(name)") +287 put(name, "3b", "set SF if rm32 > r32"); +288 +289 :(scenario compare_r32_with_mem_at_r32_greater) +290 % Reg[EAX].i = 0x60; +291 % Reg[EBX].i = 0x0a0b0c0d; +292 == 0x1 # code segment +293 # op ModR/M SIB displacement immediate +294 3b 18 # compare *EAX with EBX +295 # ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) +296 == 0x60 # data segment +297 07 0c 0b 0a # 0x0a0b0c0d +298 +run: compare r/m32 with EBX +299 +run: effective address is 0x60 (EAX) +300 +run: SF=0; ZF=0; OF=0 +301 +302 :(before "End Single-Byte Opcodes") +303 case 0x3b: { // set SF if r32 < r/m32 +304 uint8_t modrm = next(); +305 uint8_t reg1 = (modrm>>3)&0x7; +306 trace(90, "run") << "compare r/m32 with " << rname(reg1) << end(); +307 int32_t arg1 = Reg[reg1].i; +308 int32_t* arg2 = effective_address(modrm); +309 int32_t tmp1 = arg1 - *arg2; +310 SF = (tmp1 < 0); +311 ZF = (tmp1 == 0); +312 int64_t tmp2 = arg1 - *arg2; +313 OF = (tmp1 != tmp2); +314 trace(90, "run") << "SF=" << SF << "; ZF=" << ZF << "; OF=" << OF << end(); +315 break; +316 } +317 +318 :(scenario compare_r32_with_mem_at_r32_lesser) +319 % Reg[EAX].i = 0x60; +320 % Reg[EBX].i = 0x0a0b0c07; +321 == 0x1 # code segment +322 # op ModR/M SIB displacement immediate +323 3b 18 # compare *EAX with EBX +324 # ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) +325 == 0x60 # data segment +326 0d 0c 0b 0a # 0x0a0b0c0d +327 +run: compare r/m32 with EBX +328 +run: effective address is 0x60 (EAX) +329 +run: SF=1; ZF=0; OF=0 +330 +331 :(scenario compare_r32_with_mem_at_r32_equal) +332 % Reg[EAX].i = 0x60; +333 % Reg[EBX].i = 0x0a0b0c0d; +334 == 0x1 # code segment +335 # op ModR/M SIB displacement immediate +336 3b 18 # compare *EAX with EBX +337 # ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) +338 == 0x60 # data segment +339 0d 0c 0b 0a # 0x0a0b0c0d +340 +run: compare r/m32 with EBX +341 +run: effective address is 0x60 (EAX) +342 +run: SF=0; ZF=1; OF=0 +343 +344 //:: copy (mov) +345 +346 :(scenario copy_r32_to_mem_at_r32) +347 % Reg[EBX].i = 0xaf; +348 % Reg[EAX].i = 0x60; +349 == 0x1 +350 # op ModR/M SIB displacement immediate +351 89 18 # copy EBX to *EAX +352 # ModR/M in binary: 00 (indirect mode) 011 (src EAX) 000 (dest EAX) +353 +run: copy EBX to r/m32 +354 +run: effective address is 0x60 (EAX) +355 +run: storing 0x000000af +356 +357 //: +358 +359 :(before "End Initialize Op Names(name)") +360 put(name, "8b", "copy rm32 to r32"); +361 +362 :(scenario copy_mem_at_r32_to_r32) +363 % Reg[EAX].i = 0x60; +364 == 0x1 # code segment +365 # op ModR/M SIB displacement immediate +366 8b 18 # copy *EAX to EBX +367 # ModR/M in binary: 00 (indirect mode) 011 (src EBX) 000 (dest EAX) +368 == 0x60 # data segment +369 af 00 00 00 # 0xaf +370 +run: copy r/m32 to EBX +371 +run: effective address is 0x60 (EAX) +372 +run: storing 0x000000af +373 +374 :(before "End Single-Byte Opcodes") +375 case 0x8b: { // copy r32 to r/m32 +376 uint8_t modrm = next(); +377 uint8_t reg1 = (modrm>>3)&0x7; +378 trace(90, "run") << "copy r/m32 to " << rname(reg1) << end(); +379 int32_t* arg2 = effective_address(modrm); +380 Reg[reg1].i = *arg2; +381 trace(90, "run") << "storing 0x" << HEXWORD << *arg2 << end(); +382 break; +383 } +384 +385 //: +386 +387 :(before "End Initialize Op Names(name)") +388 put(name, "88", "copy r8 (lowermost byte of r32) to r8/m8-at-r32"); +389 +390 :(scenario copy_r8_to_mem_at_r32) +391 % Reg[EBX].i = 0xafafafaf; +392 % Reg[EAX].i = 0x60; +393 == 0x1 +394 # op ModR/M SIB displacement immediate +395 88 18 # copy just the lowermost byte of EBX to the byte at *EAX +396 # ModR/M in binary: 00 (indirect mode) 011 (src EBX) 000 (dest EAX) +397 +run: copy lowermost byte of EBX to r8/m8-at-r32 +398 +run: effective address is 0x60 (EAX) +399 +run: storing 0xaf +400 % CHECK_EQ(0x000000af, read_mem_u32(0x60)); +401 +402 :(before "End Single-Byte Opcodes") +403 case 0x88: { // copy r/m8 to r8 +404 uint8_t modrm = next(); +405 uint8_t reg2 = (modrm>>3)&0x7; +406 trace(90, "run") << "copy lowermost byte of " << rname(reg2) << " to r8/m8-at-r32" << end(); +407 // use unsigned to zero-extend 8-bit value to 32 bits +408 uint8_t* arg1 = reinterpret_cast<uint8_t*>(effective_address(modrm)); +409 *arg1 = Reg[reg2].u; +410 trace(90, "run") << "storing 0x" << HEXBYTE << NUM(*arg1) << end(); +411 break; +412 } +413 +414 //: +415 +416 :(before "End Initialize Op Names(name)") +417 put(name, "8a", "copy r8/m8-at-r32 to r8 (lowermost byte of r32)"); +418 +419 :(scenario copy_mem_at_r32_to_r8) +420 % Reg[EBX].i = 0xaf; +421 % Reg[EAX].i = 0x60; +422 == 0x1 +423 # op ModR/M SIB displacement immediate +424 8a 18 # copy just the byte at *EAX to lowermost byte of EBX (clearing remaining bytes) +425 # ModR/M in binary: 00 (indirect mode) 011 (dest EBX) 000 (src EAX) +426 == 0x60 # data segment +427 af ff ff ff # 0xaf with more data in following bytes +428 +run: copy r8/m8-at-r32 to lowermost byte of EBX +429 +run: effective address is 0x60 (EAX) +430 +run: storing 0xaf +431 +432 :(before "End Single-Byte Opcodes") +433 case 0x8a: { // copy r/m8 to r8 +434 uint8_t modrm = next(); +435 uint8_t reg1 = (modrm>>3)&0x7; +436 trace(90, "run") << "copy r8/m8-at-r32 to lowermost byte of " << rname(reg1) << end(); +437 // use unsigned to zero-extend 8-bit value to 32 bits +438 uint8_t* arg2 = reinterpret_cast<uint8_t*>(effective_address(modrm)); +439 Reg[reg1].u = static_cast<uint32_t>(*arg2); +440 trace(90, "run") << "storing 0x" << HEXBYTE << NUM(*arg2) << end(); +441 break; +442 } +443 +444 //:: jump +445 +446 :(before "End Initialize Op Names(name)") +447 put(name, "ff", "jump/push/call rm32 based on subop"); +448 +449 :(scenario jump_mem_at_r32) +450 % Reg[EAX].i = 0x60; +451 == 0x1 # code segment +452 # op ModR/M SIB displacement immediate +453 ff 20 # jump to *EAX +454 # ModR/M in binary: 00 (indirect mode) 100 (jump to r/m32) 000 (src EAX) +455 05 00 00 00 01 +456 05 00 00 00 02 +457 == 0x60 # data segment +458 08 00 00 00 # 8 +459 +run: inst: 0x00000001 +460 +run: jump to r/m32 +461 +run: effective address is 0x60 (EAX) +462 +run: jumping to 0x00000008 +463 +run: inst: 0x00000008 +464 -run: inst: 0x00000003 +465 +466 :(before "End Single-Byte Opcodes") +467 case 0xff: { +468 uint8_t modrm = next(); +469 uint8_t subop = (modrm>>3)&0x7; // middle 3 'reg opcode' bits +470 switch (subop) { +471 case 4: { // jump to r/m32 +472 trace(90, "run") << "jump to r/m32" << end(); +473 int32_t* arg2 = effective_address(modrm); +474 EIP = *arg2; +475 trace(90, "run") << "jumping to 0x" << HEXWORD << EIP << end(); +476 break; +477 } +478 // End Op ff Subops +479 } +480 break; +481 } +482 +483 //:: push +484 +485 :(scenario push_mem_at_r32) +486 % Reg[EAX].i = 0x60; +487 % Reg[ESP].u = 0x14; +488 == 0x1 # code segment +489 # op ModR/M SIB displacement immediate +490 ff 30 # push *EAX to stack +491 # ModR/M in binary: 00 (indirect mode) 110 (push r/m32) 000 (src EAX) +492 == 0x60 # data segment +493 af 00 00 00 # 0xaf +494 +run: push r/m32 +495 +run: effective address is 0x60 (EAX) +496 +run: decrementing ESP to 0x00000010 +497 +run: pushing value 0x000000af +498 +499 :(before "End Op ff Subops") +500 case 6: { // push r/m32 to stack +501 trace(90, "run") << "push r/m32" << end(); +502 const int32_t* val = effective_address(modrm); +503 push(*val); +504 break; +505 } +506 +507 //:: pop +508 +509 :(before "End Initialize Op Names(name)") +510 put(name, "8f", "pop top of stack to rm32"); +511 +512 :(scenario pop_mem_at_r32) +513 % Reg[EAX].i = 0x60; +514 % Reg[ESP].u = 0x10; +515 == 0x1 # code segment +516 # op ModR/M SIB displacement immediate +517 8f 00 # pop stack into *EAX +518 # ModR/M in binary: 00 (indirect mode) 000 (pop r/m32) 000 (dest EAX) +519 == 0x10 # data segment +520 30 00 00 00 # 0x30 +521 +run: pop into r/m32 +522 +run: effective address is 0x60 (EAX) +523 +run: popping value 0x00000030 +524 +run: incrementing ESP to 0x00000014 +525 +526 :(before "End Single-Byte Opcodes") +527 case 0x8f: { // pop stack into r/m32 +528 uint8_t modrm = next(); +529 uint8_t subop = (modrm>>3)&0x7; +530 switch (subop) { +531 case 0: { +532 trace(90, "run") << "pop into r/m32" << end(); +533 int32_t* dest = effective_address(modrm); +534 *dest = pop(); +535 break; +536 } +537 } +538 break; +539 } +540 +541 //:: special-case for loading address from disp32 rather than register +542 +543 :(scenario add_r32_to_mem_at_displacement) +544 % Reg[EBX].i = 0x10; // source +545 == 0x1 # code segment +546 # op ModR/M SIB displacement immediate +547 01 1d 60 00 00 00 # add EBX to *0x60 +548 # ModR/M in binary: 00 (indirect mode) 011 (src EBX) 101 (dest in disp32) +549 == 0x60 # data segment +550 01 00 00 00 # 1 +551 +run: add EBX to r/m32 +552 +run: effective address is 0x60 (disp32) +553 +run: storing 0x00000011 +554 +555 :(before "End Mod 0 Special-cases(addr)") +556 case 5: // exception: mod 0b00 rm 0b101 => incoming disp32 +557 addr = next32(); +558 trace(90, "run") << "effective address is 0x" << std::hex << addr << " (disp32)" << end(); +559 break; +560 +561 //: +562 +563 :(scenario add_r32_to_mem_at_r32_plus_disp8) +564 % Reg[EBX].i = 0x10; // source +565 % Reg[EAX].i = 0x5e; // dest +566 == 0x1 # code segment +567 # op ModR/M SIB displacement immediate +568 01 58 02 # add EBX to *(EAX+2) +569 # ModR/M in binary: 01 (indirect+disp8 mode) 011 (src EBX) 000 (dest EAX) +570 == 0x60 # data segment +571 01 00 00 00 # 1 +572 +run: add EBX to r/m32 +573 +run: effective address is initially 0x5e (EAX) +574 +run: effective address is 0x60 (after adding disp8) +575 +run: storing 0x00000011 +576 +577 :(before "End Mod Special-cases(addr)") +578 case 1: // indirect + disp8 addressing +579 switch (rm) { +580 default: +581 addr = Reg[rm].u; +582 trace(90, "run") << "effective address is initially 0x" << std::hex << addr << " (" << rname(rm) << ")" << end(); +583 break; +584 // End Mod 1 Special-cases(addr) +585 } +586 if (addr > 0) { +587 addr += static_cast<int8_t>(next()); +588 trace(90, "run") << "effective address is 0x" << std::hex << addr << " (after adding disp8)" << end(); +589 } +590 break; +591 +592 :(scenario add_r32_to_mem_at_r32_plus_negative_disp8) +593 % Reg[EBX].i = 0x10; // source +594 % Reg[EAX].i = 0x61; // dest +595 == 0x1 # code segment +596 # op ModR/M SIB displacement immediate +597 01 58 ff # add EBX to *(EAX-1) +598 # ModR/M in binary: 01 (indirect+disp8 mode) 011 (src EBX) 000 (dest EAX) +599 == 0x60 # data segment +600 01 00 00 00 # 1 +601 +run: add EBX to r/m32 +602 +run: effective address is initially 0x61 (EAX) +603 +run: effective address is 0x60 (after adding disp8) +604 +run: storing 0x00000011 +605 +606 //: +607 +608 :(scenario add_r32_to_mem_at_r32_plus_disp32) +609 % Reg[EBX].i = 0x10; // source +610 % Reg[EAX].i = 0x5e; // dest +611 == 0x1 # code segment +612 # op ModR/M SIB displacement immediate +613 01 98 02 00 00 00 # add EBX to *(EAX+2) +614 # ModR/M in binary: 10 (indirect+disp32 mode) 011 (src EBX) 000 (dest EAX) +615 == 0x60 # data segment +616 01 00 00 00 # 1 +617 +run: add EBX to r/m32 +618 +run: effective address is initially 0x5e (EAX) +619 +run: effective address is 0x60 (after adding disp32) +620 +run: storing 0x00000011 +621 +622 :(before "End Mod Special-cases(addr)") +623 case 2: // indirect + disp32 addressing +624 switch (rm) { +625 default: +626 addr = Reg[rm].u; +627 trace(90, "run") << "effective address is initially 0x" << std::hex << addr << " (" << rname(rm) << ")" << end(); +628 break; +629 // End Mod 2 Special-cases(addr) +630 } +631 if (addr > 0) { +632 addr += next32(); +633 trace(90, "run") << "effective address is 0x" << std::hex << addr << " (after adding disp32)" << end(); +634 } +635 break; +636 +637 :(scenario add_r32_to_mem_at_r32_plus_negative_disp32) +638 % Reg[EBX].i = 0x10; // source +639 % Reg[EAX].i = 0x61; // dest +640 == 0x1 # code segment +641 # op ModR/M SIB displacement immediate +642 01 98 ff ff ff ff # add EBX to *(EAX-1) +643 # ModR/M in binary: 10 (indirect+disp32 mode) 011 (src EBX) 000 (dest EAX) +644 == 0x60 # data segment +645 01 00 00 00 # 1 +646 +run: add EBX to r/m32 +647 +run: effective address is initially 0x61 (EAX) +648 +run: effective address is 0x60 (after adding disp32) +649 +run: storing 0x00000011 -- cgit 1.4.1-2-gfad0