Implemented indirect calls on arm64
All checks were successful
/ test (push) Successful in 18s

This commit is contained in:
Eduard Urbach 2025-07-06 21:01:57 +02:00
parent a7fd4172b9
commit 6fda03fade
Signed by: akyoto
GPG key ID: 49226B848C78F6C8
3 changed files with 42 additions and 3 deletions

View file

@ -1,8 +1,15 @@
package arm package arm
import "git.urbach.dev/cli/q/src/cpu"
// Call branches to a PC-relative offset, setting the register X30 to PC+4. // 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. // 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). // This instruction is also known as BL (branch with link).
func Call(offset int) uint32 { func Call(offset int) uint32 {
return uint32(0b100101<<26) | uint32(offset&mask26) return uint32(0b100101<<26) | uint32(offset&mask26)
}
// Calls a function whose address is stored in the given register.
func CallRegister(register cpu.Register) uint32 {
return uint32(0b1101011000111111<<16) | uint32(register)<<5
} }

View file

@ -4,6 +4,7 @@ import (
"testing" "testing"
"git.urbach.dev/cli/q/src/arm" "git.urbach.dev/cli/q/src/arm"
"git.urbach.dev/cli/q/src/cpu"
"git.urbach.dev/go/assert" "git.urbach.dev/go/assert"
) )
@ -22,4 +23,21 @@ func TestCall(t *testing.T) {
code := arm.Call(pattern.Offset) code := arm.Call(pattern.Offset)
assert.Equal(t, code, pattern.Code) assert.Equal(t, code, pattern.Code)
} }
}
func TestCallRegister(t *testing.T) {
usagePatterns := []struct {
Register cpu.Register
Code uint32
}{
{arm.X0, 0xD63F0000},
{arm.X1, 0xD63F0020},
{arm.X2, 0xD63F0040},
}
for _, pattern := range usagePatterns {
t.Logf("blr %d", pattern.Register)
code := arm.CallRegister(pattern.Register)
assert.Equal(t, code, pattern.Code)
}
} }

View file

@ -2,6 +2,7 @@ package asm
import ( import (
"encoding/binary" "encoding/binary"
"fmt"
"git.urbach.dev/cli/q/src/arm" "git.urbach.dev/cli/q/src/arm"
) )
@ -33,11 +34,24 @@ func (c *compilerARM) Compile(instr Instruction) {
binary.LittleEndian.PutUint32(c.code[start:start+4], arm.Call(offset)) binary.LittleEndian.PutUint32(c.code[start:start+4], arm.Call(offset))
}) })
case *CallExtern: case *CallExtern:
panic("not implemented") start := len(c.code)
c.append(arm.LoadAddress(arm.X0, 0))
c.append(arm.LoadRegister(arm.X0, arm.X0, 0, 8))
c.append(arm.CallRegister(arm.X0))
c.Defer(func() {
index := c.libraries.Index(instr.Library, instr.Function)
if index == -1 {
panic(fmt.Sprintf("unknown extern function '%s' in library '%s'", instr.Function, instr.Library))
}
address := c.importsStart + index*8
offset := address - start
binary.LittleEndian.PutUint32(c.code[start:start+4], arm.LoadAddress(arm.X0, offset))
})
case *CallExternStart: case *CallExternStart:
panic("not implemented")
case *CallExternEnd: case *CallExternEnd:
panic("not implemented")
case *Jump: case *Jump:
start := len(c.code) start := len(c.code)
c.append(arm.Jump(0)) c.append(arm.Jump(0))