darwin: replace custom syscall package with Go native syscall package

This required a few compiler and runtime tricks to work, but I ran a
bunch of tests and it seems fine. (CI will of course do more exhaustive
testing).

The main benefit here is that we don't need to maintain the darwin
version of the syscall package, and reduce extra risks for bugs (because
we reuse the well-tested syscall package). For example, Go 1.23 needed a
bunch of new constants in the syscall package. That would have been
avoided if we had used the native syscall package on MacOS.
This commit is contained in:
Ayke van Laethem
2024-08-18 19:33:04 +02:00
committed by Ron Evans
parent 753f4b38b4
commit 105fe9b25d
19 changed files with 229 additions and 531 deletions
+27 -2
View File
@@ -1,7 +1,32 @@
// Wrapper function because 'open' is a variadic function and variadic functions
// use a different (incompatible) calling convention on darwin/arm64.
//go:build none
// This file is included in the build, despite the //go:build line above.
#include <fcntl.h>
// Wrapper function because 'open' is a variadic function and variadic functions
// use a different (incompatible) calling convention on darwin/arm64.
// This function is referenced from the compiler, when it sees a
// syscall.libc_open_trampoline function.
int syscall_libc_open(const char *pathname, int flags, mode_t mode) {
return open(pathname, flags, mode);
}
// The following functions are called by the runtime because Go can't call
// function pointers directly.
int tinygo_syscall(int (*fn)(uintptr_t a1, uintptr_t a2, uintptr_t a3), uintptr_t a1, uintptr_t a2, uintptr_t a3) {
return fn(a1, a2, a3);
}
uintptr_t tinygo_syscallX(uintptr_t (*fn)(uintptr_t a1, uintptr_t a2, uintptr_t a3), uintptr_t a1, uintptr_t a2, uintptr_t a3) {
return fn(a1, a2, a3);
}
int tinygo_syscall6(int (*fn)(uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5, uintptr_t a6), uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5, uintptr_t a6) {
return fn(a1, a2, a3, a4, a5, a6);
}
uintptr_t tinygo_syscall6X(uintptr_t (*fn)(uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5, uintptr_t a6), uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5, uintptr_t a6) {
return fn(a1, a2, a3, a4, a5, a6);
}
+100 -2
View File
@@ -4,8 +4,6 @@ package runtime
import "unsafe"
import "C" // dummy import so that os_darwin.c works
const GOOS = "darwin"
const (
@@ -127,7 +125,107 @@ func hardwareRand() (n uint64, ok bool) {
return n, true
}
//go:linkname syscall_Getpagesize syscall.Getpagesize
func syscall_Getpagesize() int {
return int(libc_getpagesize())
}
// Call "system calls" (actually: libc functions) in a special way.
// - Most calls calls return a C int (which is 32-bits), and -1 on failure.
// - syscallX* is for functions that return a 64-bit integer (and also return
// -1 on failure).
// - syscallPtr is for functions that return a pointer on success or NULL on
// failure.
// - rawSyscall seems to avoid some stack modifications, which isn't relevant
// to TinyGo.
//go:linkname syscall_syscall syscall.syscall
func syscall_syscall(fn, a1, a2, a3 uintptr) (r1, r2, err uintptr) {
// For TinyGo we don't need to do anything special to call C functions.
return syscall_rawSyscall(fn, a1, a2, a3)
}
//go:linkname syscall_rawSyscall syscall.rawSyscall
func syscall_rawSyscall(fn, a1, a2, a3 uintptr) (r1, r2, err uintptr) {
result := call_syscall(fn, a1, a2, a3)
r1 = uintptr(result)
if result == -1 {
// Syscall returns -1 on failure.
err = uintptr(*libc___error())
}
return
}
//go:linkname syscall_syscallX syscall.syscallX
func syscall_syscallX(fn, a1, a2, a3 uintptr) (r1, r2, err uintptr) {
r1 = call_syscallX(fn, a1, a2, a3)
if int64(r1) == -1 {
// Syscall returns -1 on failure.
err = uintptr(*libc___error())
}
return
}
//go:linkname syscall_syscallPtr syscall.syscallPtr
func syscall_syscallPtr(fn, a1, a2, a3 uintptr) (r1, r2, err uintptr) {
r1 = call_syscallX(fn, a1, a2, a3)
if r1 == 0 {
// Syscall returns a pointer on success, or NULL on failure.
err = uintptr(*libc___error())
}
return
}
//go:linkname syscall_syscall6 syscall.syscall6
func syscall_syscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) {
result := call_syscall6(fn, a1, a2, a3, a4, a5, a6)
r1 = uintptr(result)
if result == -1 {
// Syscall returns -1 on failure.
err = uintptr(*libc___error())
}
return
}
//go:linkname syscall_syscall6X syscall.syscall6X
func syscall_syscall6X(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) {
r1 = call_syscall6X(fn, a1, a2, a3, a4, a5, a6)
if int64(r1) == -1 {
// Syscall returns -1 on failure.
err = uintptr(*libc___error())
}
return
}
// uint32_t arc4random(void);
//
//export arc4random
func libc_arc4random() uint32
// int getpagesize(void);
//
//export getpagesize
func libc_getpagesize() int32
// This function returns the error location in the darwin ABI.
// Discovered by compiling the following code using Clang:
//
// #include <errno.h>
// int getErrno() {
// return errno;
// }
//
//export __error
func libc___error() *int32
//export tinygo_syscall
func call_syscall(fn, a1, a2, a3 uintptr) int32
//export tinygo_syscallX
func call_syscallX(fn, a1, a2, a3 uintptr) uintptr
//export tinygo_syscall6
func call_syscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) int32
//export tinygo_syscall6X
func call_syscall6X(fn, a1, a2, a3, a4, a5, a6 uintptr) uintptr