From 0e11812af3439fc0cecebcb6723b420fc7c4dc75 Mon Sep 17 00:00:00 2001 From: Eduard Urbach Date: Thu, 9 Oct 2025 11:37:21 +0200 Subject: [PATCH] Added more tests for LoadAddress on arm64 --- src/arm/LoadAddress.go | 15 ++++++++++----- src/arm/LoadAddress_test.go | 12 +++++++++--- src/arm/arm_test.go | 4 ++++ src/arm/mask.go | 1 + src/asm/compilerARM.go | 22 ++++++++++++++++++---- 5 files changed, 42 insertions(+), 12 deletions(-) diff --git a/src/arm/LoadAddress.go b/src/arm/LoadAddress.go index 1d60287..d570303 100644 --- a/src/arm/LoadAddress.go +++ b/src/arm/LoadAddress.go @@ -2,9 +2,14 @@ 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) +// LoadAddress calculates the address with the PC-relative offset in the range -1048576 to 1048575 +// and writes the result to the destination register. +func LoadAddress(destination cpu.Register, offset int) (code uint32, encodable bool) { + if offset < -1048576 || offset > 1048575 { + return 0, false + } + + hi := uint32(offset>>2) & mask19 + lo := uint32(offset) & mask2 + return lo<<29 | 0b10000<<24 | hi<<5 | uint32(destination), true } \ No newline at end of file diff --git a/src/arm/LoadAddress_test.go b/src/arm/LoadAddress_test.go index d43a836..95bdaed 100644 --- a/src/arm/LoadAddress_test.go +++ b/src/arm/LoadAddress_test.go @@ -11,17 +11,23 @@ import ( func TestLoadAddress(t *testing.T) { usagePatterns := []struct { Destination cpu.Register - Number int + Offset int Code uint32 }{ + {arm.X0, 0, 0x10000000}, + {arm.X0, 4, 0x10000020}, + {arm.X0, -4, 0x10FFFFE0}, {arm.X0, 56, 0x100001C0}, + {arm.X0, -1048576, 0x10800000}, + {arm.X0, 1048575, 0x707FFFE0}, {arm.X1, 80, 0x10000281}, {arm.X16, 0x3000, 0x10018010}, } for _, pattern := range usagePatterns { - t.Logf("adr %s, %d", pattern.Destination, pattern.Number) - code := arm.LoadAddress(pattern.Destination, pattern.Number) + t.Logf("adr %s, %d", pattern.Destination, pattern.Offset) + code, encodable := arm.LoadAddress(pattern.Destination, pattern.Offset) + assert.True(t, encodable) assert.Equal(t, code, pattern.Code) } } \ No newline at end of file diff --git a/src/arm/arm_test.go b/src/arm/arm_test.go index dbc29d5..0c7bd99 100644 --- a/src/arm/arm_test.go +++ b/src/arm/arm_test.go @@ -33,4 +33,8 @@ func TestNotEncodable(t *testing.T) { assert.False(t, encodable) _, encodable = arm.SubRegisterNumber(arm.X0, arm.X0, 0xF0000000) assert.False(t, encodable) + _, encodable = arm.LoadAddress(arm.X0, -1048577) + assert.False(t, encodable) + _, encodable = arm.LoadAddress(arm.X0, 1048576) + assert.False(t, encodable) } \ No newline at end of file diff --git a/src/arm/mask.go b/src/arm/mask.go index c7850f8..7bdb6cf 100644 --- a/src/arm/mask.go +++ b/src/arm/mask.go @@ -1,6 +1,7 @@ package arm const ( + mask2 = 0b11 mask6 = 0b111111 mask7 = 0b1111111 mask9 = 0b1_11111111 diff --git a/src/asm/compilerARM.go b/src/asm/compilerARM.go index d084bf7..161ea80 100644 --- a/src/asm/compilerARM.go +++ b/src/asm/compilerARM.go @@ -45,7 +45,8 @@ func (c *compilerARM) Compile(instr Instruction) { return code } case *CallExtern: - c.append(arm.LoadAddress(arm.X16, 0)) + encoding, _ := arm.LoadAddress(arm.X16, 0) + c.append(encoding) patch := c.PatchLast4Bytes() c.append(arm.LoadFixedOffset(arm.X16, arm.X16, arm.UnscaledImmediate, 0, 8)) c.append(arm.CallRegister(arm.X16)) @@ -59,7 +60,13 @@ func (c *compilerARM) Compile(instr Instruction) { address := c.importsStart + index*8 offset := address - patch.start - binary.LittleEndian.PutUint32(code, arm.LoadAddress(arm.X16, offset)) + encoding, encodable := arm.LoadAddress(arm.X16, offset) + + if !encodable { + panic("label offset outside of encodable range") + } + + binary.LittleEndian.PutUint32(code, encoding) return code } case *CallExternStart: @@ -155,7 +162,8 @@ func (c *compilerARM) Compile(instr Instruction) { c.append(arm.DivSignedRegisterRegister(instr.Destination, instr.Source, instr.Operand)) c.append(arm.MultiplySubtract(instr.Destination, instr.Destination, instr.Operand, instr.Source)) case *MoveLabel: - c.append(arm.LoadAddress(instr.Destination, 0)) + encoding, _ := arm.LoadAddress(instr.Destination, 0) + c.append(encoding) patch := c.PatchLast4Bytes() patch.apply = func(code []byte) []byte { @@ -166,7 +174,13 @@ func (c *compilerARM) Compile(instr Instruction) { } offset := address - patch.start - binary.LittleEndian.PutUint32(code, arm.LoadAddress(instr.Destination, offset)) + encoding, encodable := arm.LoadAddress(instr.Destination, offset) + + if !encodable { + panic("label offset outside of encodable range") + } + + binary.LittleEndian.PutUint32(code, encoding) return code } case *Move: -- 2.51.2