mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-11 06:23:39 +00:00
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:
committed by
Ron Evans
parent
753f4b38b4
commit
105fe9b25d
@@ -1847,7 +1847,9 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
|
||||
case strings.HasPrefix(name, "(device/riscv.CSR)."):
|
||||
return b.emitCSROperation(instr)
|
||||
case strings.HasPrefix(name, "syscall.Syscall") || strings.HasPrefix(name, "syscall.RawSyscall") || strings.HasPrefix(name, "golang.org/x/sys/unix.Syscall") || strings.HasPrefix(name, "golang.org/x/sys/unix.RawSyscall"):
|
||||
return b.createSyscall(instr)
|
||||
if b.GOOS != "darwin" {
|
||||
return b.createSyscall(instr)
|
||||
}
|
||||
case strings.HasPrefix(name, "syscall.rawSyscallNoError") || strings.HasPrefix(name, "golang.org/x/sys/unix.RawSyscallNoError"):
|
||||
return b.createRawSyscallNoError(instr)
|
||||
case name == "runtime.supportsRecover":
|
||||
@@ -1865,6 +1867,11 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
|
||||
return llvm.ConstInt(b.ctx.Int8Type(), panicStrategy, false), nil
|
||||
case name == "runtime/interrupt.New":
|
||||
return b.createInterruptGlobal(instr)
|
||||
case name == "internal/abi.FuncPCABI0":
|
||||
retval := b.createDarwinFuncPCABI0Call(instr)
|
||||
if !retval.IsNil() {
|
||||
return retval, nil
|
||||
}
|
||||
}
|
||||
|
||||
calleeType, callee = b.getFunction(fn)
|
||||
|
||||
@@ -5,6 +5,7 @@ package compiler
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/tools/go/ssa"
|
||||
"tinygo.org/x/go-llvm"
|
||||
@@ -329,3 +330,64 @@ func (b *builder) createRawSyscallNoError(call *ssa.CallCommon) (llvm.Value, err
|
||||
retval = b.CreateInsertValue(retval, llvm.ConstInt(b.uintptrType, 0, false), 1, "")
|
||||
return retval, nil
|
||||
}
|
||||
|
||||
// Lower a call to internal/abi.FuncPCABI0 on MacOS.
|
||||
// This function is called like this:
|
||||
//
|
||||
// syscall(abi.FuncPCABI0(libc_mkdir_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
|
||||
//
|
||||
// So we'll want to return a function pointer (as uintptr) that points to the
|
||||
// libc function. Specifically, we _don't_ want to point to the trampoline
|
||||
// function (which is implemented in Go assembly which we can't read), but
|
||||
// rather to the actually intended function. For this we're going to assume that
|
||||
// all the functions follow a specific pattern: libc_<functionname>_trampoline.
|
||||
//
|
||||
// The return value is the function pointer as an uintptr, or a nil value if
|
||||
// this isn't possible (and a regular call should be made as fallback).
|
||||
func (b *builder) createDarwinFuncPCABI0Call(instr *ssa.CallCommon) llvm.Value {
|
||||
if b.GOOS != "darwin" {
|
||||
// This has only been tested on MacOS (and only seems to be used there).
|
||||
return llvm.Value{}
|
||||
}
|
||||
|
||||
// Check that it uses a function call like syscall.libc_*_trampoline
|
||||
itf := instr.Args[0].(*ssa.MakeInterface)
|
||||
calledFn := itf.X.(*ssa.Function)
|
||||
if pkgName := calledFn.Pkg.Pkg.Path(); pkgName != "syscall" && pkgName != "internal/syscall/unix" {
|
||||
return llvm.Value{}
|
||||
}
|
||||
if !strings.HasPrefix(calledFn.Name(), "libc_") || !strings.HasSuffix(calledFn.Name(), "_trampoline") {
|
||||
|
||||
return llvm.Value{}
|
||||
}
|
||||
|
||||
// Extract the libc function name.
|
||||
name := strings.TrimPrefix(strings.TrimSuffix(calledFn.Name(), "_trampoline"), "libc_")
|
||||
if name == "open" {
|
||||
// Special case: open() is a variadic function and can't be called like
|
||||
// a regular function. Therefore, we need to use a wrapper implemented
|
||||
// in C.
|
||||
name = "syscall_libc_open"
|
||||
}
|
||||
if b.GOARCH == "amd64" {
|
||||
if name == "fdopendir" || name == "readdir_r" {
|
||||
// Hack to support amd64, which needs the $INODE64 suffix.
|
||||
// This is also done in upstream Go:
|
||||
// https://github.com/golang/go/commit/096ab3c21b88ccc7d411379d09fe6274e3159467
|
||||
name += "$INODE64"
|
||||
}
|
||||
}
|
||||
|
||||
// Obtain the C function.
|
||||
// Use a simple function (no parameters or return value) because all we need
|
||||
// is the address of the function.
|
||||
llvmFn := b.mod.NamedFunction(name)
|
||||
if llvmFn.IsNil() {
|
||||
llvmFnType := llvm.FunctionType(b.ctx.VoidType(), nil, false)
|
||||
llvmFn = llvm.AddFunction(b.mod, name, llvmFnType)
|
||||
}
|
||||
|
||||
// Cast the function pointer to a uintptr (because that's what
|
||||
// abi.FuncPCABI0 returns).
|
||||
return b.CreatePtrToInt(llvmFn, b.uintptrType, "")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user