detached d60df56

fakecgo: add s390x support for CGO_ENABLED=0 (#422)

commit
d60df56996e903cedc3502eac480026a2c469429
author
George Adams · · 2026-07-02 02:47 UTC
committer
GitHub · · 2026-07-02 02:47 UTC
parent
5da5389
signature
GPG UnverifiedB5690EEEBB952194 The key is unknown
refs
tag: v0.11.0-alpha.6
6 files · +235 -19
M .github/workflows/test.yml +10 -5
@@ -10,7 +10,7 @@ jobs:
1010 strategy:
1111 matrix:
1212 os: [ubuntu-latest, ubuntu-24.04-arm, macos-latest, windows-latest, windows-11-arm]
13- go: ['1.25.x', '1.26.x']
13+ go: ['1.25.x', '1.26.x', '1.27.0-rc.1']
1414 name: Test with Go ${{ matrix.go }} on ${{ matrix.os }}
1515 runs-on: ${{ matrix.os }}
1616 defaults:
@@ -75,13 +75,13 @@ jobs:
7575
7676 - name: go build (Linux minor architectures)
7777 # Test them only on the latest Go to reduce CI time.
78- # s390x cannot be tested here as it requires Cgo.
79- if: startsWith(matrix.go, '1.26.')
78+ if: startsWith(matrix.go, '1.27.')
8079 run: |
8180 # Check cross-compiling Linux binaries for minor architectures.
8281 env GOOS=linux GOARCH=loong64 go build -v ./...
8382 env GOOS=linux GOARCH=ppc64le go build -v ./...
8483 env GOOS=linux GOARCH=riscv64 go build -v ./...
84+ env GOOS=linux GOARCH=s390x go build -v ./...
8585
8686 - name: go build (Linux mips, Cgo)
8787 # mips builds only via the Cgo fallback (CGO_ENABLED=1). See #460.
@@ -191,7 +191,7 @@ jobs:
191191 minor-arches:
192192 strategy:
193193 matrix:
194- go: ['1.25.x', '1.26.x']
194+ go: ['1.25.x', '1.26.x', '1.27.0-rc.1']
195195 name: Test with Go ${{ matrix.go }} on Linux minor architectures
196196 runs-on: ubuntu-latest
197197 defaults:
@@ -278,6 +278,11 @@ jobs:
278278 run: |
279279 go env -w CC=s390x-linux-gnu-gcc
280280 go env -w CXX=s390x-linux-gnu-g++
281+ # CGO_ENABLED=0 is only supported on Go 1.27+ for s390x.
282+ if [[ "${{ matrix.go }}" != 1.25.* && "${{ matrix.go }}" != 1.26.* ]]; then
283+ env GOOS=linux GOARCH=s390x CGO_ENABLED=0 go test -c -o=purego-test-nocgo .
284+ env QEMU_LD_PREFIX=/usr/s390x-linux-gnu qemu-s390x ./purego-test-nocgo -test.shuffle=on -test.v -test.count=10
285+ fi
281286 env GOOS=linux GOARCH=s390x CGO_ENABLED=1 go test -c -o=purego-test-cgo .
282287 env QEMU_LD_PREFIX=/usr/s390x-linux-gnu qemu-s390x ./purego-test-cgo -test.shuffle=on -test.v -test.count=10
283288 go env -u CC
@@ -326,7 +331,7 @@ jobs:
326331 strategy:
327332 fail-fast: false
328333 matrix:
329- go: ['1.25.x', '1.26.x']
334+ go: ['1.25.x', '1.26.x', '1.27.0-rc.1']
330335 name: Test with Go ${{ matrix.go }} on Android amd64
331336 runs-on: ubuntu-latest
332337 defaults:
@@ -10,7 +10,7 @@ jobs:
10 strategy:10 strategy:
11 matrix:11 matrix:
12 os: [ubuntu-latest, ubuntu-24.04-arm, macos-latest, windows-latest, windows-11-arm]12 os: [ubuntu-latest, ubuntu-24.04-arm, macos-latest, windows-latest, windows-11-arm]
13- go: ['1.25.x', '1.26.x']13+ go: ['1.25.x', '1.26.x', '1.27.0-rc.1']
14 name: Test with Go ${{ matrix.go }} on ${{ matrix.os }}14 name: Test with Go ${{ matrix.go }} on ${{ matrix.os }}
15 runs-on: ${{ matrix.os }}15 runs-on: ${{ matrix.os }}
16 defaults:16 defaults:
@@ -75,13 +75,13 @@ jobs:
75 75
76 - name: go build (Linux minor architectures)76 - name: go build (Linux minor architectures)
77 # Test them only on the latest Go to reduce CI time.77 # Test them only on the latest Go to reduce CI time.
78- # s390x cannot be tested here as it requires Cgo.78+ if: startsWith(matrix.go, '1.27.')
79- if: startsWith(matrix.go, '1.26.')
80 run: |79 run: |
81 # Check cross-compiling Linux binaries for minor architectures.80 # Check cross-compiling Linux binaries for minor architectures.
82 env GOOS=linux GOARCH=loong64 go build -v ./...81 env GOOS=linux GOARCH=loong64 go build -v ./...
83 env GOOS=linux GOARCH=ppc64le go build -v ./...82 env GOOS=linux GOARCH=ppc64le go build -v ./...
84 env GOOS=linux GOARCH=riscv64 go build -v ./...83 env GOOS=linux GOARCH=riscv64 go build -v ./...
84+ env GOOS=linux GOARCH=s390x go build -v ./...
85 85
86 - name: go build (Linux mips, Cgo)86 - name: go build (Linux mips, Cgo)
87 # mips builds only via the Cgo fallback (CGO_ENABLED=1). See #460.87 # mips builds only via the Cgo fallback (CGO_ENABLED=1). See #460.
@@ -191,7 +191,7 @@ jobs:
191 minor-arches:191 minor-arches:
192 strategy:192 strategy:
193 matrix:193 matrix:
194- go: ['1.25.x', '1.26.x']194+ go: ['1.25.x', '1.26.x', '1.27.0-rc.1']
195 name: Test with Go ${{ matrix.go }} on Linux minor architectures195 name: Test with Go ${{ matrix.go }} on Linux minor architectures
196 runs-on: ubuntu-latest196 runs-on: ubuntu-latest
197 defaults:197 defaults:
@@ -278,6 +278,11 @@ jobs:
278 run: |278 run: |
279 go env -w CC=s390x-linux-gnu-gcc279 go env -w CC=s390x-linux-gnu-gcc
280 go env -w CXX=s390x-linux-gnu-g++280 go env -w CXX=s390x-linux-gnu-g++
281+ # CGO_ENABLED=0 is only supported on Go 1.27+ for s390x.
282+ if [[ "${{ matrix.go }}" != 1.25.* && "${{ matrix.go }}" != 1.26.* ]]; then
283+ env GOOS=linux GOARCH=s390x CGO_ENABLED=0 go test -c -o=purego-test-nocgo .
284+ env QEMU_LD_PREFIX=/usr/s390x-linux-gnu qemu-s390x ./purego-test-nocgo -test.shuffle=on -test.v -test.count=10
285+ fi
281 env GOOS=linux GOARCH=s390x CGO_ENABLED=1 go test -c -o=purego-test-cgo .286 env GOOS=linux GOARCH=s390x CGO_ENABLED=1 go test -c -o=purego-test-cgo .
282 env QEMU_LD_PREFIX=/usr/s390x-linux-gnu qemu-s390x ./purego-test-cgo -test.shuffle=on -test.v -test.count=10287 env QEMU_LD_PREFIX=/usr/s390x-linux-gnu qemu-s390x ./purego-test-cgo -test.shuffle=on -test.v -test.count=10
283 go env -u CC288 go env -u CC
@@ -326,7 +331,7 @@ jobs:
326 strategy:331 strategy:
327 fail-fast: false332 fail-fast: false
328 matrix:333 matrix:
329- go: ['1.25.x', '1.26.x']334+ go: ['1.25.x', '1.26.x', '1.27.0-rc.1']
330 name: Test with Go ${{ matrix.go }} on Android amd64335 name: Test with Go ${{ matrix.go }} on Android amd64
331 runs-on: ubuntu-latest336 runs-on: ubuntu-latest
332 defaults:337 defaults:
M README.md +5 -4
@@ -42,9 +42,9 @@ Tier 2 platforms are supported by PureGo on a best-effort basis. Critical bugs o
4242
4343 - **Android**: 386<sup>1,3</sup>, arm<sup>1,3</sup>
4444 - **FreeBSD**: amd64<sup>3,4</sup>, arm64<sup>3,4</sup>
45-- **Linux**: 386<sup>3</sup>, arm<sup>3</sup>, loong64<sup>3</sup>, ppc64le<sup>3</sup>, riscv64<sup>3</sup>, s390x<sup>1,3</sup>
45+- **Linux**: 386<sup>3</sup>, arm<sup>3</sup>, loong64<sup>3</sup>, ppc64le<sup>3</sup>, riscv64<sup>3</sup>, s390x<sup>3, 5</sup>
4646 - **NetBSD**: amd64<sup>3,4</sup>, arm64<sup>3,4</sup>
47-- **Windows**: 386<sup>3,5</sup>, arm<sup>3,5,6</sup>
47+- **Windows**: 386<sup>3,6</sup>, arm<sup>3,6,7</sup>
4848
4949 #### Support Notes
5050
@@ -52,8 +52,9 @@ Tier 2 platforms are supported by PureGo on a best-effort basis. Critical bugs o
5252 2. These architectures support passing structs by value as arguments and return values when calling C functions, but not in callbacks created with `NewCallback`
5353 3. These architectures do not support passing structs by value as arguments or return values
5454 4. These architectures require the special flag `-gcflags="github.com/ebitengine/purego/internal/fakecgo=-std"` to compile with CGO_ENABLED=0
55-5. These architectures only support `SyscallN` and `NewCallback`
56-6. These architectures are no longer supported as of Go 1.26
55+5. These architectures require CGO_ENABLED=1 to compile in versions before Go 1.27, but will be supported without Cgo in Go 1.27 and later
56+6. These architectures only support `SyscallN` and `NewCallback`
57+7. These architectures are no longer supported as of Go 1.26
5758
5859 ## Example
5960
@@ -42,9 +42,9 @@ Tier 2 platforms are supported by PureGo on a best-effort basis. Critical bugs o
42 42
43 - **Android**: 386<sup>1,3</sup>, arm<sup>1,3</sup>43 - **Android**: 386<sup>1,3</sup>, arm<sup>1,3</sup>
44 - **FreeBSD**: amd64<sup>3,4</sup>, arm64<sup>3,4</sup>44 - **FreeBSD**: amd64<sup>3,4</sup>, arm64<sup>3,4</sup>
45-- **Linux**: 386<sup>3</sup>, arm<sup>3</sup>, loong64<sup>3</sup>, ppc64le<sup>3</sup>, riscv64<sup>3</sup>, s390x<sup>1,3</sup>45+- **Linux**: 386<sup>3</sup>, arm<sup>3</sup>, loong64<sup>3</sup>, ppc64le<sup>3</sup>, riscv64<sup>3</sup>, s390x<sup>3, 5</sup>
46 - **NetBSD**: amd64<sup>3,4</sup>, arm64<sup>3,4</sup>46 - **NetBSD**: amd64<sup>3,4</sup>, arm64<sup>3,4</sup>
47-- **Windows**: 386<sup>3,5</sup>, arm<sup>3,5,6</sup>47+- **Windows**: 386<sup>3,6</sup>, arm<sup>3,6,7</sup>
48 48
49 #### Support Notes49 #### Support Notes
50 50
@@ -52,8 +52,9 @@ Tier 2 platforms are supported by PureGo on a best-effort basis. Critical bugs o
52 2. These architectures support passing structs by value as arguments and return values when calling C functions, but not in callbacks created with `NewCallback`52 2. These architectures support passing structs by value as arguments and return values when calling C functions, but not in callbacks created with `NewCallback`
53 3. These architectures do not support passing structs by value as arguments or return values53 3. These architectures do not support passing structs by value as arguments or return values
54 4. These architectures require the special flag `-gcflags="github.com/ebitengine/purego/internal/fakecgo=-std"` to compile with CGO_ENABLED=054 4. These architectures require the special flag `-gcflags="github.com/ebitengine/purego/internal/fakecgo=-std"` to compile with CGO_ENABLED=0
55-5. These architectures only support `SyscallN` and `NewCallback`55+5. These architectures require CGO_ENABLED=1 to compile in versions before Go 1.27, but will be supported without Cgo in Go 1.27 and later
56-6. These architectures are no longer supported as of Go 1.2656+6. These architectures only support `SyscallN` and `NewCallback`
57+7. These architectures are no longer supported as of Go 1.26
57 58
58 ## Example59 ## Example
59 60
A internal/fakecgo/trampolines_linux_s390x.s +51 -0
@@ -0,0 +1,51 @@
1+// SPDX-License-Identifier: Apache-2.0
2+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
3+
4+//go:build go1.27 && !cgo
5+
6+#include "textflag.h"
7+
8+TEXT _cgo_purego_setegid_trampoline(SB), NOSPLIT|NOFRAME, $0
9+ MOVD ·x_cgo_purego_setegid_call(SB), R1
10+ MOVD (R1), R1
11+ BR R1
12+
13+TEXT _cgo_purego_seteuid_trampoline(SB), NOSPLIT|NOFRAME, $0
14+ MOVD ·x_cgo_purego_seteuid_call(SB), R1
15+ MOVD (R1), R1
16+ BR R1
17+
18+TEXT _cgo_purego_setgid_trampoline(SB), NOSPLIT|NOFRAME, $0
19+ MOVD ·x_cgo_purego_setgid_call(SB), R1
20+ MOVD (R1), R1
21+ BR R1
22+
23+TEXT _cgo_purego_setregid_trampoline(SB), NOSPLIT|NOFRAME, $0
24+ MOVD ·x_cgo_purego_setregid_call(SB), R1
25+ MOVD (R1), R1
26+ BR R1
27+
28+TEXT _cgo_purego_setresgid_trampoline(SB), NOSPLIT|NOFRAME, $0
29+ MOVD ·x_cgo_purego_setresgid_call(SB), R1
30+ MOVD (R1), R1
31+ BR R1
32+
33+TEXT _cgo_purego_setresuid_trampoline(SB), NOSPLIT|NOFRAME, $0
34+ MOVD ·x_cgo_purego_setresuid_call(SB), R1
35+ MOVD (R1), R1
36+ BR R1
37+
38+TEXT _cgo_purego_setreuid_trampoline(SB), NOSPLIT|NOFRAME, $0
39+ MOVD ·x_cgo_purego_setreuid_call(SB), R1
40+ MOVD (R1), R1
41+ BR R1
42+
43+TEXT _cgo_purego_setuid_trampoline(SB), NOSPLIT|NOFRAME, $0
44+ MOVD ·x_cgo_purego_setuid_call(SB), R1
45+ MOVD (R1), R1
46+ BR R1
47+
48+TEXT _cgo_purego_setgroups_trampoline(SB), NOSPLIT|NOFRAME, $0
49+ MOVD ·x_cgo_purego_setgroups_call(SB), R1
50+ MOVD (R1), R1
51+ BR R1
@@ -0,0 +1,51 @@
1+// SPDX-License-Identifier: Apache-2.0
2+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
3+
4+//go:build go1.27 && !cgo
5+
6+#include "textflag.h"
7+
8+TEXT _cgo_purego_setegid_trampoline(SB), NOSPLIT|NOFRAME, $0
9+ MOVD ·x_cgo_purego_setegid_call(SB), R1
10+ MOVD (R1), R1
11+ BR R1
12+
13+TEXT _cgo_purego_seteuid_trampoline(SB), NOSPLIT|NOFRAME, $0
14+ MOVD ·x_cgo_purego_seteuid_call(SB), R1
15+ MOVD (R1), R1
16+ BR R1
17+
18+TEXT _cgo_purego_setgid_trampoline(SB), NOSPLIT|NOFRAME, $0
19+ MOVD ·x_cgo_purego_setgid_call(SB), R1
20+ MOVD (R1), R1
21+ BR R1
22+
23+TEXT _cgo_purego_setregid_trampoline(SB), NOSPLIT|NOFRAME, $0
24+ MOVD ·x_cgo_purego_setregid_call(SB), R1
25+ MOVD (R1), R1
26+ BR R1
27+
28+TEXT _cgo_purego_setresgid_trampoline(SB), NOSPLIT|NOFRAME, $0
29+ MOVD ·x_cgo_purego_setresgid_call(SB), R1
30+ MOVD (R1), R1
31+ BR R1
32+
33+TEXT _cgo_purego_setresuid_trampoline(SB), NOSPLIT|NOFRAME, $0
34+ MOVD ·x_cgo_purego_setresuid_call(SB), R1
35+ MOVD (R1), R1
36+ BR R1
37+
38+TEXT _cgo_purego_setreuid_trampoline(SB), NOSPLIT|NOFRAME, $0
39+ MOVD ·x_cgo_purego_setreuid_call(SB), R1
40+ MOVD (R1), R1
41+ BR R1
42+
43+TEXT _cgo_purego_setuid_trampoline(SB), NOSPLIT|NOFRAME, $0
44+ MOVD ·x_cgo_purego_setuid_call(SB), R1
45+ MOVD (R1), R1
46+ BR R1
47+
48+TEXT _cgo_purego_setgroups_trampoline(SB), NOSPLIT|NOFRAME, $0
49+ MOVD ·x_cgo_purego_setgroups_call(SB), R1
50+ MOVD (R1), R1
51+ BR R1
A internal/fakecgo/trampolines_s390x.s +158 -0
@@ -0,0 +1,158 @@
1+// SPDX-License-Identifier: Apache-2.0
2+// SPDX-FileCopyrightText: 2026 The Ebitengine Authors
3+
4+//go:build go1.27 && !cgo && linux
5+
6+#include "textflag.h"
7+#include "go_asm.h"
8+
9+// these trampolines map the gcc ABI to Go ABI and then calls into the Go equivalent functions.
10+// Note that C arguments are passed in R2-R6, which matches Go ABIInternal for the first five arguments.
11+// R1 is used as a temporary register.
12+
13+TEXT x_cgo_init_trampoline(SB), NOSPLIT|NOFRAME, $0-0
14+ MOVD R15, R1
15+ SUB $192, R15
16+ MOVD R1, 0(R15) // backchain
17+ MOVD R14, 160(R15) // save R14
18+ MOVD R9, 168(R15) // save R9 (Go runtime needs this preserved)
19+
20+ MOVD ·x_cgo_init_call(SB), R1
21+ MOVD (R1), R1
22+ BL R1
23+
24+ MOVD 168(R15), R9
25+ MOVD 160(R15), R14
26+ ADD $192, R15
27+ BR R14
28+
29+TEXT x_cgo_thread_start_trampoline(SB), NOSPLIT|NOFRAME, $0-0
30+ MOVD R15, R1
31+ SUB $176, R15
32+ MOVD R1, 0(R15) // backchain
33+ MOVD R14, 152(R15) // save R14
34+
35+ MOVD ·x_cgo_thread_start_call(SB), R1
36+ MOVD (R1), R1
37+ BL R1
38+
39+ MOVD 152(R15), R14
40+ ADD $176, R15
41+ BR R14
42+
43+TEXT x_cgo_setenv_trampoline(SB), NOSPLIT|NOFRAME, $0-0
44+ MOVD R15, R1
45+ SUB $176, R15
46+ MOVD R1, 0(R15) // backchain
47+ MOVD R14, 152(R15) // save R14
48+
49+ MOVD ·x_cgo_setenv_call(SB), R1
50+ MOVD (R1), R1
51+ BL R1
52+
53+ MOVD 152(R15), R14
54+ ADD $176, R15
55+ BR R14
56+
57+TEXT x_cgo_unsetenv_trampoline(SB), NOSPLIT|NOFRAME, $0-0
58+ MOVD R15, R1
59+ SUB $176, R15
60+ MOVD R1, 0(R15) // backchain
61+ MOVD R14, 152(R15) // save R14
62+
63+ MOVD ·x_cgo_unsetenv_call(SB), R1
64+ MOVD (R1), R1
65+ BL R1
66+
67+ MOVD 152(R15), R14
68+ ADD $176, R15
69+ BR R14
70+
71+// These just tail-call into Go functions
72+TEXT x_cgo_notify_runtime_init_done_trampoline(SB), NOSPLIT|NOFRAME, $0-0
73+ BR ·x_cgo_notify_runtime_init_done(SB)
74+
75+TEXT x_cgo_bindm_trampoline(SB), NOSPLIT|NOFRAME, $0-0
76+ BR ·x_cgo_bindm(SB)
77+
78+// setg_trampoline(setg uintptr, g uintptr) - called from Go
79+TEXT ·setg_trampoline(SB), NOSPLIT|NOFRAME, $0-16
80+ MOVD 8(R15), R1 // setg function pointer
81+ MOVD 16(R15), R2 // g pointer -> C arg
82+
83+ MOVD R14, R0
84+ MOVD R15, R3
85+ SUB $160, R15
86+ MOVD R3, 0(R15)
87+ MOVD R0, 112(R15)
88+ MOVD R2, 120(R15) // save newg before call
89+
90+ BL R1 // call setg_gcc
91+
92+ // Assign g directly instead of calling runtime·load_g
93+ // setg_gcc has already stored newg into TLS; put it in the g register too.
94+ MOVD 120(R15), g
95+
96+ MOVD 112(R15), R14
97+ ADD $160, R15
98+ BR R14
99+
100+TEXT threadentry_trampoline(SB), NOSPLIT|NOFRAME, $0-0
101+ STMG R6, R15, 48(R15) // C save area
102+ MOVD R15, R1
103+ SUB $176, R15
104+ MOVD R1, 0(R15) // backchain
105+
106+ MOVD ·threadentry_call(SB), R1
107+ MOVD (R1), R1
108+ BL R1
109+
110+ ADD $176, R15
111+ LMG 48(R15), R6, R15
112+ RET
113+
114+TEXT ·call5(SB), NOSPLIT|NOFRAME, $0-56
115+ // Load Go args before modifying R15
116+ MOVD 8(R15), R1 // fn
117+ MOVD 16(R15), R7 // a1
118+ MOVD 24(R15), R8 // a2
119+ MOVD 32(R15), R9 // a3
120+ MOVD 40(R15), R10 // a4
121+ MOVD 48(R15), R11 // a5
122+
123+ // Save state
124+ MOVD R15, R0 // original R15
125+ MOVD R12, R6 // Go's R12
126+ ADD $-128, R15
127+
128+ // Set up C frame with backchain
129+ MOVD R0, 0(R15) // backchain -> original R15
130+ MOVD R0, R3 // R3 = original R15 (can't use R0 as base!)
131+ MOVD 0(R3), R7 // save 0(original R15)
132+ MOVD $0, 0(R3) // terminate backchain
133+
134+ // Save context
135+ MOVD R14, 8(R15)
136+ MOVD R6, 16(R15) // R12
137+ MOVD R0, 24(R15) // original R15
138+ MOVD R7, 32(R15) // saved backchain
139+
140+ // Set up C args (reload a1 since R7 was clobbered)
141+ MOVD 16(R3), R2 // a1 (use R3 as base, not R0!)
142+ MOVD R8, R3 // a2
143+ MOVD R9, R4 // a3
144+ MOVD R10, R5 // a4
145+ MOVD R11, R6 // a5
146+
147+ BL R1
148+
149+ // Store result and restore
150+ MOVD 24(R15), R3 // original R15
151+ MOVD R2, 56(R3) // return value
152+ MOVD 32(R15), R7
153+ MOVD R7, 0(R3) // restore backchain
154+
155+ MOVD 8(R15), R14
156+ MOVD 16(R15), R12
157+ MOVD 24(R15), R15
158+ BR R14
@@ -0,0 +1,158 @@
1+// SPDX-License-Identifier: Apache-2.0
2+// SPDX-FileCopyrightText: 2026 The Ebitengine Authors
3+
4+//go:build go1.27 && !cgo && linux
5+
6+#include "textflag.h"
7+#include "go_asm.h"
8+
9+// these trampolines map the gcc ABI to Go ABI and then calls into the Go equivalent functions.
10+// Note that C arguments are passed in R2-R6, which matches Go ABIInternal for the first five arguments.
11+// R1 is used as a temporary register.
12+
13+TEXT x_cgo_init_trampoline(SB), NOSPLIT|NOFRAME, $0-0
14+ MOVD R15, R1
15+ SUB $192, R15
16+ MOVD R1, 0(R15) // backchain
17+ MOVD R14, 160(R15) // save R14
18+ MOVD R9, 168(R15) // save R9 (Go runtime needs this preserved)
19+
20+ MOVD ·x_cgo_init_call(SB), R1
21+ MOVD (R1), R1
22+ BL R1
23+
24+ MOVD 168(R15), R9
25+ MOVD 160(R15), R14
26+ ADD $192, R15
27+ BR R14
28+
29+TEXT x_cgo_thread_start_trampoline(SB), NOSPLIT|NOFRAME, $0-0
30+ MOVD R15, R1
31+ SUB $176, R15
32+ MOVD R1, 0(R15) // backchain
33+ MOVD R14, 152(R15) // save R14
34+
35+ MOVD ·x_cgo_thread_start_call(SB), R1
36+ MOVD (R1), R1
37+ BL R1
38+
39+ MOVD 152(R15), R14
40+ ADD $176, R15
41+ BR R14
42+
43+TEXT x_cgo_setenv_trampoline(SB), NOSPLIT|NOFRAME, $0-0
44+ MOVD R15, R1
45+ SUB $176, R15
46+ MOVD R1, 0(R15) // backchain
47+ MOVD R14, 152(R15) // save R14
48+
49+ MOVD ·x_cgo_setenv_call(SB), R1
50+ MOVD (R1), R1
51+ BL R1
52+
53+ MOVD 152(R15), R14
54+ ADD $176, R15
55+ BR R14
56+
57+TEXT x_cgo_unsetenv_trampoline(SB), NOSPLIT|NOFRAME, $0-0
58+ MOVD R15, R1
59+ SUB $176, R15
60+ MOVD R1, 0(R15) // backchain
61+ MOVD R14, 152(R15) // save R14
62+
63+ MOVD ·x_cgo_unsetenv_call(SB), R1
64+ MOVD (R1), R1
65+ BL R1
66+
67+ MOVD 152(R15), R14
68+ ADD $176, R15
69+ BR R14
70+
71+// These just tail-call into Go functions
72+TEXT x_cgo_notify_runtime_init_done_trampoline(SB), NOSPLIT|NOFRAME, $0-0
73+ BR ·x_cgo_notify_runtime_init_done(SB)
74+
75+TEXT x_cgo_bindm_trampoline(SB), NOSPLIT|NOFRAME, $0-0
76+ BR ·x_cgo_bindm(SB)
77+
78+// setg_trampoline(setg uintptr, g uintptr) - called from Go
79+TEXT ·setg_trampoline(SB), NOSPLIT|NOFRAME, $0-16
80+ MOVD 8(R15), R1 // setg function pointer
81+ MOVD 16(R15), R2 // g pointer -> C arg
82+
83+ MOVD R14, R0
84+ MOVD R15, R3
85+ SUB $160, R15
86+ MOVD R3, 0(R15)
87+ MOVD R0, 112(R15)
88+ MOVD R2, 120(R15) // save newg before call
89+
90+ BL R1 // call setg_gcc
91+
92+ // Assign g directly instead of calling runtime·load_g
93+ // setg_gcc has already stored newg into TLS; put it in the g register too.
94+ MOVD 120(R15), g
95+
96+ MOVD 112(R15), R14
97+ ADD $160, R15
98+ BR R14
99+
100+TEXT threadentry_trampoline(SB), NOSPLIT|NOFRAME, $0-0
101+ STMG R6, R15, 48(R15) // C save area
102+ MOVD R15, R1
103+ SUB $176, R15
104+ MOVD R1, 0(R15) // backchain
105+
106+ MOVD ·threadentry_call(SB), R1
107+ MOVD (R1), R1
108+ BL R1
109+
110+ ADD $176, R15
111+ LMG 48(R15), R6, R15
112+ RET
113+
114+TEXT ·call5(SB), NOSPLIT|NOFRAME, $0-56
115+ // Load Go args before modifying R15
116+ MOVD 8(R15), R1 // fn
117+ MOVD 16(R15), R7 // a1
118+ MOVD 24(R15), R8 // a2
119+ MOVD 32(R15), R9 // a3
120+ MOVD 40(R15), R10 // a4
121+ MOVD 48(R15), R11 // a5
122+
123+ // Save state
124+ MOVD R15, R0 // original R15
125+ MOVD R12, R6 // Go's R12
126+ ADD $-128, R15
127+
128+ // Set up C frame with backchain
129+ MOVD R0, 0(R15) // backchain -> original R15
130+ MOVD R0, R3 // R3 = original R15 (can't use R0 as base!)
131+ MOVD 0(R3), R7 // save 0(original R15)
132+ MOVD $0, 0(R3) // terminate backchain
133+
134+ // Save context
135+ MOVD R14, 8(R15)
136+ MOVD R6, 16(R15) // R12
137+ MOVD R0, 24(R15) // original R15
138+ MOVD R7, 32(R15) // saved backchain
139+
140+ // Set up C args (reload a1 since R7 was clobbered)
141+ MOVD 16(R3), R2 // a1 (use R3 as base, not R0!)
142+ MOVD R8, R3 // a2
143+ MOVD R9, R4 // a3
144+ MOVD R10, R5 // a4
145+ MOVD R11, R6 // a5
146+
147+ BL R1
148+
149+ // Store result and restore
150+ MOVD 24(R15), R3 // original R15
151+ MOVD R2, 56(R3) // return value
152+ MOVD 32(R15), R7
153+ MOVD R7, 0(R3) // restore backchain
154+
155+ MOVD 8(R15), R14
156+ MOVD 16(R15), R12
157+ MOVD 24(R15), R15
158+ BR R14
M sys_unix_s390x.s +10 -8
@@ -18,22 +18,24 @@
1818 //
1919 // S390X uses R2-R6 for integer arguments (5 registers) and F0,F2,F4,F6 for floats (4 registers).
2020 //
21-// Our frame layout (total 264 bytes, 8-byte aligned):
21+// Our frame layout (total 200 bytes, 8-byte aligned). To stay under the
22+// 800-byte nosplit limit on Go 1.27 the callbackArgs struct is stored in the
23+// caller's free linkage slot (old_R15+16..48) instead of our own frame:
2224 // 0(R15) - back chain
2325 // 48(R15) - saved R6-R15 (done by STMG)
24-// 160(R15) - callbackArgs struct (32 bytes: index, args, result, stackArgs)
25-// 192(R15) - args array start
26+// 128(R15) - args array start
2627 //
2728 // Args array layout:
2829 // - floats F0,F2,F4,F6 (32 bytes)
2930 // - ints R2-R6 (40 bytes)
30-// Total args array: 72 bytes, ends at 264
31+// Total args array: 72 bytes, ends at 200
3132 //
33+// callbackArgs struct lives at old_R15+16 (32 bytes: index, args, result, stackArgs)
3234 // Stack args in caller's frame start at old_R15+160
3335
34-#define FRAME_SIZE 264
35-#define CB_ARGS 160
36-#define ARGS_ARRAY 192
36+#define FRAME_SIZE 200
37+#define ARGS_ARRAY 128
38+#define CB_ARGS (FRAME_SIZE+16)
3739 #define FLOAT_OFF 0
3840 #define INT_OFF 32
3941
@@ -71,7 +73,7 @@ TEXT callbackasm1(SB), NOSPLIT|NOFRAME, $0
7173 MOVD R5, (ARGS_ARRAY+INT_OFF+3*8)(R15)
7274
7375 // R6 (5th int arg) was saved at 48(old_R15) by STMG
74- // old_R15 = current R15 + FRAME_SIZE, so R6 is at 48+FRAME_SIZE(R15) = 312(R15)
76+ // old_R15 = current R15 + FRAME_SIZE
7577 MOVD (48+FRAME_SIZE)(R15), R1
7678 MOVD R1, (ARGS_ARRAY+INT_OFF+4*8)(R15)
7779
@@ -18,22 +18,24 @@
18 //18 //
19 // S390X uses R2-R6 for integer arguments (5 registers) and F0,F2,F4,F6 for floats (4 registers).19 // S390X uses R2-R6 for integer arguments (5 registers) and F0,F2,F4,F6 for floats (4 registers).
20 //20 //
21-// Our frame layout (total 264 bytes, 8-byte aligned):21+// Our frame layout (total 200 bytes, 8-byte aligned). To stay under the
22+// 800-byte nosplit limit on Go 1.27 the callbackArgs struct is stored in the
23+// caller's free linkage slot (old_R15+16..48) instead of our own frame:
22 // 0(R15) - back chain24 // 0(R15) - back chain
23 // 48(R15) - saved R6-R15 (done by STMG)25 // 48(R15) - saved R6-R15 (done by STMG)
24-// 160(R15) - callbackArgs struct (32 bytes: index, args, result, stackArgs)26+// 128(R15) - args array start
25-// 192(R15) - args array start
26 //27 //
27 // Args array layout:28 // Args array layout:
28 // - floats F0,F2,F4,F6 (32 bytes)29 // - floats F0,F2,F4,F6 (32 bytes)
29 // - ints R2-R6 (40 bytes)30 // - ints R2-R6 (40 bytes)
30-// Total args array: 72 bytes, ends at 26431+// Total args array: 72 bytes, ends at 200
31 //32 //
33+// callbackArgs struct lives at old_R15+16 (32 bytes: index, args, result, stackArgs)
32 // Stack args in caller's frame start at old_R15+16034 // Stack args in caller's frame start at old_R15+160
33 35
34-#define FRAME_SIZE 26436+#define FRAME_SIZE 200
35-#define CB_ARGS 16037+#define ARGS_ARRAY 128
36-#define ARGS_ARRAY 19238+#define CB_ARGS (FRAME_SIZE+16)
37 #define FLOAT_OFF 039 #define FLOAT_OFF 0
38 #define INT_OFF 3240 #define INT_OFF 32
39 41
@@ -71,7 +73,7 @@ TEXT callbackasm1(SB), NOSPLIT|NOFRAME, $0
71 MOVD R5, (ARGS_ARRAY+INT_OFF+3*8)(R15)73 MOVD R5, (ARGS_ARRAY+INT_OFF+3*8)(R15)
72 74
73 // R6 (5th int arg) was saved at 48(old_R15) by STMG75 // R6 (5th int arg) was saved at 48(old_R15) by STMG
74- // old_R15 = current R15 + FRAME_SIZE, so R6 is at 48+FRAME_SIZE(R15) = 312(R15)76+ // old_R15 = current R15 + FRAME_SIZE
75 MOVD (48+FRAME_SIZE)(R15), R177 MOVD (48+FRAME_SIZE)(R15), R1
76 MOVD R1, (ARGS_ARRAY+INT_OFF+4*8)(R15)78 MOVD R1, (ARGS_ARRAY+INT_OFF+4*8)(R15)
77 79
M syscall_unix.go +1 -2
@@ -1,8 +1,7 @@
11 // SPDX-License-Identifier: Apache-2.0
22 // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
33
4-// TODO: remove s390x cgo dependency once golang/go#77449 is resolved
5-//go:build darwin || freebsd || (linux && (386 || amd64 || arm || arm64 || loong64 || ppc64le || riscv64 || (cgo && s390x))) || netbsd
4+//go:build darwin || freebsd || (linux && (386 || amd64 || arm || arm64 || loong64 || ppc64le || riscv64 || (s390x && (cgo || go1.27)))) || netbsd
65
76 package purego
87
@@ -1,8 +1,7 @@
1 // SPDX-License-Identifier: Apache-2.01 // SPDX-License-Identifier: Apache-2.0
2 // SPDX-FileCopyrightText: 2022 The Ebitengine Authors2 // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
3 3
4-// TODO: remove s390x cgo dependency once golang/go#77449 is resolved4+//go:build darwin || freebsd || (linux && (386 || amd64 || arm || arm64 || loong64 || ppc64le || riscv64 || (s390x && (cgo || go1.27)))) || netbsd
5-//go:build darwin || freebsd || (linux && (386 || amd64 || arm || arm64 || loong64 || ppc64le || riscv64 || (cgo && s390x))) || netbsd
6 5
7 package purego6 package purego
8 7

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 102

↑↓ moveenter openesc close