Enabled arm64 encoding

This commit is contained in:
2025-03-06 16:54:28 +01:00
parent 5f522b519a
commit 7798eca074
9 changed files with 103 additions and 29 deletions

View File

@ -0,0 +1,8 @@
init() {
main.main()
exit()
}
exit() {
syscall(93, 0)
}

View File

@ -6,5 +6,10 @@ import "encoding/binary"
// 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, uint32(0b100101<<26)|offset)
return binary.LittleEndian.AppendUint32(code, EncodeCall(offset))
}
// EncodeCall returns the raw encoding of a call with the given offset.
func EncodeCall(offset uint32) uint32 {
return uint32(0b100101<<26) | offset
}

View File

@ -39,8 +39,8 @@ const (
var (
GeneralRegisters = []cpu.Register{X9, X10, X11, X12, X13, X14, X15, X16, X17, X18, X19, X20, X21, X22, X23, X24, X25, X26, X27, X28}
InputRegisters = SyscallInputRegisters
OutputRegisters = SyscallInputRegisters
InputRegisters = []cpu.Register{X0, X1, X2, X3, X4, X5}
OutputRegisters = InputRegisters
SyscallInputRegisters = []cpu.Register{X8, X0, X1, X2, X3, X4, X5}
SyscallOutputRegisters = []cpu.Register{X0, X1}
WindowsInputRegisters = []cpu.Register{X0, X1, X2, X3, X4, X5, X6, X7}

View File

@ -1,23 +1,54 @@
package asmc
import (
"fmt"
"git.urbach.dev/cli/q/src/arm"
"git.urbach.dev/cli/q/src/asm"
)
func (c *compiler) compileARM(x asm.Instruction) {
switch x.Mnemonic {
// case asm.MOVE:
// switch operands := x.Data.(type) {
// case *asm.RegisterNumber:
// c.code = arm.MoveRegisterNumber(c.code, operands.Register, operands.Number)
// }
case asm.CALL:
switch data := x.Data.(type) {
case *asm.Label:
position := len(c.code)
c.code = arm.Call(c.code, 0)
// case asm.RETURN:
// c.code = arm.Return(c.code)
pointer := &pointer{
Position: Address(position),
OpSize: 0,
Size: 4,
}
// case asm.SYSCALL:
// c.code = arm.Syscall(c.code)
pointer.Resolve = func() Address {
destination, exists := c.codeLabels[data.Name]
if !exists {
panic(fmt.Sprintf("unknown jump label %s", data.Name))
}
distance := (destination - pointer.Position) / 4
return arm.EncodeCall(distance)
}
c.codePointers = append(c.codePointers, pointer)
}
case asm.LABEL:
c.codeLabels[x.Data.(*asm.Label).Name] = Address(len(c.code))
case asm.MOVE:
switch operands := x.Data.(type) {
case *asm.RegisterNumber:
c.code = arm.MoveRegisterNumber(c.code, operands.Register, operands.Number)
}
case asm.RETURN:
c.code = arm.Return(c.code)
case asm.SYSCALL:
c.code = arm.Syscall(c.code)
default:
c.code = arm.Nop(c.code)

View File

@ -1,7 +1,7 @@
package asmc
// Address represents a memory address.
type Address = int32
type Address = uint32
// pointer stores a relative memory address that we can later turn into an absolute one.
// Position: The machine code offset where the address was inserted.

View File

@ -16,7 +16,7 @@ restart:
for i, pointer := range c.codePointers {
address := pointer.Resolve()
if sizeof.Signed(address) > int(pointer.Size) {
if sizeof.Signed(int32(address)) > int(pointer.Size) {
left := c.code[:pointer.Position-Address(pointer.OpSize)]
right := c.code[pointer.Position+Address(pointer.Size):]
size := pointer.Size + pointer.OpSize

View File

@ -7,10 +7,10 @@ import (
// Finalize returns the final raw data slice and a map of labels with their respective indices.
// It will try to reuse existing data whenever possible.
func (data Data) Finalize() ([]byte, map[string]int32) {
func (data Data) Finalize() ([]byte, map[string]uint32) {
var (
keys = make([]string, 0, len(data))
positions = make(map[string]int32, len(data))
positions = make(map[string]uint32, len(data))
capacity = 0
)
@ -30,9 +30,9 @@ func (data Data) Finalize() ([]byte, map[string]int32) {
position := bytes.Index(final, raw)
if position != -1 {
positions[key] = int32(position)
positions[key] = uint32(position)
} else {
positions[key] = int32(len(final))
positions[key] = uint32(len(final))
final = append(final, raw...)
}
}

View File

@ -21,20 +21,50 @@ func (s *Scanner) queueDirectory(directory string, pkg string) {
return
}
if strings.HasSuffix(name, "_linux.q") && config.TargetOS != config.Linux {
return
}
tmp := name[:len(name)-2]
if strings.HasSuffix(name, "_mac.q") && config.TargetOS != config.Mac {
return
}
for {
underscore := strings.LastIndexByte(tmp, '_')
if strings.HasSuffix(name, "_unix.q") && config.TargetOS != config.Linux && config.TargetOS != config.Mac {
return
}
if underscore == -1 {
break
}
if strings.HasSuffix(name, "_windows.q") && config.TargetOS != config.Windows {
return
condition := tmp[underscore+1:]
switch condition {
case "linux":
if config.TargetOS != config.Linux {
return
}
case "mac":
if config.TargetOS != config.Mac {
return
}
case "unix":
if config.TargetOS != config.Linux && config.TargetOS != config.Mac {
return
}
case "windows":
if config.TargetOS != config.Windows {
return
}
case "x86":
if config.TargetArch != config.X86 {
return
}
case "arm":
if config.TargetArch != config.ARM {
return
}
}
tmp = tmp[:underscore]
}
fullPath := filepath.Join(directory, name)