From 7798eca0740a12242253ecdd21ae0050430f02de Mon Sep 17 00:00:00 2001 From: Eduard Urbach Date: Thu, 6 Mar 2025 16:54:28 +0100 Subject: [PATCH] Enabled arm64 encoding --- lib/core/core_linux_arm.q | 8 ++++ lib/core/{core_linux.q => core_linux_x86.q} | 0 src/arm/Call.go | 7 ++- src/arm/Registers.go | 4 +- src/asmc/compileARM.go | 49 +++++++++++++++---- src/asmc/pointer.go | 2 +- src/asmc/resolvePointers.go | 2 +- src/data/Finalize.go | 8 ++-- src/scanner/queueDirectory.go | 52 ++++++++++++++++----- 9 files changed, 103 insertions(+), 29 deletions(-) create mode 100644 lib/core/core_linux_arm.q rename lib/core/{core_linux.q => core_linux_x86.q} (100%) diff --git a/lib/core/core_linux_arm.q b/lib/core/core_linux_arm.q new file mode 100644 index 0000000..939ba41 --- /dev/null +++ b/lib/core/core_linux_arm.q @@ -0,0 +1,8 @@ +init() { + main.main() + exit() +} + +exit() { + syscall(93, 0) +} \ No newline at end of file diff --git a/lib/core/core_linux.q b/lib/core/core_linux_x86.q similarity index 100% rename from lib/core/core_linux.q rename to lib/core/core_linux_x86.q diff --git a/src/arm/Call.go b/src/arm/Call.go index 1a4fd3f..5122e02 100644 --- a/src/arm/Call.go +++ b/src/arm/Call.go @@ -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 } diff --git a/src/arm/Registers.go b/src/arm/Registers.go index 62c7814..388dc0d 100644 --- a/src/arm/Registers.go +++ b/src/arm/Registers.go @@ -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} diff --git a/src/asmc/compileARM.go b/src/asmc/compileARM.go index 3c89d8d..06c2417 100644 --- a/src/asmc/compileARM.go +++ b/src/asmc/compileARM.go @@ -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) diff --git a/src/asmc/pointer.go b/src/asmc/pointer.go index f299758..bfd950c 100644 --- a/src/asmc/pointer.go +++ b/src/asmc/pointer.go @@ -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. diff --git a/src/asmc/resolvePointers.go b/src/asmc/resolvePointers.go index 2e6d30f..ea8aef2 100644 --- a/src/asmc/resolvePointers.go +++ b/src/asmc/resolvePointers.go @@ -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 diff --git a/src/data/Finalize.go b/src/data/Finalize.go index aa0787a..a4567a2 100644 --- a/src/data/Finalize.go +++ b/src/data/Finalize.go @@ -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...) } } diff --git a/src/scanner/queueDirectory.go b/src/scanner/queueDirectory.go index d99f0db..d5b0a47 100644 --- a/src/scanner/queueDirectory.go +++ b/src/scanner/queueDirectory.go @@ -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)