Last active
June 21, 2018 08:57
-
-
Save iosadchiy/39fbe6d96a9254d0bd90f67956fd7d9d to your computer and use it in GitHub Desktop.
TV A1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package tv_a1 | |
import ( | |
"fmt" | |
"testing" | |
) | |
type Vcpu struct { | |
} | |
const ( | |
LOCK_PREFIX = 1 << iota | |
//... | |
OPERAND_SIZE_OVERRIDE_PREFIX | |
//... | |
) | |
func (c *Vcpu) Decode(ip []byte, opts int) (disasm string) { | |
// Parse prefixes if any and call self with updated ip and opts | |
switch ip[0] { | |
case 0xF0: // LOCK | |
return c.Decode(ip[1:], opts|LOCK_PREFIX) | |
case 0xF2: // REPNE/REPNZ | |
case 0xF3: // REP or REPE/REPZ | |
// The six prefixes to change the segment register | |
case 0x26: // ES | |
case 0x2E: // CS | |
case 0x36: // SS | |
case 0x3E: // DS | |
case 0x64: // FS | |
case 0x65: // GS | |
case 0x66: // Override operand size | |
return c.Decode(ip[1:], opts|OPERAND_SIZE_OVERRIDE_PREFIX) | |
case 0x67: // Address-size override prefix | |
// ... some more prefixes are possible | |
} | |
// Optional REX prefix | |
if ip[0]|0xF0 == 0x40 { | |
w := ip[0] | 0x08 // 1 for 64bit operand, 0 for default | |
r := ip[0] | 0x04 // Extends MODRM.reg | |
x := ip[0] | 0x02 // Extends SIB.index | |
b := ip[0] | 0x01 // Extends MODRM.rm OR SIB.base | |
fmt.Printf("REX: %d%d%d%d\n", w, r, x, b) | |
ip = ip[1:] | |
} | |
// Opcode | |
if ip[0] == 0x0F { | |
if ip[1] == 0x38 { | |
// Decode 3-byte opcode 0x0F 0x38 <op> | |
ip = ip[3:] | |
} else if ip[1] == 0x3A { | |
// Decode 3-byte opcode 0x0F 0x3A <op> | |
ip = ip[3:] | |
} else { | |
// Decode 2-byte opcode 0x0F <op> | |
switch ip[1] { | |
case 0x60: | |
disasm = "punpcklbw" | |
} | |
ip = ip[2:] | |
} | |
} else { | |
// Decode 1-byte opcode | |
switch ip[0] { | |
case 0x06: | |
disasm = "push es" | |
case 0x89: | |
disasm = "mov" | |
} | |
ip = ip[1:] | |
} | |
// Parse optional MODRM and operands | |
if len(ip) > 0 { | |
if ip[0] == 0xD8 { | |
if opts&OPERAND_SIZE_OVERRIDE_PREFIX > 0 { | |
disasm += " ax, bx" | |
} else { | |
disasm += " eax, ebx" | |
} | |
} else if ip[0] == 0xCD { | |
disasm += " mm1, mm5" | |
} | |
} | |
return disasm | |
} | |
type TestCase struct { | |
CodeSeq []byte | |
Disasm string | |
} | |
func TestBasic(t *testing.T) { | |
c := &Vcpu{} | |
push_es := []byte{0x06} // push es | |
mov_eax_ebx := []byte{0x89, 0xD8} // mov eax, ebx | |
mov_ax_bx := []byte{0x66, 0x89, 0xD8} // mov ax, bx | |
punpcklbw := []byte{0x0F, 0x60, 0xCD} // punpcklbw mm1, mm5 | |
testCases := []TestCase{ | |
{push_es, "push es"}, | |
{mov_eax_ebx, "mov eax, ebx"}, | |
{mov_ax_bx, "mov ax, bx"}, | |
{punpcklbw, "punpcklbw mm1, mm5"}, | |
} | |
for _, test := range testCases { | |
fmt.Println(test.CodeSeq) | |
disasm := c.Decode(test.CodeSeq, 0) | |
if disasm != test.Disasm { | |
t.Errorf("Disasm invalid. Expected: %s, got: %s", test.Disasm, disasm) | |
} | |
} | |
//fmt.Println(c.Decode(mov_ax_bx, 0)) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment