purego: support structs on Windows amd64/arm64#465
Conversation
a81e3a8 to
01d358a
Compare
There was a problem hiding this comment.
Pull request overview
Adds Windows support for passing/returning C structs by value for forward calls (Go → C) on amd64 and arm64, and updates tests/docs accordingly.
Changes:
- Enable struct argument/return support gating for Windows in
RegisterFuncand add Win64-specific struct ABI handling onamd64. - Update struct tests to run on Windows and use a cross-platform library loader helper.
- Update README/platform notes and public docs to reflect Windows struct support limitations (no struct callbacks on Windows).
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
func.go |
Extends struct support gating to Windows; adds amd64StructReturnInMemory helper and adjusts empty-struct arg handling on Windows. |
struct_amd64.go |
Implements Win64-specific struct argument passing and struct return reconstruction logic. |
struct_test.go |
Enables Windows builds for struct tests; switches to internal/load and skips callback-based struct testing on Windows. |
testdata/structtest/struct_test.c |
Normalizes integer/pointer types for consistent ABI sizing across platforms (incl. Windows). |
README.md |
Updates support matrix/footnotes to document Windows struct support for forward calls and callback limitation. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
01d358a to
b365dec
Compare
b365dec to
7c7a011
Compare
|
@TotallyGamerJet PTAL |
7c7a011 to
9027911
Compare
|
FYI if you add |
9027911 to
a717c8d
Compare
Thanks, done |
Enable passing and returning C structs by value on Windows for forward calls (Go calling C). On amd64 the Win64 ABI is used: aggregates of exactly 1, 2, 4, or 8 bytes are passed by value in a single integer slot and returned in RAX, while all other sizes are passed and returned through a caller-allocated pointer. This maps cleanly onto the positional syscall.SyscallN path and needs no float-register handling, because Win64 never passes struct fields in XMM registers. Unlike the System V ABI, an empty struct argument still consumes a slot on Win64. On arm64 the existing AAPCS64 path already runs on Windows via the shared assembly, so only the support gate is opened. Passing or returning structs in callbacks created with NewCallback is not supported on Windows, because they go through the standard library syscall.NewCallback, which cannot carry struct values. The struct test C library used `long` for values that must be 64-bit, which is only 32-bit on Windows (LLP64) and overflowed the 64-bit shift expressions and shrank struct sizes. Replace it with width-correct stdint types: int64_t/uint64_t for Go's fixed-width int64/uint64, and intptr_t/uintptr_t for Go's word-sized int/uint, so the library is correct under both LP64 and LLP64. Closes ebitengine#237 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Unfortunately, the msys tools on GitHub Windows Arm are not for Arm64 but for x86_64, then they don't work. I'll make a following PR later after this PR. I'll revert adding Windows Arm from this PR. |
a717c8d to
fd6436b
Compare
What issue is this addressing?
Closes #237
What type of issue is this addressing?
feature
What this PR does | solves
Adds support for passing and returning C structs by value on Windows
for forward calls (Go calling C), on both
amd64andarm64.Previously
RegisterFunc/RegisterLibFuncpanicked withstruct arguments/returns are only supported on darwin and linuxonWindows, so callers had to manually decompose structs into
uintptrsor pass pointers.
amd64 (Win64 ABI)
Windows amd64 goes through the standard library
syscall.SyscallN,which only carries positional
uintptrarguments. This is sufficientbecause the Win64 struct ABI never uses XMM registers for struct
fields:
by value in a single integer slot; all other sizes are passed as a
pointer to a caller-allocated copy.
RAX; every othersize is returned through a caller-allocated hidden pointer (which the
callee also returns in
RAX).This is implemented as a small Win64-specific branch in
struct_amd64.goplus anamd64StructReturnInMemoryhelper, since theexisting System V eightbyte-classification path cannot be reused.
arm64 (AAPCS64)
Windows arm64 already runs through purego's own assembly
(
sys_arm64.sincludeswindowsand loadsX0–X7/F0–F7/R8/stack),and the AAPCS64 placement logic in
struct_arm64.gohas no GOOSconstraint. Windows arm64 follows AAPCS64 for structs in non-variadic
functions, so only the support gate needed to be opened — no new ABI
code.
Not supported: structs in callbacks
Passing or returning structs in callbacks created with
NewCallbackremains unsupported on Windows, because Windows callbacks go through
the standard library
syscall.NewCallback, which cannot carry structvalues. This is documented in the
RegisterFuncgodoc and as a READMEsupport note.
Testing
struct_test.gonow builds on Windows (amd64/arm64); the callbacksub-implementation is skipped there, exercising only forward calls.
go test ./...onwindows-latest(amd64, with gcc), so the forward-call struct tests are exercised
there automatically. Windows arm64 is compile-checked only (no arm64
Windows runner).
existing targets, and that the existing struct tests still pass on
darwin/arm64.
Notes for reviewers
reflect.Newaligns to the type (often 8). This is fine forscalar-field structs in practice but is a candidate follow-up if a
vector-type case ever appears.
to accommodate the two new struct notes.
runtime.GOOSisios/android, notdarwin/linux); enablingthem is left as a separate change.
🤖 Generated with Claude Code