Skip to content

Instantly share code, notes, and snippets.

@iosadchiy
Last active June 21, 2018 08:57
Show Gist options
  • Save iosadchiy/39fbe6d96a9254d0bd90f67956fd7d9d to your computer and use it in GitHub Desktop.
Save iosadchiy/39fbe6d96a9254d0bd90f67956fd7d9d to your computer and use it in GitHub Desktop.
TV A1
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