From 47d94acd439a137a2fc0ddb2b5a32ff392e0ac01 Mon Sep 17 00:00:00 2001 From: Eduard Urbach Date: Wed, 26 Jun 2024 12:55:22 +0200 Subject: [PATCH] Added more tests --- src/build/arch/x64/Jump.go | 2 +- src/build/arch/x64/Move.go | 40 +++++-------------- src/build/arch/x64/Move_test.go | 71 +++++++++++++++++++++++++++++++++ src/build/arch/x64/Sub_test.go | 31 ++++++++++++++ src/build/arch/x64/regRegNum.go | 10 ++--- 5 files changed, 116 insertions(+), 38 deletions(-) create mode 100644 src/build/arch/x64/Move_test.go diff --git a/src/build/arch/x64/Jump.go b/src/build/arch/x64/Jump.go index 32b8b98..5b3f125 100644 --- a/src/build/arch/x64/Jump.go +++ b/src/build/arch/x64/Jump.go @@ -5,7 +5,7 @@ package x64 func Jump8(code []byte, address int8) []byte { return append( code, - 0xeb, + 0xEB, byte(address), ) } diff --git a/src/build/arch/x64/Move.go b/src/build/arch/x64/Move.go index 9f57728..e266d33 100644 --- a/src/build/arch/x64/Move.go +++ b/src/build/arch/x64/Move.go @@ -1,43 +1,23 @@ package x64 -import "git.akyoto.dev/cli/q/src/build/cpu" +import ( + "encoding/binary" + + "git.akyoto.dev/cli/q/src/build/cpu" +) // MoveRegisterNumber32 moves a 32 bit integer into the given register. func MoveRegisterNumber32(code []byte, destination cpu.Register, number uint32) []byte { - if destination >= 8 { + if destination > 0b111 { code = append(code, REX(0, 0, 0, 1)) - destination -= 8 + destination &= 0b111 } - return append( - code, - 0xb8+byte(destination), - byte(number), - byte(number>>8), - byte(number>>16), - byte(number>>24), - ) + code = append(code, 0xb8+byte(destination)) + return binary.LittleEndian.AppendUint32(code, number) } // MoveRegisterRegister64 moves a register value into another register. func MoveRegisterRegister64(code []byte, destination cpu.Register, source cpu.Register) []byte { - r := byte(0) // Extension to the "reg" field in ModRM. - b := byte(0) // Extension to the "rm" field in ModRM or the SIB base (r8 up to r15 use this). - - if source >= 8 { - r = 1 - source -= 8 - } - - if destination >= 8 { - b = 1 - destination -= 8 - } - - return append( - code, - REX(1, r, 0, b), - 0x89, - ModRM(0b11, byte(source), byte(destination)), - ) + return regReg(code, byte(source), byte(destination), 0x89) } diff --git a/src/build/arch/x64/Move_test.go b/src/build/arch/x64/Move_test.go new file mode 100644 index 0000000..7d5251e --- /dev/null +++ b/src/build/arch/x64/Move_test.go @@ -0,0 +1,71 @@ +package x64_test + +import ( + "testing" + + "git.akyoto.dev/cli/q/src/build/arch/x64" + "git.akyoto.dev/cli/q/src/build/cpu" + "git.akyoto.dev/go/assert" +) + +func TestMoveRegisterNumber(t *testing.T) { + usagePatterns := []struct { + Register cpu.Register + Number int + Code []byte + }{ + {x64.RAX, 0x7FFFFFFF, []byte{0xB8, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.RCX, 0x7FFFFFFF, []byte{0xB9, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.RDX, 0x7FFFFFFF, []byte{0xBA, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.RBX, 0x7FFFFFFF, []byte{0xBB, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.RSP, 0x7FFFFFFF, []byte{0xBC, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.RBP, 0x7FFFFFFF, []byte{0xBD, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.RSI, 0x7FFFFFFF, []byte{0xBE, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.RDI, 0x7FFFFFFF, []byte{0xBF, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R8, 0x7FFFFFFF, []byte{0x41, 0xB8, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R9, 0x7FFFFFFF, []byte{0x41, 0xB9, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R10, 0x7FFFFFFF, []byte{0x41, 0xBA, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R11, 0x7FFFFFFF, []byte{0x41, 0xBB, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R12, 0x7FFFFFFF, []byte{0x41, 0xBC, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R13, 0x7FFFFFFF, []byte{0x41, 0xBD, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R14, 0x7FFFFFFF, []byte{0x41, 0xBE, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R15, 0x7FFFFFFF, []byte{0x41, 0xBF, 0xFF, 0xFF, 0xFF, 0x7F}}, + } + + for _, pattern := range usagePatterns { + t.Logf("mov %s, %x", pattern.Register, pattern.Number) + code := x64.MoveRegisterNumber32(nil, pattern.Register, uint32(pattern.Number)) + assert.DeepEqual(t, code, pattern.Code) + } +} + +func TestMoveRegisterRegister(t *testing.T) { + usagePatterns := []struct { + Left cpu.Register + Right cpu.Register + Code []byte + }{ + {x64.RAX, x64.R15, []byte{0x4C, 0x89, 0xF8}}, + {x64.RCX, x64.R14, []byte{0x4C, 0x89, 0xF1}}, + {x64.RDX, x64.R13, []byte{0x4C, 0x89, 0xEA}}, + {x64.RBX, x64.R12, []byte{0x4C, 0x89, 0xE3}}, + {x64.RSP, x64.R11, []byte{0x4C, 0x89, 0xDC}}, + {x64.RBP, x64.R10, []byte{0x4C, 0x89, 0xD5}}, + {x64.RSI, x64.R9, []byte{0x4C, 0x89, 0xCE}}, + {x64.RDI, x64.R8, []byte{0x4C, 0x89, 0xC7}}, + {x64.R8, x64.RDI, []byte{0x49, 0x89, 0xF8}}, + {x64.R9, x64.RSI, []byte{0x49, 0x89, 0xF1}}, + {x64.R10, x64.RBP, []byte{0x49, 0x89, 0xEA}}, + {x64.R11, x64.RSP, []byte{0x49, 0x89, 0xE3}}, + {x64.R12, x64.RBX, []byte{0x49, 0x89, 0xDC}}, + {x64.R13, x64.RDX, []byte{0x49, 0x89, 0xD5}}, + {x64.R14, x64.RCX, []byte{0x49, 0x89, 0xCE}}, + {x64.R15, x64.RAX, []byte{0x49, 0x89, 0xC7}}, + } + + for _, pattern := range usagePatterns { + t.Logf("mov %s, %s", pattern.Left, pattern.Right) + code := x64.MoveRegisterRegister64(nil, pattern.Left, pattern.Right) + assert.DeepEqual(t, code, pattern.Code) + } +} diff --git a/src/build/arch/x64/Sub_test.go b/src/build/arch/x64/Sub_test.go index 2380098..69199e9 100644 --- a/src/build/arch/x64/Sub_test.go +++ b/src/build/arch/x64/Sub_test.go @@ -55,3 +55,34 @@ func TestSubRegisterNumber(t *testing.T) { assert.DeepEqual(t, code, pattern.Code) } } + +func TestSubRegisterRegister(t *testing.T) { + usagePatterns := []struct { + Left cpu.Register + Right cpu.Register + Code []byte + }{ + {x64.RAX, x64.R15, []byte{0x4C, 0x29, 0xF8}}, + {x64.RCX, x64.R14, []byte{0x4C, 0x29, 0xF1}}, + {x64.RDX, x64.R13, []byte{0x4C, 0x29, 0xEA}}, + {x64.RBX, x64.R12, []byte{0x4C, 0x29, 0xE3}}, + {x64.RSP, x64.R11, []byte{0x4C, 0x29, 0xDC}}, + {x64.RBP, x64.R10, []byte{0x4C, 0x29, 0xD5}}, + {x64.RSI, x64.R9, []byte{0x4C, 0x29, 0xCE}}, + {x64.RDI, x64.R8, []byte{0x4C, 0x29, 0xC7}}, + {x64.R8, x64.RDI, []byte{0x49, 0x29, 0xF8}}, + {x64.R9, x64.RSI, []byte{0x49, 0x29, 0xF1}}, + {x64.R10, x64.RBP, []byte{0x49, 0x29, 0xEA}}, + {x64.R11, x64.RSP, []byte{0x49, 0x29, 0xE3}}, + {x64.R12, x64.RBX, []byte{0x49, 0x29, 0xDC}}, + {x64.R13, x64.RDX, []byte{0x49, 0x29, 0xD5}}, + {x64.R14, x64.RCX, []byte{0x49, 0x29, 0xCE}}, + {x64.R15, x64.RAX, []byte{0x49, 0x29, 0xC7}}, + } + + for _, pattern := range usagePatterns { + t.Logf("sub %s, %s", pattern.Left, pattern.Right) + code := x64.SubRegisterRegister(nil, pattern.Left, pattern.Right) + assert.DeepEqual(t, code, pattern.Code) + } +} diff --git a/src/build/arch/x64/regRegNum.go b/src/build/arch/x64/regRegNum.go index 8a04be4..0fb41d1 100644 --- a/src/build/arch/x64/regRegNum.go +++ b/src/build/arch/x64/regRegNum.go @@ -1,5 +1,7 @@ package x64 +import "encoding/binary" + // regRegNum encodes an instruction with up to two registers and a number parameter. func regRegNum(code []byte, reg byte, rm byte, number int, opCode8 byte, opCode32 byte) []byte { if sizeOf(number) == 1 { @@ -8,11 +10,5 @@ func regRegNum(code []byte, reg byte, rm byte, number int, opCode8 byte, opCode3 } code = regReg(code, reg, rm, opCode32) - return append( - code, - byte(number), - byte(number>>8), - byte(number>>16), - byte(number>>24), - ) + return binary.LittleEndian.AppendUint32(code, uint32(number)) }