hotfix: duplicated definition of symbol dlopen on go1.23.9

This commit is contained in:
naison
2025-05-09 04:23:25 +00:00
parent 1f4698c6f8
commit e21fc8cda9
48 changed files with 432 additions and 135 deletions

2
go.mod
View File

@@ -161,7 +161,7 @@ require (
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 // indirect github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect github.com/dustin/go-humanize v1.0.1 // indirect
github.com/eapache/queue/v2 v2.0.0-20230407133247-75960ed334e4 // indirect github.com/eapache/queue/v2 v2.0.0-20230407133247-75960ed334e4 // indirect
github.com/ebitengine/purego v0.8.2 // indirect github.com/ebitengine/purego v0.9.0-alpha.3.0.20250507171635-5047c08daa38 // indirect
github.com/emicklei/go-restful/v3 v3.12.2 // indirect github.com/emicklei/go-restful/v3 v3.12.2 // indirect
github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 // indirect github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 // indirect
github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect

4
go.sum
View File

@@ -265,8 +265,8 @@ github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+m
github.com/dvsekhvalnov/jose2go v0.0.0-20170216131308-f21a8cedbbae/go.mod h1:7BvyPhdbLxMXIYTFPLsyJRFMsKmOZnQmzh6Gb+uquuM= github.com/dvsekhvalnov/jose2go v0.0.0-20170216131308-f21a8cedbbae/go.mod h1:7BvyPhdbLxMXIYTFPLsyJRFMsKmOZnQmzh6Gb+uquuM=
github.com/eapache/queue/v2 v2.0.0-20230407133247-75960ed334e4 h1:8EXxF+tCLqaVk8AOC29zl2mnhQjwyLxxOTuhUazWRsg= github.com/eapache/queue/v2 v2.0.0-20230407133247-75960ed334e4 h1:8EXxF+tCLqaVk8AOC29zl2mnhQjwyLxxOTuhUazWRsg=
github.com/eapache/queue/v2 v2.0.0-20230407133247-75960ed334e4/go.mod h1:I5sHm0Y0T1u5YjlyqC5GVArM7aNZRUYtTjmJ8mPJFds= github.com/eapache/queue/v2 v2.0.0-20230407133247-75960ed334e4/go.mod h1:I5sHm0Y0T1u5YjlyqC5GVArM7aNZRUYtTjmJ8mPJFds=
github.com/ebitengine/purego v0.8.2 h1:jPPGWs2sZ1UgOSgD2bClL0MJIqu58nOmIcBuXr62z1I= github.com/ebitengine/purego v0.9.0-alpha.3.0.20250507171635-5047c08daa38 h1:61WY14WhyU89bEJCjegpt6b8wDNsU+Z1416JGwfEKwI=
github.com/ebitengine/purego v0.8.2/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/ebitengine/purego v0.9.0-alpha.3.0.20250507171635-5047c08daa38/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU= github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU=
github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/envoyproxy/go-control-plane v0.13.4 h1:zEqyPVyku6IvWCFwux4x9RxkLOMUL+1vC9xUFv5l2/M= github.com/envoyproxy/go-control-plane v0.13.4 h1:zEqyPVyku6IvWCFwux4x9RxkLOMUL+1vC9xUFv5l2/M=

View File

@@ -36,7 +36,7 @@ except for float arguments and return values.
## Example ## Example
The example below only showcases purego use for macOS and Linux. The other platforms require special handling which can The example below only showcases purego use for macOS and Linux. The other platforms require special handling which can
be seen in the complete example at [examples/libc](https://github.com/ebitengine/purego/tree/main/examples/libc) which supports Windows and FreeBSD. be seen in the complete example at [examples/libc](https://github.com/ebitengine/purego/tree/main/examples/libc) which supports FreeBSD and Windows.
```go ```go
package main package main
@@ -92,6 +92,7 @@ This is a list of the copied files:
* `internal/fakecgo/iscgo.go` from package `runtime/cgo` * `internal/fakecgo/iscgo.go` from package `runtime/cgo`
* `internal/fakecgo/setenv.go` from package `runtime/cgo` * `internal/fakecgo/setenv.go` from package `runtime/cgo`
* `internal/fakecgo/freebsd.go` from package `runtime/cgo` * `internal/fakecgo/freebsd.go` from package `runtime/cgo`
* `internal/fakecgo/netbsd.go` from package `runtime/cgo`
The files `abi_*.h` and `internal/fakecgo/abi_*.h` are the same because Bazel does not support cross-package use of The files `abi_*.h` and `internal/fakecgo/abi_*.h` are the same because Bazel does not support cross-package use of
`#include` so we need each one once per package. (cf. [issue](https://github.com/bazelbuild/rules_go/issues/3636)) `#include` so we need each one once per package. (cf. [issue](https://github.com/bazelbuild/rules_go/issues/3636))

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build cgo && (darwin || freebsd || linux) //go:build cgo && (darwin || freebsd || linux || netbsd)
package purego package purego

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 The Ebitengine Authors // SPDX-FileCopyrightText: 2023 The Ebitengine Authors
//go:build darwin || freebsd || linux //go:build darwin || freebsd || linux || netbsd
package purego package purego

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build (darwin || freebsd || linux) && !android && !faketime //go:build (darwin || freebsd || linux || netbsd) && !android && !faketime
package purego package purego
@@ -83,17 +83,17 @@ func loadSymbol(handle uintptr, name string) (uintptr, error) {
// appear to work if you link directly to the C function on darwin arm64. // appear to work if you link directly to the C function on darwin arm64.
//go:linkname dlopen dlopen //go:linkname dlopen dlopen
var dlopen uintptr var dlopen uint8
var dlopenABI0 = uintptr(unsafe.Pointer(&dlopen)) var dlopenABI0 = uintptr(unsafe.Pointer(&dlopen))
//go:linkname dlsym dlsym //go:linkname dlsym dlsym
var dlsym uintptr var dlsym uint8
var dlsymABI0 = uintptr(unsafe.Pointer(&dlsym)) var dlsymABI0 = uintptr(unsafe.Pointer(&dlsym))
//go:linkname dlclose dlclose //go:linkname dlclose dlclose
var dlclose uintptr var dlclose uint8
var dlcloseABI0 = uintptr(unsafe.Pointer(&dlclose)) var dlcloseABI0 = uintptr(unsafe.Pointer(&dlclose))
//go:linkname dlerror dlerror //go:linkname dlerror dlerror
var dlerror uintptr var dlerror uint8
var dlerrorABI0 = uintptr(unsafe.Pointer(&dlerror)) var dlerrorABI0 = uintptr(unsafe.Pointer(&dlerror))

View File

@@ -17,8 +17,3 @@ const (
//go:cgo_import_dynamic purego_dlsym dlsym "/usr/lib/libSystem.B.dylib" //go:cgo_import_dynamic purego_dlsym dlsym "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic purego_dlerror dlerror "/usr/lib/libSystem.B.dylib" //go:cgo_import_dynamic purego_dlerror dlerror "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic purego_dlclose dlclose "/usr/lib/libSystem.B.dylib" //go:cgo_import_dynamic purego_dlclose dlclose "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic purego_dlopen dlopen "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic purego_dlsym dlsym "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic purego_dlerror dlerror "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic purego_dlclose dlclose "/usr/lib/libSystem.B.dylib"

15
vendor/github.com/ebitengine/purego/dlfcn_netbsd.go generated vendored Normal file
View File

@@ -0,0 +1,15 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2025 The Ebitengine Authors
package purego
// Source for constants: https://github.com/NetBSD/src/blob/trunk/include/dlfcn.h
const (
intSize = 32 << (^uint(0) >> 63) // 32 or 64
RTLD_DEFAULT = 1<<intSize - 2 // Pseudo-handle for dlsym so search for any loaded symbol
RTLD_LAZY = 0x00000001 // Relocations are performed at an implementation-dependent time.
RTLD_NOW = 0x00000002 // Relocations are performed when the object is loaded.
RTLD_LOCAL = 0x00000000 // All symbols are not made available for relocation processing by other modules.
RTLD_GLOBAL = 0x00000100 // All symbols are available for relocation processing of other modules.
)

View File

@@ -0,0 +1,9 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2025 The Ebitengine Authors
package purego
//go:cgo_import_dynamic purego_dlopen dlopen "libc.so"
//go:cgo_import_dynamic purego_dlsym dlsym "libc.so"
//go:cgo_import_dynamic purego_dlerror dlerror "libc.so"
//go:cgo_import_dynamic purego_dlclose dlclose "libc.so"

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build darwin || !cgo && (freebsd || linux) && !faketime //go:build darwin || !cgo && (freebsd || linux || netbsd) && !faketime
#include "textflag.h" #include "textflag.h"

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build darwin || freebsd || linux || windows //go:build darwin || freebsd || linux || netbsd || windows
package purego package purego
@@ -10,14 +10,20 @@ import (
"math" "math"
"reflect" "reflect"
"runtime" "runtime"
"strconv"
"sync"
"unsafe" "unsafe"
"github.com/ebitengine/purego/internal/strings" "github.com/ebitengine/purego/internal/strings"
) )
var thePool = sync.Pool{New: func() any {
return new(syscall15Args)
}}
// RegisterLibFunc is a wrapper around RegisterFunc that uses the C function returned from Dlsym(handle, name). // RegisterLibFunc is a wrapper around RegisterFunc that uses the C function returned from Dlsym(handle, name).
// It panics if it can't find the name symbol. // It panics if it can't find the name symbol.
func RegisterLibFunc(fptr interface{}, handle uintptr, name string) { func RegisterLibFunc(fptr any, handle uintptr, name string) {
sym, err := loadSymbol(handle, name) sym, err := loadSymbol(handle, name)
if err != nil { if err != nil {
panic(err) panic(err)
@@ -60,7 +66,7 @@ func RegisterLibFunc(fptr interface{}, handle uintptr, name string) {
// //
// There is a special case when the last argument of fptr is a variadic interface (or []interface} // There is a special case when the last argument of fptr is a variadic interface (or []interface}
// it will be expanded into a call to the C function as if it had the arguments in that slice. // it will be expanded into a call to the C function as if it had the arguments in that slice.
// This means that using arg ...interface{} is like a cast to the function with the arguments inside arg. // This means that using arg ...any is like a cast to the function with the arguments inside arg.
// This is not the same as C variadic. // This is not the same as C variadic.
// //
// # Memory // # Memory
@@ -105,7 +111,7 @@ func RegisterLibFunc(fptr interface{}, handle uintptr, name string) {
// defer free(mustFree) // defer free(mustFree)
// //
// [Cgo rules]: https://pkg.go.dev/cmd/cgo#hdr-Go_references_to_C // [Cgo rules]: https://pkg.go.dev/cmd/cgo#hdr-Go_references_to_C
func RegisterFunc(fptr interface{}, cfn uintptr) { func RegisterFunc(fptr any, cfn uintptr) {
fn := reflect.ValueOf(fptr).Elem() fn := reflect.ValueOf(fptr).Elem()
ty := fn.Type() ty := fn.Type()
if ty.Kind() != reflect.Func { if ty.Kind() != reflect.Func {
@@ -156,7 +162,7 @@ func RegisterFunc(fptr interface{}, cfn uintptr) {
if is32bit { if is32bit {
panic("purego: floats only supported on 64bit platforms") panic("purego: floats only supported on 64bit platforms")
} }
if floats < numOfFloats { if floats < numOfFloatRegisters {
floats++ floats++
} else { } else {
stack++ stack++
@@ -200,21 +206,8 @@ func RegisterFunc(fptr interface{}, cfn uintptr) {
} }
} }
v := reflect.MakeFunc(ty, func(args []reflect.Value) (results []reflect.Value) { v := reflect.MakeFunc(ty, func(args []reflect.Value) (results []reflect.Value) {
if len(args) > 0 {
if variadic, ok := args[len(args)-1].Interface().([]interface{}); ok {
// subtract one from args bc the last argument in args is []interface{}
// which we are currently expanding
tmp := make([]reflect.Value, len(args)-1+len(variadic))
n := copy(tmp, args[:len(args)-1])
for i, v := range variadic {
tmp[n+i] = reflect.ValueOf(v)
}
args = tmp
}
}
var sysargs [maxArgs]uintptr var sysargs [maxArgs]uintptr
stack := sysargs[numOfIntegerRegisters():] var floats [numOfFloatRegisters]uintptr
var floats [numOfFloats]uintptr
var numInts int var numInts int
var numFloats int var numFloats int
var numStack int var numStack int
@@ -222,7 +215,7 @@ func RegisterFunc(fptr interface{}, cfn uintptr) {
if runtime.GOARCH == "arm64" || runtime.GOOS != "windows" { if runtime.GOARCH == "arm64" || runtime.GOOS != "windows" {
// Windows arm64 uses the same calling convention as macOS and Linux // Windows arm64 uses the same calling convention as macOS and Linux
addStack = func(x uintptr) { addStack = func(x uintptr) {
stack[numStack] = x sysargs[numOfIntegerRegisters()+numStack] = x
numStack++ numStack++
} }
addInt = func(x uintptr) { addInt = func(x uintptr) {
@@ -255,12 +248,13 @@ func RegisterFunc(fptr interface{}, cfn uintptr) {
addFloat = addStack addFloat = addStack
} }
var keepAlive []interface{} var keepAlive []any
defer func() { defer func() {
runtime.KeepAlive(keepAlive) runtime.KeepAlive(keepAlive)
runtime.KeepAlive(args) runtime.KeepAlive(args)
}() }()
var syscall syscall15Args
var arm64_r8 uintptr
if ty.NumOut() == 1 && ty.Out(0).Kind() == reflect.Struct { if ty.NumOut() == 1 && ty.Out(0).Kind() == reflect.Struct {
outType := ty.Out(0) outType := ty.Out(0)
if runtime.GOARCH == "amd64" && outType.Size() > maxRegAllocStructSize { if runtime.GOARCH == "amd64" && outType.Size() > maxRegAllocStructSize {
@@ -272,53 +266,63 @@ func RegisterFunc(fptr interface{}, cfn uintptr) {
if !isAllFloats || numFields > 4 { if !isAllFloats || numFields > 4 {
val := reflect.New(outType) val := reflect.New(outType)
keepAlive = append(keepAlive, val) keepAlive = append(keepAlive, val)
syscall.arm64_r8 = val.Pointer() arm64_r8 = val.Pointer()
} }
} }
} }
for _, v := range args { for i, v := range args {
switch v.Kind() { if variadic, ok := args[i].Interface().([]any); ok {
case reflect.String: if i != len(args)-1 {
ptr := strings.CString(v.String()) panic("purego: can only expand last parameter")
keepAlive = append(keepAlive, ptr)
addInt(uintptr(unsafe.Pointer(ptr)))
case reflect.Uintptr, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
addInt(uintptr(v.Uint()))
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
addInt(uintptr(v.Int()))
case reflect.Ptr, reflect.UnsafePointer, reflect.Slice:
// There is no need to keepAlive this pointer separately because it is kept alive in the args variable
addInt(v.Pointer())
case reflect.Func:
addInt(NewCallback(v.Interface()))
case reflect.Bool:
if v.Bool() {
addInt(1)
} else {
addInt(0)
} }
case reflect.Float32: for _, x := range variadic {
addFloat(uintptr(math.Float32bits(float32(v.Float())))) keepAlive = addValue(reflect.ValueOf(x), keepAlive, addInt, addFloat, addStack, &numInts, &numFloats, &numStack)
case reflect.Float64: }
addFloat(uintptr(math.Float64bits(v.Float()))) continue
case reflect.Struct:
keepAlive = addStruct(v, &numInts, &numFloats, &numStack, addInt, addFloat, addStack, keepAlive)
default:
panic("purego: unsupported kind: " + v.Kind().String())
} }
if runtime.GOARCH == "arm64" && runtime.GOOS == "darwin" &&
(numInts >= numOfIntegerRegisters() || numFloats >= numOfFloatRegisters) && v.Kind() != reflect.Struct { // hit the stack
fields := make([]reflect.StructField, len(args[i:]))
for j, val := range args[i:] {
if val.Kind() == reflect.String {
ptr := strings.CString(v.String())
keepAlive = append(keepAlive, ptr)
val = reflect.ValueOf(ptr)
args[i+j] = val
}
fields[j] = reflect.StructField{
Name: "X" + strconv.Itoa(j),
Type: val.Type(),
}
}
structType := reflect.StructOf(fields)
structInstance := reflect.New(structType).Elem()
for j, val := range args[i:] {
structInstance.Field(j).Set(val)
}
placeRegisters(structInstance, addFloat, addInt)
break
}
keepAlive = addValue(v, keepAlive, addInt, addFloat, addStack, &numInts, &numFloats, &numStack)
} }
syscall := thePool.Get().(*syscall15Args)
defer thePool.Put(syscall)
if runtime.GOARCH == "arm64" || runtime.GOOS != "windows" { if runtime.GOARCH == "arm64" || runtime.GOOS != "windows" {
// Use the normal arm64 calling convention even on Windows // Use the normal arm64 calling convention even on Windows
syscall = syscall15Args{ *syscall = syscall15Args{
cfn, cfn,
sysargs[0], sysargs[1], sysargs[2], sysargs[3], sysargs[4], sysargs[5], sysargs[0], sysargs[1], sysargs[2], sysargs[3], sysargs[4], sysargs[5],
sysargs[6], sysargs[7], sysargs[8], sysargs[9], sysargs[10], sysargs[11], sysargs[6], sysargs[7], sysargs[8], sysargs[9], sysargs[10], sysargs[11],
sysargs[12], sysargs[13], sysargs[14], sysargs[12], sysargs[13], sysargs[14],
floats[0], floats[1], floats[2], floats[3], floats[4], floats[5], floats[6], floats[7], floats[0], floats[1], floats[2], floats[3], floats[4], floats[5], floats[6], floats[7],
syscall.arm64_r8, arm64_r8,
} }
runtime_cgocall(syscall15XABI0, unsafe.Pointer(&syscall)) runtime_cgocall(syscall15XABI0, unsafe.Pointer(syscall))
} else { } else {
*syscall = syscall15Args{}
// This is a fallback for Windows amd64, 386, and arm. Note this may not support floats // This is a fallback for Windows amd64, 386, and arm. Note this may not support floats
syscall.a1, syscall.a2, _ = syscall_syscall15X(cfn, sysargs[0], sysargs[1], sysargs[2], sysargs[3], sysargs[4], syscall.a1, syscall.a2, _ = syscall_syscall15X(cfn, sysargs[0], sysargs[1], sysargs[2], sysargs[3], sysargs[4],
sysargs[5], sysargs[6], sysargs[7], sysargs[8], sysargs[9], sysargs[10], sysargs[11], sysargs[5], sysargs[6], sysargs[7], sysargs[8], sysargs[9], sysargs[10], sysargs[11],
@@ -357,15 +361,54 @@ func RegisterFunc(fptr interface{}, cfn uintptr) {
// On 32bit platforms syscall.r2 is the upper part of a 64bit return. // On 32bit platforms syscall.r2 is the upper part of a 64bit return.
v.SetFloat(math.Float64frombits(uint64(syscall.f1))) v.SetFloat(math.Float64frombits(uint64(syscall.f1)))
case reflect.Struct: case reflect.Struct:
v = getStruct(outType, syscall) v = getStruct(outType, *syscall)
default: default:
panic("purego: unsupported return kind: " + outType.Kind().String()) panic("purego: unsupported return kind: " + outType.Kind().String())
} }
return []reflect.Value{v} if len(args) > 0 {
// reuse args slice instead of allocating one when possible
args[0] = v
return args[:1]
} else {
return []reflect.Value{v}
}
}) })
fn.Set(v) fn.Set(v)
} }
func addValue(v reflect.Value, keepAlive []any, addInt func(x uintptr), addFloat func(x uintptr), addStack func(x uintptr), numInts *int, numFloats *int, numStack *int) []any {
switch v.Kind() {
case reflect.String:
ptr := strings.CString(v.String())
keepAlive = append(keepAlive, ptr)
addInt(uintptr(unsafe.Pointer(ptr)))
case reflect.Uintptr, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
addInt(uintptr(v.Uint()))
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
addInt(uintptr(v.Int()))
case reflect.Ptr, reflect.UnsafePointer, reflect.Slice:
// There is no need to keepAlive this pointer separately because it is kept alive in the args variable
addInt(v.Pointer())
case reflect.Func:
addInt(NewCallback(v.Interface()))
case reflect.Bool:
if v.Bool() {
addInt(1)
} else {
addInt(0)
}
case reflect.Float32:
addFloat(uintptr(math.Float32bits(float32(v.Float()))))
case reflect.Float64:
addFloat(uintptr(math.Float64bits(v.Float())))
case reflect.Struct:
keepAlive = addStruct(v, numInts, numFloats, numStack, addInt, addFloat, addStack, keepAlive)
default:
panic("purego: unsupported kind: " + v.Kind().String())
}
return keepAlive
}
// maxRegAllocStructSize is the biggest a struct can be while still fitting in registers. // maxRegAllocStructSize is the biggest a struct can be while still fitting in registers.
// if it is bigger than this than enough space must be allocated on the heap and then passed into // if it is bigger than this than enough space must be allocated on the heap and then passed into
// the function as the first parameter on amd64 or in R8 on arm64. // the function as the first parameter on amd64 or in R8 on arm64.

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build darwin || freebsd || linux || windows //go:build darwin || freebsd || linux || netbsd || windows
package purego package purego

View File

@@ -1,12 +1,12 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2024 The Ebitengine Authors // SPDX-FileCopyrightText: 2024 The Ebitengine Authors
//go:build freebsd || linux //go:build freebsd || linux || netbsd
package cgo package cgo
/* /*
#cgo LDFLAGS: -ldl #cgo !netbsd LDFLAGS: -ldl
#include <dlfcn.h> #include <dlfcn.h>
#include <stdlib.h> #include <stdlib.h>

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build freebsd || (linux && !(arm64 || amd64)) //go:build freebsd || (linux && !(arm64 || amd64)) || netbsd
package cgo package cgo
@@ -9,7 +9,7 @@ package cgo
// because Cgo and assembly files can't be in the same package. // because Cgo and assembly files can't be in the same package.
/* /*
#cgo LDFLAGS: -ldl #cgo !netbsd LDFLAGS: -ldl
#include <stdint.h> #include <stdint.h>
#include <dlfcn.h> #include <dlfcn.h>

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build !cgo && (darwin || freebsd || linux) //go:build !cgo && (darwin || freebsd || linux || netbsd)
package fakecgo package fakecgo

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build !cgo && (darwin || freebsd || linux) //go:build !cgo && (darwin || freebsd || linux || netbsd)
// Package fakecgo implements the Cgo runtime (runtime/cgo) entirely in Go. // Package fakecgo implements the Cgo runtime (runtime/cgo) entirely in Go.
// This allows code that calls into C to function properly when CGO_ENABLED=0. // This allows code that calls into C to function properly when CGO_ENABLED=0.

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build !cgo && (darwin || freebsd || linux) //go:build !cgo && (darwin || freebsd || linux || netbsd)
package fakecgo package fakecgo

View File

@@ -0,0 +1,106 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !cgo && (amd64 || arm64)
package fakecgo
import "unsafe"
//go:nosplit
func _cgo_sys_thread_start(ts *ThreadStart) {
var attr pthread_attr_t
var ign, oset sigset_t
var p pthread_t
var size size_t
var err int
// fprintf(stderr, "runtime/cgo: _cgo_sys_thread_start: fn=%p, g=%p\n", ts->fn, ts->g); // debug
sigfillset(&ign)
pthread_sigmask(SIG_SETMASK, &ign, &oset)
pthread_attr_init(&attr)
pthread_attr_getstacksize(&attr, &size)
// Leave stacklo=0 and set stackhi=size; mstart will do the rest.
ts.g.stackhi = uintptr(size)
err = _cgo_try_pthread_create(&p, &attr, unsafe.Pointer(threadentry_trampolineABI0), ts)
pthread_sigmask(SIG_SETMASK, &oset, nil)
if err != 0 {
print("fakecgo: pthread_create failed: ")
println(err)
abort()
}
}
// threadentry_trampolineABI0 maps the C ABI to Go ABI then calls the Go function
//
//go:linkname x_threadentry_trampoline threadentry_trampoline
var x_threadentry_trampoline byte
var threadentry_trampolineABI0 = &x_threadentry_trampoline
//go:nosplit
func threadentry(v unsafe.Pointer) unsafe.Pointer {
var ss stack_t
ts := *(*ThreadStart)(v)
free(v)
// On NetBSD, a new thread inherits the signal stack of the
// creating thread. That confuses minit, so we remove that
// signal stack here before calling the regular mstart. It's
// a bit baroque to remove a signal stack here only to add one
// in minit, but it's a simple change that keeps NetBSD
// working like other OS's. At this point all signals are
// blocked, so there is no race.
ss.ss_flags = SS_DISABLE
sigaltstack(&ss, nil)
setg_trampoline(setg_func, uintptr(unsafe.Pointer(ts.g)))
// faking funcs in go is a bit a... involved - but the following works :)
fn := uintptr(unsafe.Pointer(&ts.fn))
(*(*func())(unsafe.Pointer(&fn)))()
return nil
}
// here we will store a pointer to the provided setg func
var setg_func uintptr
//go:nosplit
func x_cgo_init(g *G, setg uintptr) {
var size size_t
var attr *pthread_attr_t
/* The memory sanitizer distributed with versions of clang
before 3.8 has a bug: if you call mmap before malloc, mmap
may return an address that is later overwritten by the msan
library. Avoid this problem by forcing a call to malloc
here, before we ever call malloc.
This is only required for the memory sanitizer, so it's
unfortunate that we always run it. It should be possible
to remove this when we no longer care about versions of
clang before 3.8. The test for this is
misc/cgo/testsanitizers.
GCC works hard to eliminate a seemingly unnecessary call to
malloc, so we actually use the memory we allocate. */
setg_func = setg
attr = (*pthread_attr_t)(malloc(unsafe.Sizeof(*attr)))
if attr == nil {
println("fakecgo: malloc failed")
abort()
}
pthread_attr_init(attr)
pthread_attr_getstacksize(attr, &size)
// runtime/cgo uses __builtin_frame_address(0) instead of `uintptr(unsafe.Pointer(&size))`
// but this should be OK since we are taking the address of the first variable in this function.
g.stacklo = uintptr(unsafe.Pointer(&size)) - uintptr(size) + 4096
pthread_attr_destroy(attr)
free(unsafe.Pointer(attr))
}

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build !cgo && (darwin || freebsd || linux) //go:build !cgo && (darwin || freebsd || linux || netbsd)
package fakecgo package fakecgo

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build !cgo && (darwin || freebsd || linux) //go:build !cgo && (darwin || freebsd || linux || netbsd)
package fakecgo package fakecgo

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build !cgo && (darwin || freebsd || linux) //go:build !cgo && (darwin || freebsd || linux || netbsd)
// The runtime package contains an uninitialized definition // The runtime package contains an uninitialized definition
// for runtime·iscgo. Override it to tell the runtime we're here. // for runtime·iscgo. Override it to tell the runtime we're here.

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build !cgo && (darwin || freebsd || linux) //go:build !cgo && (darwin || freebsd || linux || netbsd)
package fakecgo package fakecgo

View File

@@ -20,3 +20,7 @@ var (
PTHREAD_COND_INITIALIZER = pthread_cond_t{sig: 0x3CB0B1BB} PTHREAD_COND_INITIALIZER = pthread_cond_t{sig: 0x3CB0B1BB}
PTHREAD_MUTEX_INITIALIZER = pthread_mutex_t{sig: 0x32AAABA7} PTHREAD_MUTEX_INITIALIZER = pthread_mutex_t{sig: 0x32AAABA7}
) )
type stack_t struct {
/* not implemented */
}

View File

@@ -14,3 +14,7 @@ var (
PTHREAD_COND_INITIALIZER = pthread_cond_t(0) PTHREAD_COND_INITIALIZER = pthread_cond_t(0)
PTHREAD_MUTEX_INITIALIZER = pthread_mutex_t(0) PTHREAD_MUTEX_INITIALIZER = pthread_mutex_t(0)
) )
type stack_t struct {
/* not implemented */
}

View File

@@ -14,3 +14,7 @@ var (
PTHREAD_COND_INITIALIZER = pthread_cond_t{} PTHREAD_COND_INITIALIZER = pthread_cond_t{}
PTHREAD_MUTEX_INITIALIZER = pthread_mutex_t{} PTHREAD_MUTEX_INITIALIZER = pthread_mutex_t{}
) )
type stack_t struct {
/* not implemented */
}

View File

@@ -0,0 +1,26 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2025 The Ebitengine Authors
//go:build !cgo
package fakecgo
type (
pthread_cond_t uintptr
pthread_mutex_t uintptr
)
var (
PTHREAD_COND_INITIALIZER = pthread_cond_t(0)
PTHREAD_MUTEX_INITIALIZER = pthread_mutex_t(0)
)
// Source: https://github.com/NetBSD/src/blob/613e27c65223fd2283b6ed679da1197e12f50e27/sys/compat/linux/arch/m68k/linux_signal.h#L133
type stack_t struct {
ss_sp uintptr
ss_flags int32
ss_size uintptr
}
// Source: https://github.com/NetBSD/src/blob/613e27c65223fd2283b6ed679da1197e12f50e27/sys/sys/signal.h#L261
const SS_DISABLE = 0x004

View File

@@ -0,0 +1,23 @@
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build netbsd
package fakecgo
import _ "unsafe" // for go:linkname
// Supply environ and __progname, because we don't
// link against the standard NetBSD crt0.o and the
// libc dynamic library needs them.
//go:linkname _environ environ
//go:linkname _progname __progname
//go:linkname ___ps_strings __ps_strings
var (
_environ uintptr
_progname uintptr
___ps_strings uintptr
)

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build !cgo && (darwin || freebsd || linux) //go:build !cgo && (darwin || freebsd || linux || netbsd)
package fakecgo package fakecgo

View File

@@ -3,7 +3,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build !cgo && (darwin || freebsd || linux) //go:build !cgo && (darwin || freebsd || linux || netbsd)
package fakecgo package fakecgo
@@ -55,6 +55,11 @@ func abort() {
call5(abortABI0, 0, 0, 0, 0, 0) call5(abortABI0, 0, 0, 0, 0, 0)
} }
//go:nosplit
func sigaltstack(ss *stack_t, old_ss *stack_t) int32 {
return int32(call5(sigaltstackABI0, uintptr(unsafe.Pointer(ss)), uintptr(unsafe.Pointer(old_ss)), 0, 0, 0))
}
//go:nosplit //go:nosplit
func pthread_attr_init(attr *pthread_attr_t) int32 { func pthread_attr_init(attr *pthread_attr_t) int32 {
return int32(call5(pthread_attr_initABI0, uintptr(unsafe.Pointer(attr)), 0, 0, 0, 0)) return int32(call5(pthread_attr_initABI0, uintptr(unsafe.Pointer(attr)), 0, 0, 0, 0))
@@ -121,81 +126,85 @@ func pthread_setspecific(key pthread_key_t, value unsafe.Pointer) int32 {
} }
//go:linkname _malloc _malloc //go:linkname _malloc _malloc
var _malloc uintptr var _malloc uint8
var mallocABI0 = uintptr(unsafe.Pointer(&_malloc)) var mallocABI0 = uintptr(unsafe.Pointer(&_malloc))
//go:linkname _free _free //go:linkname _free _free
var _free uintptr var _free uint8
var freeABI0 = uintptr(unsafe.Pointer(&_free)) var freeABI0 = uintptr(unsafe.Pointer(&_free))
//go:linkname _setenv _setenv //go:linkname _setenv _setenv
var _setenv uintptr var _setenv uint8
var setenvABI0 = uintptr(unsafe.Pointer(&_setenv)) var setenvABI0 = uintptr(unsafe.Pointer(&_setenv))
//go:linkname _unsetenv _unsetenv //go:linkname _unsetenv _unsetenv
var _unsetenv uintptr var _unsetenv uint8
var unsetenvABI0 = uintptr(unsafe.Pointer(&_unsetenv)) var unsetenvABI0 = uintptr(unsafe.Pointer(&_unsetenv))
//go:linkname _sigfillset _sigfillset //go:linkname _sigfillset _sigfillset
var _sigfillset uintptr var _sigfillset uint8
var sigfillsetABI0 = uintptr(unsafe.Pointer(&_sigfillset)) var sigfillsetABI0 = uintptr(unsafe.Pointer(&_sigfillset))
//go:linkname _nanosleep _nanosleep //go:linkname _nanosleep _nanosleep
var _nanosleep uintptr var _nanosleep uint8
var nanosleepABI0 = uintptr(unsafe.Pointer(&_nanosleep)) var nanosleepABI0 = uintptr(unsafe.Pointer(&_nanosleep))
//go:linkname _abort _abort //go:linkname _abort _abort
var _abort uintptr var _abort uint8
var abortABI0 = uintptr(unsafe.Pointer(&_abort)) var abortABI0 = uintptr(unsafe.Pointer(&_abort))
//go:linkname _sigaltstack _sigaltstack
var _sigaltstack uint8
var sigaltstackABI0 = uintptr(unsafe.Pointer(&_sigaltstack))
//go:linkname _pthread_attr_init _pthread_attr_init //go:linkname _pthread_attr_init _pthread_attr_init
var _pthread_attr_init uintptr var _pthread_attr_init uint8
var pthread_attr_initABI0 = uintptr(unsafe.Pointer(&_pthread_attr_init)) var pthread_attr_initABI0 = uintptr(unsafe.Pointer(&_pthread_attr_init))
//go:linkname _pthread_create _pthread_create //go:linkname _pthread_create _pthread_create
var _pthread_create uintptr var _pthread_create uint8
var pthread_createABI0 = uintptr(unsafe.Pointer(&_pthread_create)) var pthread_createABI0 = uintptr(unsafe.Pointer(&_pthread_create))
//go:linkname _pthread_detach _pthread_detach //go:linkname _pthread_detach _pthread_detach
var _pthread_detach uintptr var _pthread_detach uint8
var pthread_detachABI0 = uintptr(unsafe.Pointer(&_pthread_detach)) var pthread_detachABI0 = uintptr(unsafe.Pointer(&_pthread_detach))
//go:linkname _pthread_sigmask _pthread_sigmask //go:linkname _pthread_sigmask _pthread_sigmask
var _pthread_sigmask uintptr var _pthread_sigmask uint8
var pthread_sigmaskABI0 = uintptr(unsafe.Pointer(&_pthread_sigmask)) var pthread_sigmaskABI0 = uintptr(unsafe.Pointer(&_pthread_sigmask))
//go:linkname _pthread_self _pthread_self //go:linkname _pthread_self _pthread_self
var _pthread_self uintptr var _pthread_self uint8
var pthread_selfABI0 = uintptr(unsafe.Pointer(&_pthread_self)) var pthread_selfABI0 = uintptr(unsafe.Pointer(&_pthread_self))
//go:linkname _pthread_get_stacksize_np _pthread_get_stacksize_np //go:linkname _pthread_get_stacksize_np _pthread_get_stacksize_np
var _pthread_get_stacksize_np uintptr var _pthread_get_stacksize_np uint8
var pthread_get_stacksize_npABI0 = uintptr(unsafe.Pointer(&_pthread_get_stacksize_np)) var pthread_get_stacksize_npABI0 = uintptr(unsafe.Pointer(&_pthread_get_stacksize_np))
//go:linkname _pthread_attr_getstacksize _pthread_attr_getstacksize //go:linkname _pthread_attr_getstacksize _pthread_attr_getstacksize
var _pthread_attr_getstacksize uintptr var _pthread_attr_getstacksize uint8
var pthread_attr_getstacksizeABI0 = uintptr(unsafe.Pointer(&_pthread_attr_getstacksize)) var pthread_attr_getstacksizeABI0 = uintptr(unsafe.Pointer(&_pthread_attr_getstacksize))
//go:linkname _pthread_attr_setstacksize _pthread_attr_setstacksize //go:linkname _pthread_attr_setstacksize _pthread_attr_setstacksize
var _pthread_attr_setstacksize uintptr var _pthread_attr_setstacksize uint8
var pthread_attr_setstacksizeABI0 = uintptr(unsafe.Pointer(&_pthread_attr_setstacksize)) var pthread_attr_setstacksizeABI0 = uintptr(unsafe.Pointer(&_pthread_attr_setstacksize))
//go:linkname _pthread_attr_destroy _pthread_attr_destroy //go:linkname _pthread_attr_destroy _pthread_attr_destroy
var _pthread_attr_destroy uintptr var _pthread_attr_destroy uint8
var pthread_attr_destroyABI0 = uintptr(unsafe.Pointer(&_pthread_attr_destroy)) var pthread_attr_destroyABI0 = uintptr(unsafe.Pointer(&_pthread_attr_destroy))
//go:linkname _pthread_mutex_lock _pthread_mutex_lock //go:linkname _pthread_mutex_lock _pthread_mutex_lock
var _pthread_mutex_lock uintptr var _pthread_mutex_lock uint8
var pthread_mutex_lockABI0 = uintptr(unsafe.Pointer(&_pthread_mutex_lock)) var pthread_mutex_lockABI0 = uintptr(unsafe.Pointer(&_pthread_mutex_lock))
//go:linkname _pthread_mutex_unlock _pthread_mutex_unlock //go:linkname _pthread_mutex_unlock _pthread_mutex_unlock
var _pthread_mutex_unlock uintptr var _pthread_mutex_unlock uint8
var pthread_mutex_unlockABI0 = uintptr(unsafe.Pointer(&_pthread_mutex_unlock)) var pthread_mutex_unlockABI0 = uintptr(unsafe.Pointer(&_pthread_mutex_unlock))
//go:linkname _pthread_cond_broadcast _pthread_cond_broadcast //go:linkname _pthread_cond_broadcast _pthread_cond_broadcast
var _pthread_cond_broadcast uintptr var _pthread_cond_broadcast uint8
var pthread_cond_broadcastABI0 = uintptr(unsafe.Pointer(&_pthread_cond_broadcast)) var pthread_cond_broadcastABI0 = uintptr(unsafe.Pointer(&_pthread_cond_broadcast))
//go:linkname _pthread_setspecific _pthread_setspecific //go:linkname _pthread_setspecific _pthread_setspecific
var _pthread_setspecific uintptr var _pthread_setspecific uint8
var pthread_setspecificABI0 = uintptr(unsafe.Pointer(&_pthread_setspecific)) var pthread_setspecificABI0 = uintptr(unsafe.Pointer(&_pthread_setspecific))

View File

@@ -14,6 +14,7 @@ package fakecgo
//go:cgo_import_dynamic purego_sigfillset sigfillset "/usr/lib/libSystem.B.dylib" //go:cgo_import_dynamic purego_sigfillset sigfillset "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic purego_nanosleep nanosleep "/usr/lib/libSystem.B.dylib" //go:cgo_import_dynamic purego_nanosleep nanosleep "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic purego_abort abort "/usr/lib/libSystem.B.dylib" //go:cgo_import_dynamic purego_abort abort "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic purego_sigaltstack sigaltstack "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic purego_pthread_attr_init pthread_attr_init "/usr/lib/libSystem.B.dylib" //go:cgo_import_dynamic purego_pthread_attr_init pthread_attr_init "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic purego_pthread_create pthread_create "/usr/lib/libSystem.B.dylib" //go:cgo_import_dynamic purego_pthread_create pthread_create "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic purego_pthread_detach pthread_detach "/usr/lib/libSystem.B.dylib" //go:cgo_import_dynamic purego_pthread_detach pthread_detach "/usr/lib/libSystem.B.dylib"

View File

@@ -14,6 +14,7 @@ package fakecgo
//go:cgo_import_dynamic purego_sigfillset sigfillset "libc.so.7" //go:cgo_import_dynamic purego_sigfillset sigfillset "libc.so.7"
//go:cgo_import_dynamic purego_nanosleep nanosleep "libc.so.7" //go:cgo_import_dynamic purego_nanosleep nanosleep "libc.so.7"
//go:cgo_import_dynamic purego_abort abort "libc.so.7" //go:cgo_import_dynamic purego_abort abort "libc.so.7"
//go:cgo_import_dynamic purego_sigaltstack sigaltstack "libc.so.7"
//go:cgo_import_dynamic purego_pthread_attr_init pthread_attr_init "libpthread.so" //go:cgo_import_dynamic purego_pthread_attr_init pthread_attr_init "libpthread.so"
//go:cgo_import_dynamic purego_pthread_create pthread_create "libpthread.so" //go:cgo_import_dynamic purego_pthread_create pthread_create "libpthread.so"
//go:cgo_import_dynamic purego_pthread_detach pthread_detach "libpthread.so" //go:cgo_import_dynamic purego_pthread_detach pthread_detach "libpthread.so"

View File

@@ -14,6 +14,7 @@ package fakecgo
//go:cgo_import_dynamic purego_sigfillset sigfillset "libc.so.6" //go:cgo_import_dynamic purego_sigfillset sigfillset "libc.so.6"
//go:cgo_import_dynamic purego_nanosleep nanosleep "libc.so.6" //go:cgo_import_dynamic purego_nanosleep nanosleep "libc.so.6"
//go:cgo_import_dynamic purego_abort abort "libc.so.6" //go:cgo_import_dynamic purego_abort abort "libc.so.6"
//go:cgo_import_dynamic purego_sigaltstack sigaltstack "libc.so.6"
//go:cgo_import_dynamic purego_pthread_attr_init pthread_attr_init "libpthread.so.0" //go:cgo_import_dynamic purego_pthread_attr_init pthread_attr_init "libpthread.so.0"
//go:cgo_import_dynamic purego_pthread_create pthread_create "libpthread.so.0" //go:cgo_import_dynamic purego_pthread_create pthread_create "libpthread.so.0"
//go:cgo_import_dynamic purego_pthread_detach pthread_detach "libpthread.so.0" //go:cgo_import_dynamic purego_pthread_detach pthread_detach "libpthread.so.0"

View File

@@ -0,0 +1,30 @@
// Code generated by 'go generate' with gen.go. DO NOT EDIT.
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build !cgo
package fakecgo
//go:cgo_import_dynamic purego_malloc malloc "libc.so"
//go:cgo_import_dynamic purego_free free "libc.so"
//go:cgo_import_dynamic purego_setenv setenv "libc.so"
//go:cgo_import_dynamic purego_unsetenv unsetenv "libc.so"
//go:cgo_import_dynamic purego_sigfillset sigfillset "libc.so"
//go:cgo_import_dynamic purego_nanosleep nanosleep "libc.so"
//go:cgo_import_dynamic purego_abort abort "libc.so"
//go:cgo_import_dynamic purego_sigaltstack sigaltstack "libc.so"
//go:cgo_import_dynamic purego_pthread_attr_init pthread_attr_init "libpthread.so"
//go:cgo_import_dynamic purego_pthread_create pthread_create "libpthread.so"
//go:cgo_import_dynamic purego_pthread_detach pthread_detach "libpthread.so"
//go:cgo_import_dynamic purego_pthread_sigmask pthread_sigmask "libpthread.so"
//go:cgo_import_dynamic purego_pthread_self pthread_self "libpthread.so"
//go:cgo_import_dynamic purego_pthread_get_stacksize_np pthread_get_stacksize_np "libpthread.so"
//go:cgo_import_dynamic purego_pthread_attr_getstacksize pthread_attr_getstacksize "libpthread.so"
//go:cgo_import_dynamic purego_pthread_attr_setstacksize pthread_attr_setstacksize "libpthread.so"
//go:cgo_import_dynamic purego_pthread_attr_destroy pthread_attr_destroy "libpthread.so"
//go:cgo_import_dynamic purego_pthread_mutex_lock pthread_mutex_lock "libpthread.so"
//go:cgo_import_dynamic purego_pthread_mutex_unlock pthread_mutex_unlock "libpthread.so"
//go:cgo_import_dynamic purego_pthread_cond_broadcast pthread_cond_broadcast "libpthread.so"
//go:cgo_import_dynamic purego_pthread_setspecific pthread_setspecific "libpthread.so"

View File

@@ -3,7 +3,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build !cgo && (darwin || freebsd || linux) //go:build !cgo && (darwin || freebsd || linux || netbsd)
#include "textflag.h" #include "textflag.h"
@@ -37,6 +37,10 @@ TEXT _abort(SB), NOSPLIT|NOFRAME, $0-0
JMP purego_abort(SB) JMP purego_abort(SB)
RET RET
TEXT _sigaltstack(SB), NOSPLIT|NOFRAME, $0-0
JMP purego_sigaltstack(SB)
RET
TEXT _pthread_attr_init(SB), NOSPLIT|NOFRAME, $0-0 TEXT _pthread_attr_init(SB), NOSPLIT|NOFRAME, $0-0
JMP purego_pthread_attr_init(SB) JMP purego_pthread_attr_init(SB)
RET RET

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build !cgo && (darwin || freebsd || linux) //go:build !cgo && (darwin || freebsd || linux || netbsd)
package purego package purego

View File

@@ -85,7 +85,7 @@ const (
_MEMORY = 0b1111 _MEMORY = 0b1111
) )
func addStruct(v reflect.Value, numInts, numFloats, numStack *int, addInt, addFloat, addStack func(uintptr), keepAlive []interface{}) []interface{} { func addStruct(v reflect.Value, numInts, numFloats, numStack *int, addInt, addFloat, addStack func(uintptr), keepAlive []any) []any {
if v.Type().Size() == 0 { if v.Type().Size() == 0 {
return keepAlive return keepAlive
} }
@@ -120,7 +120,7 @@ func postMerger(t reflect.Type) (passInMemory bool) {
if t.Size() <= 2*8 { if t.Size() <= 2*8 {
return false return false
} }
return true // Go does not have an SSE/SEEUP type so this is always true return true // Go does not have an SSE/SSEUP type so this is always true
} }
func tryPlaceRegister(v reflect.Value, addFloat func(uintptr), addInt func(uintptr)) (ok bool) { func tryPlaceRegister(v reflect.Value, addFloat func(uintptr), addInt func(uintptr)) (ok bool) {
@@ -258,3 +258,7 @@ func placeStack(v reflect.Value, addStack func(uintptr)) {
} }
} }
} }
func placeRegisters(v reflect.Value, addFloat func(uintptr), addInt func(uintptr)) {
panic("purego: not needed on amd64")
}

View File

@@ -65,7 +65,7 @@ const (
_INT = 0b11 _INT = 0b11
) )
func addStruct(v reflect.Value, numInts, numFloats, numStack *int, addInt, addFloat, addStack func(uintptr), keepAlive []interface{}) []interface{} { func addStruct(v reflect.Value, numInts, numFloats, numStack *int, addInt, addFloat, addStack func(uintptr), keepAlive []any) []any {
if v.Type().Size() == 0 { if v.Type().Size() == 0 {
return keepAlive return keepAlive
} }
@@ -73,8 +73,8 @@ func addStruct(v reflect.Value, numInts, numFloats, numStack *int, addInt, addFl
if hva, hfa, size := isHVA(v.Type()), isHFA(v.Type()), v.Type().Size(); hva || hfa || size <= 16 { if hva, hfa, size := isHVA(v.Type()), isHFA(v.Type()), v.Type().Size(); hva || hfa || size <= 16 {
// if this doesn't fit entirely in registers then // if this doesn't fit entirely in registers then
// each element goes onto the stack // each element goes onto the stack
if hfa && *numFloats+v.NumField() > numOfFloats { if hfa && *numFloats+v.NumField() > numOfFloatRegisters {
*numFloats = numOfFloats *numFloats = numOfFloatRegisters
} else if hva && *numInts+v.NumField() > numOfIntegerRegisters() { } else if hva && *numInts+v.NumField() > numOfIntegerRegisters() {
*numInts = numOfIntegerRegisters() *numInts = numOfIntegerRegisters()
} }
@@ -107,6 +107,8 @@ func placeRegisters(v reflect.Value, addFloat func(uintptr), addInt func(uintptr
} else { } else {
f = v.Index(k) f = v.Index(k)
} }
align := byte(f.Type().Align()*8 - 1)
shift = (shift + align) &^ align
if shift >= 64 { if shift >= 64 {
shift = 0 shift = 0
flushed = true flushed = true
@@ -137,10 +139,11 @@ func placeRegisters(v reflect.Value, addFloat func(uintptr), addInt func(uintptr
val |= f.Uint() << shift val |= f.Uint() << shift
shift += 32 shift += 32
class |= _INT class |= _INT
case reflect.Uint64: case reflect.Uint64, reflect.Uint, reflect.Uintptr:
addInt(uintptr(f.Uint())) addInt(uintptr(f.Uint()))
shift = 0 shift = 0
flushed = true flushed = true
class = _NO_CLASS
case reflect.Int8: case reflect.Int8:
val |= uint64(f.Int()&0xFF) << shift val |= uint64(f.Int()&0xFF) << shift
shift += 8 shift += 8
@@ -153,10 +156,11 @@ func placeRegisters(v reflect.Value, addFloat func(uintptr), addInt func(uintptr
val |= uint64(f.Int()&0xFFFF_FFFF) << shift val |= uint64(f.Int()&0xFFFF_FFFF) << shift
shift += 32 shift += 32
class |= _INT class |= _INT
case reflect.Int64: case reflect.Int64, reflect.Int:
addInt(uintptr(f.Int())) addInt(uintptr(f.Int()))
shift = 0 shift = 0
flushed = true flushed = true
class = _NO_CLASS
case reflect.Float32: case reflect.Float32:
if class == _FLOAT { if class == _FLOAT {
addFloat(uintptr(val)) addFloat(uintptr(val))
@@ -170,6 +174,12 @@ func placeRegisters(v reflect.Value, addFloat func(uintptr), addInt func(uintptr
addFloat(uintptr(math.Float64bits(float64(f.Float())))) addFloat(uintptr(math.Float64bits(float64(f.Float()))))
shift = 0 shift = 0
flushed = true flushed = true
class = _NO_CLASS
case reflect.Ptr:
addInt(f.Pointer())
shift = 0
flushed = true
class = _NO_CLASS
case reflect.Array: case reflect.Array:
place(f) place(f)
default: default:
@@ -187,7 +197,7 @@ func placeRegisters(v reflect.Value, addFloat func(uintptr), addInt func(uintptr
} }
} }
func placeStack(v reflect.Value, keepAlive []interface{}, addInt func(uintptr)) []interface{} { func placeStack(v reflect.Value, keepAlive []any, addInt func(uintptr)) []any {
// Struct is too big to be placed in registers. // Struct is too big to be placed in registers.
// Copy to heap and place the pointer in register // Copy to heap and place the pointer in register
ptrStruct := reflect.New(v.Type()) ptrStruct := reflect.New(v.Type())

View File

@@ -7,10 +7,14 @@ package purego
import "reflect" import "reflect"
func addStruct(v reflect.Value, numInts, numFloats, numStack *int, addInt, addFloat, addStack func(uintptr), keepAlive []interface{}) []interface{} { func addStruct(v reflect.Value, numInts, numFloats, numStack *int, addInt, addFloat, addStack func(uintptr), keepAlive []any) []any {
panic("purego: struct arguments are not supported") panic("purego: struct arguments are not supported")
} }
func getStruct(outType reflect.Type, syscall syscall15Args) (v reflect.Value) { func getStruct(outType reflect.Type, syscall syscall15Args) (v reflect.Value) {
panic("purego: struct returns are not supported") panic("purego: struct returns are not supported")
} }
func placeRegisters(v reflect.Value, addFloat func(uintptr), addInt func(uintptr)) {
panic("purego: not needed on other platforms")
}

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build darwin || freebsd || linux //go:build darwin || freebsd || linux || netbsd
#include "textflag.h" #include "textflag.h"
#include "abi_amd64.h" #include "abi_amd64.h"

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build darwin || freebsd || linux || windows //go:build darwin || freebsd || linux || netbsd || windows
#include "textflag.h" #include "textflag.h"
#include "go_asm.h" #include "go_asm.h"

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 The Ebitengine Authors // SPDX-FileCopyrightText: 2023 The Ebitengine Authors
//go:build darwin || freebsd || linux //go:build darwin || freebsd || linux || netbsd
#include "textflag.h" #include "textflag.h"
#include "go_asm.h" #include "go_asm.h"

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build darwin || freebsd || linux || windows //go:build darwin || freebsd || linux || netbsd || windows
package purego package purego
@@ -13,8 +13,8 @@ package purego
type CDecl struct{} type CDecl struct{}
const ( const (
maxArgs = 15 maxArgs = 15
numOfFloats = 8 // arm64 and amd64 both have 8 float registers numOfFloatRegisters = 8 // arm64 and amd64 both have 8 float registers
) )
type syscall15Args struct { type syscall15Args struct {
@@ -27,6 +27,9 @@ type syscall15Args struct {
// There is an internal maximum number of arguments that SyscallN can take. It panics // There is an internal maximum number of arguments that SyscallN can take. It panics
// when the maximum is exceeded. It returns the result and the libc error code if there is one. // when the maximum is exceeded. It returns the result and the libc error code if there is one.
// //
// In order to call this function properly make sure to follow all the rules specified in [unsafe.Pointer]
// especially point 4.
//
// NOTE: SyscallN does not properly call functions that have both integer and float parameters. // NOTE: SyscallN does not properly call functions that have both integer and float parameters.
// See discussion comment https://github.com/ebiten/purego/pull/1#issuecomment-1128057607 // See discussion comment https://github.com/ebiten/purego/pull/1#issuecomment-1128057607
// for an explanation of why that is. // for an explanation of why that is.

View File

@@ -16,6 +16,6 @@ func syscall_syscall15X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a
return cgo.Syscall15X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15) return cgo.Syscall15X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15)
} }
func NewCallback(_ interface{}) uintptr { func NewCallback(_ any) uintptr {
panic("purego: NewCallback on Linux is only supported on amd64/arm64") panic("purego: NewCallback on Linux is only supported on amd64/arm64")
} }

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build darwin || freebsd || (linux && (amd64 || arm64)) //go:build darwin || freebsd || (linux && (amd64 || arm64)) || netbsd
package purego package purego
@@ -31,7 +31,7 @@ func syscall_syscall15X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a
// of uintptr. Only a limited number of callbacks may be created in a single Go process, and any memory allocated // of uintptr. Only a limited number of callbacks may be created in a single Go process, and any memory allocated
// for these callbacks is never released. At least 2000 callbacks can always be created. Although this function // for these callbacks is never released. At least 2000 callbacks can always be created. Although this function
// provides similar functionality to windows.NewCallback it is distinct. // provides similar functionality to windows.NewCallback it is distinct.
func NewCallback(fn interface{}) uintptr { func NewCallback(fn any) uintptr {
ty := reflect.TypeOf(fn) ty := reflect.TypeOf(fn)
for i := 0; i < ty.NumIn(); i++ { for i := 0; i < ty.NumIn(); i++ {
in := ty.In(i) in := ty.In(i)
@@ -71,7 +71,7 @@ type callbackArgs struct {
result uintptr result uintptr
} }
func compileCallback(fn interface{}) uintptr { func compileCallback(fn any) uintptr {
val := reflect.ValueOf(fn) val := reflect.ValueOf(fn)
if val.Kind() != reflect.Func { if val.Kind() != reflect.Func {
panic("purego: the type must be a function but was not") panic("purego: the type must be a function but was not")
@@ -146,12 +146,12 @@ func callbackWrap(a *callbackArgs) {
var intsN int // intsN represents the number of integer arguments processed var intsN int // intsN represents the number of integer arguments processed
// stack points to the index into frame of the current stack element. // stack points to the index into frame of the current stack element.
// The stack begins after the float and integer registers. // The stack begins after the float and integer registers.
stack := numOfIntegerRegisters() + numOfFloats stack := numOfIntegerRegisters() + numOfFloatRegisters
for i := range args { for i := range args {
var pos int var pos int
switch fnType.In(i).Kind() { switch fnType.In(i).Kind() {
case reflect.Float32, reflect.Float64: case reflect.Float32, reflect.Float64:
if floatsN >= numOfFloats { if floatsN >= numOfFloatRegisters {
pos = stack pos = stack
stack++ stack++
} else { } else {
@@ -169,7 +169,7 @@ func callbackWrap(a *callbackArgs) {
stack++ stack++
} else { } else {
// the integers begin after the floats in frame // the integers begin after the floats in frame
pos = intsN + numOfFloats pos = intsN + numOfFloatRegisters
} }
intsN++ intsN++
} }

View File

@@ -22,7 +22,7 @@ func syscall_syscall15X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a
// allocated for these callbacks is never released. Between NewCallback and NewCallbackCDecl, at least 1024 // allocated for these callbacks is never released. Between NewCallback and NewCallbackCDecl, at least 1024
// callbacks can always be created. Although this function is similiar to the darwin version it may act // callbacks can always be created. Although this function is similiar to the darwin version it may act
// differently. // differently.
func NewCallback(fn interface{}) uintptr { func NewCallback(fn any) uintptr {
isCDecl := false isCDecl := false
ty := reflect.TypeOf(fn) ty := reflect.TypeOf(fn)
for i := 0; i < ty.NumIn(); i++ { for i := 0; i < ty.NumIn(); i++ {

View File

@@ -1,6 +1,6 @@
// Code generated by wincallback.go using 'go generate'. DO NOT EDIT. // Code generated by wincallback.go using 'go generate'. DO NOT EDIT.
//go:build darwin || freebsd || linux //go:build darwin || freebsd || linux || netbsd
// runtime·callbackasm is called by external code to // runtime·callbackasm is called by external code to
// execute Go implemented callback function. It is not // execute Go implemented callback function. It is not

View File

@@ -1,6 +1,6 @@
// Code generated by wincallback.go using 'go generate'. DO NOT EDIT. // Code generated by wincallback.go using 'go generate'. DO NOT EDIT.
//go:build darwin || freebsd || linux //go:build darwin || freebsd || linux || netbsd
// External code calls into callbackasm at an offset corresponding // External code calls into callbackasm at an offset corresponding
// to the callback index. Callbackasm is a table of MOV and B instructions. // to the callback index. Callbackasm is a table of MOV and B instructions.

2
vendor/modules.txt vendored
View File

@@ -673,7 +673,7 @@ github.com/dustin/go-humanize
# github.com/eapache/queue/v2 v2.0.0-20230407133247-75960ed334e4 # github.com/eapache/queue/v2 v2.0.0-20230407133247-75960ed334e4
## explicit; go 1.20 ## explicit; go 1.20
github.com/eapache/queue/v2 github.com/eapache/queue/v2
# github.com/ebitengine/purego v0.8.2 # github.com/ebitengine/purego v0.9.0-alpha.3.0.20250507171635-5047c08daa38
## explicit; go 1.18 ## explicit; go 1.18
github.com/ebitengine/purego github.com/ebitengine/purego
github.com/ebitengine/purego/internal/cgo github.com/ebitengine/purego/internal/cgo