From 0ac7fc9a853a715d751833cb8ceeebc56a8a4771 Mon Sep 17 00:00:00 2001 From: Eduard Urbach Date: Thu, 6 Mar 2025 23:13:14 +0100 Subject: [PATCH] Implemented more arm64 instructions --- lib/sys/sys_linux_arm.q | 15 ++++++ lib/sys/{sys_linux.q => sys_linux_x86.q} | 0 src/arm/Call.go | 9 +--- src/arm/Load.go | 13 +++++ src/arm/LoadAddress.go | 10 ++++ src/arm/LoadAddress_test.go | 26 +++++++++ src/arm/Load_test.go | 31 +++++++++++ src/arm/Move.go | 21 ++++---- src/arm/Move_test.go | 33 +++++++++--- src/arm/Nop.go | 4 +- src/arm/Return.go | 4 +- src/arm/Syscall.go | 4 +- src/arm/arm_test.go | 10 ++-- src/asm/CanSkipReturn.go | 12 ++++- src/asmc/Finalize.go | 5 -- src/asmc/compileARM.go | 68 ++++++++++++++++++++---- src/asmc/compiler.go | 1 + src/asmc/load.go | 4 +- src/asmc/move.go | 2 +- src/asmc/resolvePointers.go | 8 +-- src/core/ResolveTypes.go | 3 +- src/x86/Load.go | 4 +- src/x86/LoadDynamic.go | 4 +- src/x86/LoadDynamic_test.go | 6 +-- src/x86/Load_test.go | 6 +-- src/x86/Move.go | 2 +- 26 files changed, 232 insertions(+), 73 deletions(-) create mode 100644 lib/sys/sys_linux_arm.q rename lib/sys/{sys_linux.q => sys_linux_x86.q} (100%) create mode 100644 src/arm/Load.go create mode 100644 src/arm/LoadAddress.go create mode 100644 src/arm/LoadAddress_test.go create mode 100644 src/arm/Load_test.go diff --git a/lib/sys/sys_linux_arm.q b/lib/sys/sys_linux_arm.q new file mode 100644 index 0000000..cfc351e --- /dev/null +++ b/lib/sys/sys_linux_arm.q @@ -0,0 +1,15 @@ +read(fd int, buffer *byte, length int) -> int { + return syscall(63, fd, buffer, length) +} + +write(fd int, buffer *byte, length int) -> int { + return syscall(64, fd, buffer, length) +} + +mmap(address int, length uint, protection int, flags int) -> *any { + return syscall(222, address, length, protection, flags) +} + +munmap(address *any, length uint) -> int { + return syscall(215, address, length) +} \ No newline at end of file diff --git a/lib/sys/sys_linux.q b/lib/sys/sys_linux_x86.q similarity index 100% rename from lib/sys/sys_linux.q rename to lib/sys/sys_linux_x86.q diff --git a/src/arm/Call.go b/src/arm/Call.go index 5122e02..8c1901f 100644 --- a/src/arm/Call.go +++ b/src/arm/Call.go @@ -1,15 +1,8 @@ package arm -import "encoding/binary" - // Call branches to a PC-relative offset, setting the register X30 to PC+4. // The offset starts from the address of this instruction and is encoded as "imm26" times 4. // This instruction is also known as BL (branch with link). -func Call(code []byte, offset uint32) []byte { - return binary.LittleEndian.AppendUint32(code, EncodeCall(offset)) -} - -// EncodeCall returns the raw encoding of a call with the given offset. -func EncodeCall(offset uint32) uint32 { +func Call(offset uint32) uint32 { return uint32(0b100101<<26) | offset } diff --git a/src/arm/Load.go b/src/arm/Load.go new file mode 100644 index 0000000..e1d09e1 --- /dev/null +++ b/src/arm/Load.go @@ -0,0 +1,13 @@ +package arm + +import "git.urbach.dev/cli/q/src/cpu" + +// LoadRegister loads from memory into a register. +func LoadRegister(destination cpu.Register, base cpu.Register, offset int16, length byte) uint32 { + if offset < 0 { + offset &= 0xFF + offset |= 1 << 8 + } + + return 0b11111000010<<21 | uint32(offset)<<12 | uint32(base)<<5 | uint32(destination) +} diff --git a/src/arm/LoadAddress.go b/src/arm/LoadAddress.go new file mode 100644 index 0000000..00284f5 --- /dev/null +++ b/src/arm/LoadAddress.go @@ -0,0 +1,10 @@ +package arm + +import "git.urbach.dev/cli/q/src/cpu" + +// LoadAddress calculates the address with the PC-relative offset and writes the result to the destination register. +func LoadAddress(destination cpu.Register, offset int) uint32 { + hi := uint32(offset) >> 2 + lo := uint32(offset) & 0b11 + return lo<<29 | 0b10000<<24 | hi<<5 | uint32(destination) +} diff --git a/src/arm/LoadAddress_test.go b/src/arm/LoadAddress_test.go new file mode 100644 index 0000000..3b3c05f --- /dev/null +++ b/src/arm/LoadAddress_test.go @@ -0,0 +1,26 @@ +package arm_test + +import ( + "testing" + + "git.urbach.dev/cli/q/src/arm" + "git.urbach.dev/cli/q/src/cpu" + "git.urbach.dev/go/assert" +) + +func TestLoadAddress(t *testing.T) { + usagePatterns := []struct { + Destination cpu.Register + Number int + Code uint32 + }{ + {arm.X0, 56, 0x100001C0}, + {arm.X1, 80, 0x10000281}, + } + + for _, pattern := range usagePatterns { + t.Logf("adr %s, %d", pattern.Destination, pattern.Number) + code := arm.LoadAddress(pattern.Destination, pattern.Number) + assert.DeepEqual(t, code, pattern.Code) + } +} diff --git a/src/arm/Load_test.go b/src/arm/Load_test.go new file mode 100644 index 0000000..c04f60a --- /dev/null +++ b/src/arm/Load_test.go @@ -0,0 +1,31 @@ +package arm_test + +import ( + "testing" + + "git.urbach.dev/cli/q/src/arm" + "git.urbach.dev/cli/q/src/cpu" + "git.urbach.dev/go/assert" +) + +func TestLoadRegister(t *testing.T) { + usagePatterns := []struct { + Destination cpu.Register + Base cpu.Register + Offset int16 + Length byte + Code uint32 + }{ + {arm.X2, arm.X1, -8, 8, 0xF85F8022}, + {arm.X2, arm.X1, 0, 8, 0xF8400022}, + {arm.X2, arm.X1, 8, 8, 0xF8408022}, + {arm.X2, arm.X1, -256, 8, 0xF8500022}, + {arm.X2, arm.X1, 255, 8, 0xF84FF022}, + } + + for _, pattern := range usagePatterns { + t.Logf("ldur %s, [%s, %d] %db", pattern.Destination, pattern.Base, pattern.Offset, pattern.Length) + code := arm.LoadRegister(pattern.Destination, pattern.Base, pattern.Offset, pattern.Length) + assert.DeepEqual(t, code, pattern.Code) + } +} diff --git a/src/arm/Move.go b/src/arm/Move.go index f26744f..e61ff8f 100644 --- a/src/arm/Move.go +++ b/src/arm/Move.go @@ -1,26 +1,27 @@ package arm import ( - "encoding/binary" - "git.urbach.dev/cli/q/src/cpu" ) +// MoveRegisterRegister copies a register to another register. +func MoveRegisterRegister(destination cpu.Register, source cpu.Register) uint32 { + return 0b10101010<<24 | uint32(source)<<16 | 0b11111<<5 | uint32(destination) +} + // MoveRegisterNumber moves an integer into the given register. -func MoveRegisterNumber(code []byte, destination cpu.Register, number int) []byte { - return MoveZero(code, destination, 0, uint16(number)) +func MoveRegisterNumber(destination cpu.Register, number int) uint32 { + return MoveZero(destination, 0, uint16(number)) } // MoveKeep moves a 16-bit integer into the given register and keeps all other bits. -func MoveKeep(code []byte, destination cpu.Register, halfword int, number uint16) []byte { - x := mov(0b11, halfword, number, destination) - return binary.LittleEndian.AppendUint32(code, x) +func MoveKeep(destination cpu.Register, halfword int, number uint16) uint32 { + return mov(0b11, halfword, number, destination) } // MoveZero moves a 16-bit integer into the given register and clears all other bits to zero. -func MoveZero(code []byte, destination cpu.Register, halfword int, number uint16) []byte { - x := mov(0b10, halfword, number, destination) - return binary.LittleEndian.AppendUint32(code, x) +func MoveZero(destination cpu.Register, halfword int, number uint16) uint32 { + return mov(0b10, halfword, number, destination) } // mov encodes a generic move instruction. diff --git a/src/arm/Move_test.go b/src/arm/Move_test.go index fb7f7d3..9811e37 100644 --- a/src/arm/Move_test.go +++ b/src/arm/Move_test.go @@ -8,19 +8,36 @@ import ( "git.urbach.dev/go/assert" ) +func TestMoveRegisterRegister(t *testing.T) { + usagePatterns := []struct { + Destination cpu.Register + Source cpu.Register + Code uint32 + }{ + {arm.X0, arm.X1, 0xAA0103E0}, + {arm.X1, arm.X0, 0xAA0003E1}, + } + + for _, pattern := range usagePatterns { + t.Logf("mov %s, %s", pattern.Destination, pattern.Source) + code := arm.MoveRegisterRegister(pattern.Destination, pattern.Source) + assert.DeepEqual(t, code, pattern.Code) + } +} + func TestMoveKeep(t *testing.T) { usagePatterns := []struct { Register cpu.Register Number uint16 - Code []byte + Code uint32 }{ - {arm.X0, 0, []byte{0x00, 0x00, 0x80, 0xF2}}, - {arm.X0, 1, []byte{0x20, 0x00, 0x80, 0xF2}}, + {arm.X0, 0, 0xF2800000}, + {arm.X0, 1, 0xF2800020}, } for _, pattern := range usagePatterns { t.Logf("movk %s, %x", pattern.Register, pattern.Number) - code := arm.MoveKeep(nil, pattern.Register, 0, pattern.Number) + code := arm.MoveKeep(pattern.Register, 0, pattern.Number) assert.DeepEqual(t, code, pattern.Code) } } @@ -29,15 +46,15 @@ func TestMoveZero(t *testing.T) { usagePatterns := []struct { Register cpu.Register Number uint16 - Code []byte + Code uint32 }{ - {arm.X0, 0, []byte{0x00, 0x00, 0x80, 0xD2}}, - {arm.X0, 1, []byte{0x20, 0x00, 0x80, 0xD2}}, + {arm.X0, 0, 0xD2800000}, + {arm.X0, 1, 0xD2800020}, } for _, pattern := range usagePatterns { t.Logf("movz %s, %x", pattern.Register, pattern.Number) - code := arm.MoveZero(nil, pattern.Register, 0, pattern.Number) + code := arm.MoveZero(pattern.Register, 0, pattern.Number) assert.DeepEqual(t, code, pattern.Code) } } diff --git a/src/arm/Nop.go b/src/arm/Nop.go index 8152293..6f518f4 100644 --- a/src/arm/Nop.go +++ b/src/arm/Nop.go @@ -1,6 +1,6 @@ package arm // Nop does nothing. This can be used for alignment purposes. -func Nop(code []byte) []byte { - return append(code, 0x1F, 0x20, 0x03, 0xD5) +func Nop() uint32 { + return 0xD503201F } diff --git a/src/arm/Return.go b/src/arm/Return.go index b98c038..898c6e7 100644 --- a/src/arm/Return.go +++ b/src/arm/Return.go @@ -1,6 +1,6 @@ package arm // Return transfers program control to the caller. -func Return(code []byte) []byte { - return append(code, 0xC0, 0x03, 0x5F, 0xD6) +func Return() uint32 { + return 0xD65F03C0 } diff --git a/src/arm/Syscall.go b/src/arm/Syscall.go index 2792926..e9227d6 100644 --- a/src/arm/Syscall.go +++ b/src/arm/Syscall.go @@ -1,6 +1,6 @@ package arm // Syscall is the primary way to communicate with the OS kernel. -func Syscall(code []byte) []byte { - return append(code, 0x01, 0x00, 0x00, 0xD4) +func Syscall() uint32 { + return 0xD4000001 } diff --git a/src/arm/arm_test.go b/src/arm/arm_test.go index b4918fc..948f869 100644 --- a/src/arm/arm_test.go +++ b/src/arm/arm_test.go @@ -8,9 +8,9 @@ import ( ) func TestARM(t *testing.T) { - assert.DeepEqual(t, arm.Call(nil, 0), []byte{0x00, 0x00, 0x00, 0x94}) - assert.DeepEqual(t, arm.MoveRegisterNumber(nil, arm.X0, 42), arm.MoveZero(nil, arm.X0, 0, 42)) - assert.DeepEqual(t, arm.Nop(nil), []byte{0x1F, 0x20, 0x03, 0xD5}) - assert.DeepEqual(t, arm.Return(nil), []byte{0xC0, 0x03, 0x5F, 0xD6}) - assert.DeepEqual(t, arm.Syscall(nil), []byte{0x01, 0x00, 0x00, 0xD4}) + assert.DeepEqual(t, arm.Call(0), 0x94000000) + assert.DeepEqual(t, arm.MoveRegisterNumber(arm.X0, 42), arm.MoveZero(arm.X0, 0, 42)) + assert.DeepEqual(t, arm.Nop(), 0xD503201F) + assert.DeepEqual(t, arm.Return(), 0xD65F03C0) + assert.DeepEqual(t, arm.Syscall(), 0xD4000001) } diff --git a/src/asm/CanSkipReturn.go b/src/asm/CanSkipReturn.go index 0ce31cb..56e5096 100644 --- a/src/asm/CanSkipReturn.go +++ b/src/asm/CanSkipReturn.go @@ -6,11 +6,19 @@ func (a *Assembler) CanSkipReturn() bool { return false } - lastMnemonic := a.Instructions[len(a.Instructions)-1].Mnemonic + last := a.Instructions[len(a.Instructions)-1] - if lastMnemonic == RETURN || lastMnemonic == JUMP { + if last.Mnemonic == RETURN || last.Mnemonic == JUMP { return true } + if last.Mnemonic == CALL { + label, isLabel := last.Data.(*Label) + + if isLabel && label.String() == "core.exit" { + return true + } + } + return false } diff --git a/src/asmc/Finalize.go b/src/asmc/Finalize.go index 2619905..708f207 100644 --- a/src/asmc/Finalize.go +++ b/src/asmc/Finalize.go @@ -1,7 +1,6 @@ package asmc import ( - "git.urbach.dev/cli/q/src/arm" "git.urbach.dev/cli/q/src/asm" "git.urbach.dev/cli/q/src/config" "git.urbach.dev/cli/q/src/dll" @@ -31,10 +30,6 @@ func Finalize(a asm.Assembler, dlls dll.List) ([]byte, []byte) { c.compileARM(x) } - c.code = arm.MoveRegisterNumber(c.code, arm.X0, 0) - c.code = arm.MoveRegisterNumber(c.code, arm.X8, 0x5D) - c.code = arm.Syscall(c.code) - case config.X86: for _, x := range a.Instructions { c.compileX86(x) diff --git a/src/asmc/compileARM.go b/src/asmc/compileARM.go index 06c2417..058f1f0 100644 --- a/src/asmc/compileARM.go +++ b/src/asmc/compileARM.go @@ -1,7 +1,10 @@ package asmc import ( + "encoding/binary" "fmt" + "math" + "strings" "git.urbach.dev/cli/q/src/arm" "git.urbach.dev/cli/q/src/asm" @@ -12,11 +15,11 @@ func (c *compiler) compileARM(x asm.Instruction) { case asm.CALL: switch data := x.Data.(type) { case *asm.Label: - position := len(c.code) - c.code = arm.Call(c.code, 0) + position := Address(len(c.code)) + c.append(arm.Call(0)) pointer := &pointer{ - Position: Address(position), + Position: position, OpSize: 0, Size: 4, } @@ -28,8 +31,8 @@ func (c *compiler) compileARM(x asm.Instruction) { panic(fmt.Sprintf("unknown jump label %s", data.Name)) } - distance := (destination - pointer.Position) / 4 - return arm.EncodeCall(distance) + distance := (destination - position) / 4 + return arm.Call(distance) } c.codePointers = append(c.codePointers, pointer) @@ -37,20 +40,67 @@ func (c *compiler) compileARM(x asm.Instruction) { case asm.LABEL: c.codeLabels[x.Data.(*asm.Label).Name] = Address(len(c.code)) + c.append(0xa9be7bfd) + c.append(0x910003fd) + + case asm.LOAD: + switch operands := x.Data.(type) { + case *asm.MemoryRegister: + if operands.Address.OffsetRegister == math.MaxUint8 { + c.append(arm.LoadRegister(operands.Register, operands.Address.Base, int16(operands.Address.Offset), operands.Address.Length)) + } else { + // TODO: LoadDynamicRegister + panic("not implemented") + } + } case asm.MOVE: switch operands := x.Data.(type) { + case *asm.RegisterRegister: + c.append(arm.MoveRegisterRegister(operands.Destination, operands.Source)) + case *asm.RegisterNumber: - c.code = arm.MoveRegisterNumber(c.code, operands.Register, operands.Number) + c.append(arm.MoveRegisterNumber(operands.Register, operands.Number)) + + case *asm.RegisterLabel: + position := Address(len(c.code)) + c.append(arm.LoadAddress(operands.Register, 0)) + + if strings.HasPrefix(operands.Label, "data ") { + c.dataPointers = append(c.dataPointers, &pointer{ + Position: position, + OpSize: 0, + Size: 4, + Resolve: func() Address { + destination, exists := c.dataLabels[operands.Label] + + if !exists { + panic("unknown label") + } + + destination += c.dataStart - c.codeStart + distance := destination - position + 8 + return arm.LoadAddress(operands.Register, int(distance)) + }, + }) + } else { + panic("not implemented") + } } case asm.RETURN: - c.code = arm.Return(c.code) + c.append(0xa8c27bfd) + c.append(0xd65f03c0) + c.append(arm.Return()) case asm.SYSCALL: - c.code = arm.Syscall(c.code) + c.append(arm.Syscall()) default: - c.code = arm.Nop(c.code) + panic("unknown mnemonic: " + x.Mnemonic.String()) } } + +func (c *compiler) append(code uint32) { + c.code = binary.LittleEndian.AppendUint32(c.code, code) +} diff --git a/src/asmc/compiler.go b/src/asmc/compiler.go index b4e30e6..041e590 100644 --- a/src/asmc/compiler.go +++ b/src/asmc/compiler.go @@ -12,4 +12,5 @@ type compiler struct { dllPointers []*pointer dlls dll.List codeStart Address + dataStart Address } diff --git a/src/asmc/load.go b/src/asmc/load.go index 7a3a707..8b28fa8 100644 --- a/src/asmc/load.go +++ b/src/asmc/load.go @@ -11,9 +11,9 @@ func (c *compiler) load(x asm.Instruction) { switch operands := x.Data.(type) { case *asm.MemoryRegister: if operands.Address.OffsetRegister == math.MaxUint8 { - c.code = x86.LoadRegister(c.code, operands.Register, operands.Address.Offset, operands.Address.Length, operands.Address.Base) + c.code = x86.LoadRegister(c.code, operands.Register, operands.Address.Base, operands.Address.Offset, operands.Address.Length) } else { - c.code = x86.LoadDynamicRegister(c.code, operands.Register, operands.Address.OffsetRegister, operands.Address.Length, operands.Address.Base) + c.code = x86.LoadDynamicRegister(c.code, operands.Register, operands.Address.Base, operands.Address.OffsetRegister, operands.Address.Length) } } } diff --git a/src/asmc/move.go b/src/asmc/move.go index 71e71f3..056872c 100644 --- a/src/asmc/move.go +++ b/src/asmc/move.go @@ -35,7 +35,7 @@ func (c *compiler) move(x asm.Instruction) { panic("unknown label") } - return destination + return config.BaseAddress + c.dataStart + destination + 8 }, }) } else { diff --git a/src/asmc/resolvePointers.go b/src/asmc/resolvePointers.go index ea8aef2..6e3ac9d 100644 --- a/src/asmc/resolvePointers.go +++ b/src/asmc/resolvePointers.go @@ -77,16 +77,16 @@ restart: } } - dataStart, _ := fs.Align(c.codeStart+Address(len(c.code)), config.Align) + c.dataStart, _ = fs.Align(c.codeStart+Address(len(c.code)), config.Align) for _, pointer := range c.dataPointers { - address := config.BaseAddress + dataStart + pointer.Resolve() + 8 - slice := c.code[pointer.Position : pointer.Position+4] + address := pointer.Resolve() + slice := c.code[pointer.Position : pointer.Position+Address(pointer.Size)] binary.LittleEndian.PutUint32(slice, uint32(address)) } if config.TargetOS == config.Windows { - importsStart, _ := fs.Align(dataStart+Address(len(c.data)), config.Align) + importsStart, _ := fs.Align(c.dataStart+Address(len(c.data)), config.Align) for _, pointer := range c.dllPointers { destination := importsStart + pointer.Resolve() diff --git a/src/core/ResolveTypes.go b/src/core/ResolveTypes.go index e10e41e..306309e 100644 --- a/src/core/ResolveTypes.go +++ b/src/core/ResolveTypes.go @@ -6,7 +6,6 @@ import ( "git.urbach.dev/cli/q/src/scope" "git.urbach.dev/cli/q/src/token" "git.urbach.dev/cli/q/src/types" - "git.urbach.dev/cli/q/src/x86" ) // ResolveTypes parses the input and output types. @@ -34,7 +33,7 @@ func (f *Function) ResolveTypes() error { Name: param.name, Value: eval.Register{ Typ: param.typ, - Register: x86.InputRegisters[i], + Register: f.CPU.Input[i], Alive: uses, }, }) diff --git a/src/x86/Load.go b/src/x86/Load.go index dc04a25..f29a08e 100644 --- a/src/x86/Load.go +++ b/src/x86/Load.go @@ -3,6 +3,6 @@ package x86 import "git.urbach.dev/cli/q/src/cpu" // LoadRegister loads from memory into a register. -func LoadRegister(code []byte, destination cpu.Register, offset int8, length byte, source cpu.Register) []byte { - return memoryAccess(code, 0x8A, 0x8B, source, offset, length, destination) +func LoadRegister(code []byte, destination cpu.Register, base cpu.Register, offset int8, length byte) []byte { + return memoryAccess(code, 0x8A, 0x8B, base, offset, length, destination) } diff --git a/src/x86/LoadDynamic.go b/src/x86/LoadDynamic.go index 1c5cb30..c06878e 100644 --- a/src/x86/LoadDynamic.go +++ b/src/x86/LoadDynamic.go @@ -3,6 +3,6 @@ package x86 import "git.urbach.dev/cli/q/src/cpu" // LoadDynamicRegister loads from memory with a register offset into a register. -func LoadDynamicRegister(code []byte, destination cpu.Register, offset cpu.Register, length byte, source cpu.Register) []byte { - return memoryAccessDynamic(code, 0x8A, 0x8B, source, offset, length, destination) +func LoadDynamicRegister(code []byte, destination cpu.Register, base cpu.Register, offset cpu.Register, length byte) []byte { + return memoryAccessDynamic(code, 0x8A, 0x8B, base, offset, length, destination) } diff --git a/src/x86/LoadDynamic_test.go b/src/x86/LoadDynamic_test.go index 9638e80..4cc3935 100644 --- a/src/x86/LoadDynamic_test.go +++ b/src/x86/LoadDynamic_test.go @@ -12,7 +12,7 @@ func TestLoadDynamicRegister(t *testing.T) { usagePatterns := []struct { Destination cpu.Register Length byte - Source cpu.Register + Base cpu.Register OffsetRegister cpu.Register Code []byte }{ @@ -83,8 +83,8 @@ func TestLoadDynamicRegister(t *testing.T) { } for _, pattern := range usagePatterns { - t.Logf("load %dB %s, [%s+%s]", pattern.Length, pattern.Destination, pattern.Source, pattern.OffsetRegister) - code := x86.LoadDynamicRegister(nil, pattern.Destination, pattern.OffsetRegister, pattern.Length, pattern.Source) + t.Logf("load %dB %s, [%s+%s]", pattern.Length, pattern.Destination, pattern.Base, pattern.OffsetRegister) + code := x86.LoadDynamicRegister(nil, pattern.Destination, pattern.Base, pattern.OffsetRegister, pattern.Length) assert.DeepEqual(t, code, pattern.Code) } } diff --git a/src/x86/Load_test.go b/src/x86/Load_test.go index b81f6e0..3d5240b 100644 --- a/src/x86/Load_test.go +++ b/src/x86/Load_test.go @@ -11,7 +11,7 @@ import ( func TestLoadRegister(t *testing.T) { usagePatterns := []struct { Destination cpu.Register - Source cpu.Register + Base cpu.Register Offset int8 Length byte Code []byte @@ -150,8 +150,8 @@ func TestLoadRegister(t *testing.T) { } for _, pattern := range usagePatterns { - t.Logf("load %dB %s, [%s+%d]", pattern.Length, pattern.Destination, pattern.Source, pattern.Offset) - code := x86.LoadRegister(nil, pattern.Destination, pattern.Offset, pattern.Length, pattern.Source) + t.Logf("load %dB %s, [%s+%d]", pattern.Length, pattern.Destination, pattern.Base, pattern.Offset) + code := x86.LoadRegister(nil, pattern.Destination, pattern.Base, pattern.Offset, pattern.Length) assert.DeepEqual(t, code, pattern.Code) } } diff --git a/src/x86/Move.go b/src/x86/Move.go index efe8756..7e3b103 100644 --- a/src/x86/Move.go +++ b/src/x86/Move.go @@ -54,7 +54,7 @@ func MoveRegisterNumber32(code []byte, destination cpu.Register, number int) []b return binary.LittleEndian.AppendUint32(code, uint32(number)) } -// MoveRegisterRegister moves a register value into another register. +// MoveRegisterRegister copies a register to another register. func MoveRegisterRegister(code []byte, destination cpu.Register, source cpu.Register) []byte { return encode(code, AddressDirect, source, destination, 8, 0x89) }