purego: support string arguments in Go callbacks from C
- commit
- a7a757496003828984098b524cea737794202c53
- author
- brice · · 2026-04-15 03:32 UTC
- parent
- 3078bf4
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
1 file · +27 -1
M syscall_unix.go +27 -1
| @@ -11,6 +11,8 @@ import ( | |||
| 11 | 11 | "runtime" | |
| 12 | 12 | "sync" | |
| 13 | 13 | "unsafe" | |
| 14 | + | ||
| 15 | + | "github.com/bnema/purego/internal/strings" | |
| 14 | 16 | ) | |
| 15 | 17 | ||
| 16 | 18 | var syscall15XABI0 uintptr | |
| @@ -82,7 +84,7 @@ func compileCallback(fn any) uintptr { | |||
| 82 | 84 | continue | |
| 83 | 85 | case reflect.Interface, reflect.Func, reflect.Slice, | |
| 84 | 86 | reflect.Chan, reflect.Complex64, reflect.Complex128, | |
| 85 | - | reflect.String, reflect.Map, reflect.Invalid: | |
| 87 | + | reflect.Map, reflect.Invalid: | |
| 86 | 88 | panic("purego: unsupported argument type: " + in.Kind().String()) | |
| 87 | 89 | } | |
| 88 | 90 | } | |
| @@ -211,6 +213,30 @@ func callbackWrap(a *callbackArgs) { | |||
| 211 | 213 | } | |
| 212 | 214 | } | |
| 213 | 215 | floatsN += slots | |
| 216 | + | case reflect.String: | |
| 217 | + | slots = 1 | |
| 218 | + | var ptr uintptr | |
| 219 | + | if intsN+slots > numOfIntegerRegisters() { | |
| 220 | + | if runtime.GOOS == "darwin" && runtime.GOARCH == "arm64" { | |
| 221 | + | ptr = uintptr(callbackArgFromStack(a.args, stackSlot, &stackByteOffset, reflect.TypeOf(uintptr(0))).Uint()) | |
| 222 | + | } else if stackFrame != nil { | |
| 223 | + | if runtime.GOARCH == "s390x" { | |
| 224 | + | ptr = uintptr(callbackArgFromSlotBigEndian(unsafe.Pointer(&stackFrame[stackSlot]), reflect.TypeOf(uintptr(0))).Uint()) | |
| 225 | + | } else { | |
| 226 | + | ptr = *(*uintptr)(unsafe.Pointer(&stackFrame[stackSlot])) | |
| 227 | + | } | |
| 228 | + | stackSlot += slots | |
| 229 | + | } else { | |
| 230 | + | ptr = frame[stackSlot] | |
| 231 | + | stackSlot += slots | |
| 232 | + | } | |
| 233 | + | } else { | |
| 234 | + | pos := intsN + numOfFloatRegisters() | |
| 235 | + | ptr = frame[pos] | |
| 236 | + | } | |
| 237 | + | intsN += slots | |
| 238 | + | args[i] = reflect.ValueOf(strings.GoString(ptr)) | |
| 239 | + | continue | |
| 214 | 240 | case reflect.Struct: | |
| 215 | 241 | if i == 0 && inType.AssignableTo(reflect.TypeOf(CDecl{})) { | |
| 216 | 242 | args[i] = reflect.Zero(inType) | |
| @@ -11,6 +11,8 @@ import ( | |||||
| 11 | "runtime" | 11 | "runtime" | ||
| 12 | "sync" | 12 | "sync" | ||
| 13 | "unsafe" | 13 | "unsafe" | ||
| 14 | + | ||||
| 15 | + | "github.com/bnema/purego/internal/strings" | |||
| 14 | ) | 16 | ) | ||
| 15 | 17 | ||||
| 16 | var syscall15XABI0 uintptr | 18 | var syscall15XABI0 uintptr | ||
| @@ -82,7 +84,7 @@ func compileCallback(fn any) uintptr { | |||||
| 82 | continue | 84 | continue | ||
| 83 | case reflect.Interface, reflect.Func, reflect.Slice, | 85 | case reflect.Interface, reflect.Func, reflect.Slice, | ||
| 84 | reflect.Chan, reflect.Complex64, reflect.Complex128, | 86 | reflect.Chan, reflect.Complex64, reflect.Complex128, | ||
| 85 | - | reflect.String, reflect.Map, reflect.Invalid: | 87 | + | reflect.Map, reflect.Invalid: |
| 86 | panic("purego: unsupported argument type: " + in.Kind().String()) | 88 | panic("purego: unsupported argument type: " + in.Kind().String()) | ||
| 87 | } | 89 | } | ||
| 88 | } | 90 | } | ||
| @@ -211,6 +213,30 @@ func callbackWrap(a *callbackArgs) { | |||||
| 211 | } | 213 | } | ||
| 212 | } | 214 | } | ||
| 213 | floatsN += slots | 215 | floatsN += slots | ||
| 216 | + | case reflect.String: | |||
| 217 | + | slots = 1 | |||
| 218 | + | var ptr uintptr | |||
| 219 | + | if intsN+slots > numOfIntegerRegisters() { | |||
| 220 | + | if runtime.GOOS == "darwin" && runtime.GOARCH == "arm64" { | |||
| 221 | + | ptr = uintptr(callbackArgFromStack(a.args, stackSlot, &stackByteOffset, reflect.TypeOf(uintptr(0))).Uint()) | |||
| 222 | + | } else if stackFrame != nil { | |||
| 223 | + | if runtime.GOARCH == "s390x" { | |||
| 224 | + | ptr = uintptr(callbackArgFromSlotBigEndian(unsafe.Pointer(&stackFrame[stackSlot]), reflect.TypeOf(uintptr(0))).Uint()) | |||
| 225 | + | } else { | |||
| 226 | + | ptr = *(*uintptr)(unsafe.Pointer(&stackFrame[stackSlot])) | |||
| 227 | + | } | |||
| 228 | + | stackSlot += slots | |||
| 229 | + | } else { | |||
| 230 | + | ptr = frame[stackSlot] | |||
| 231 | + | stackSlot += slots | |||
| 232 | + | } | |||
| 233 | + | } else { | |||
| 234 | + | pos := intsN + numOfFloatRegisters() | |||
| 235 | + | ptr = frame[pos] | |||
| 236 | + | } | |||
| 237 | + | intsN += slots | |||
| 238 | + | args[i] = reflect.ValueOf(strings.GoString(ptr)) | |||
| 239 | + | continue | |||
| 214 | case reflect.Struct: | 240 | case reflect.Struct: | ||
| 215 | if i == 0 && inType.AssignableTo(reflect.TypeOf(CDecl{})) { | 241 | if i == 0 && inType.AssignableTo(reflect.TypeOf(CDecl{})) { | ||
| 216 | args[i] = reflect.Zero(inType) | 242 | args[i] = reflect.Zero(inType) | ||