From 3cba36f2ba789a7680d9bef98acb5f84bdcfbdf8 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Tue, 5 Feb 2019 20:13:39 +0100 Subject: [PATCH] compiler: add syscalls for 64-bit arm --- .travis.yml | 2 ++ compiler/syscall.go | 35 +++++++++++++++++++++++++++++++++++ main_test.go | 10 ++++++++++ target.go | 3 ++- 4 files changed, 49 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 40f2b8c7..365a6df8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,6 +18,8 @@ addons: - gcc-arm-linux-gnueabi - binutils-arm-none-eabi - libc6-dev-armel-cross + - gcc-aarch64-linux-gnu + - libc6-dev-arm64-cross - qemu-system-arm - qemu-user - gcc-avr diff --git a/compiler/syscall.go b/compiler/syscall.go index 6ba6535d..fc9235d3 100644 --- a/compiler/syscall.go +++ b/compiler/syscall.go @@ -81,6 +81,41 @@ func (c *Compiler) emitSyscall(frame *Frame, call *ssa.CallCommon) (llvm.Value, fnType := llvm.FunctionType(c.uintptrType, argTypes, false) target := llvm.InlineAsm(fnType, "svc #0", constraints, true, false, 0) syscallResult = c.builder.CreateCall(target, args, "") + case c.GOARCH == "arm64" && c.GOOS == "linux": + // Source: syscall(2) man page. + args := []llvm.Value{} + argTypes := []llvm.Type{} + // Constraints will look something like: + // ={x0},0,{x1},{x2},{x8},~{x3},~{x4},~{x5},~{x6},~{x7},~{x16},~{x17} + constraints := "={x0}" + for i, arg := range call.Args[1:] { + constraints += "," + [...]string{ + "0", // tie to output + "{x1}", + "{x2}", + "{x3}", + "{x4}", + "{x5}", + }[i] + llvmValue, err := c.parseExpr(frame, arg) + if err != nil { + return llvm.Value{}, err + } + args = append(args, llvmValue) + argTypes = append(argTypes, llvmValue.Type()) + } + args = append(args, llvm.ConstInt(c.uintptrType, num, false)) + argTypes = append(argTypes, c.uintptrType) + constraints += ",{x8}" // syscall number + for i := len(call.Args) - 1; i < 8; i++ { + // x0-x7 may get clobbered during the syscall following the aarch64 + // calling convention. + constraints += ",~{x" + strconv.Itoa(i) + "}" + } + constraints += ",~{x16},~{x17}" // scratch registers + fnType := llvm.FunctionType(c.uintptrType, argTypes, false) + target := llvm.InlineAsm(fnType, "svc #0", constraints, true, false, 0) + syscallResult = c.builder.CreateCall(target, args, "") default: return llvm.Value{}, c.makeError(call.Pos(), "unknown GOOS/GOARCH for syscall: "+c.GOOS+"/"+c.GOARCH) } diff --git a/main_test.go b/main_test.go index 2882c227..f1e164d8 100644 --- a/main_test.go +++ b/main_test.go @@ -63,6 +63,16 @@ func TestCompiler(t *testing.T) { }) } + t.Log("running tests for linux/arm64...") + for _, path := range matches { + if path == "testdata/cgo/" { + continue // TODO: improve CGo + } + t.Run(path, func(t *testing.T) { + runTest(path, tmpdir, "aarch64--linux-gnueabi", t) + }) + } + t.Log("running tests for emulated cortex-m3...") for _, path := range matches { t.Run(path, func(t *testing.T) { diff --git a/target.go b/target.go index 141be076..a85e6561 100644 --- a/target.go +++ b/target.go @@ -224,10 +224,11 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) { spec.GDB = "arm-linux-gnueabi-gdb" spec.Emulator = []string{"qemu-arm", "-L", "/usr/arm-linux-gnueabi"} } - if goarch == "arm64" { + if goarch == "arm64" && goos == "linux" { spec.Linker = "aarch64-linux-gnu-gcc" spec.Objcopy = "aarch64-linux-gnu-objcopy" spec.GDB = "aarch64-linux-gnu-gdb" + spec.Emulator = []string{"qemu-aarch64", "-L", "/usr/aarch64-linux-gnu"} } if goarch == "386" { spec.CFlags = []string{"-m32"}