detached 15800b5

purego: return 64-bit callback results on 386 (#519)

The 386 callback trampoline returned only EAX, losing the upper half
of int64 and uint64 results. Its callbackArgs area also overlapped
the copied C arguments.

Reserve space for the full callbackArgs struct, move the argument
copy past it, and return both result words in EDX:EAX.

Add regression tests for signed and unsigned 64-bit callback results,
including a callback with stack arguments.

Closes #524
commit
15800b5b0a4f3febc099cf663d75ab558a6db8f2
author
Hiroki KUMAZAKI · · 2026-09-12 07:22 UTC
committer
Hajime Hoshi · · 2026-09-18 20:30 UTC
parent
fc7e496
signature
unsigned
refs
tag: v0.11.1
2 files · +129 -74
M callback_test.go +47 -0
@@ -154,6 +154,53 @@ func TestNewCallbackFloat32AndFloat64(t *testing.T) {
154154 }
155155 }
156156
157+func TestNewCallbackInt64Result(t *testing.T) {
158+ // A 64-bit result needs two words: EDX:EAX on 386 and R1:R0 on arm.
159+ // The trampoline must forward both halves of the value.
160+ const mask = int64(0x0123456789abcdef)
161+ imp := purego.NewCallback(func(v int64) int64 { return v ^ mask })
162+ var fn func(v int64) int64
163+ purego.RegisterFunc(&fn, imp)
164+ for _, v := range []int64{
165+ 0,
166+ -1,
167+ 1 << 32,
168+ -0x7edcba9876543210,
169+ } {
170+ if got, want := fn(v), v^mask; got != want {
171+ t.Errorf("callback(%#x) = %#x, want %#x", uint64(v), uint64(got), uint64(want))
172+ }
173+ }
174+}
175+
176+func TestNewCallbackUint64Result(t *testing.T) {
177+ // The upper half of a uint64 result must not be dropped by the trampoline.
178+ imp := purego.NewCallback(func(lo, hi uint32) uint64 { return uint64(hi)<<32 | uint64(lo) })
179+ var fn func(lo, hi uint32) uint64
180+ purego.RegisterFunc(&fn, imp)
181+ const want = uint64(0x0123456789abcdef)
182+ if got := fn(0x89abcdef, 0x01234567); got != want {
183+ t.Errorf("callback() = %#x, want %#x", got, want)
184+ }
185+}
186+
187+func TestNewCallbackInt64ResultWithStackArgs(t *testing.T) {
188+ // On 386 all the arguments are passed on the stack, so this also checks
189+ // that the copied arguments do not overlap the result of the callback.
190+ // The number of arguments is kept small enough for ppc64le, which only
191+ // has maxArgs(15) slots in total, 8 of them in integer registers.
192+ const wantSum = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12
193+ imp := purego.NewCallback(func(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 int) int64 {
194+ return int64(a1+a2+a3+a4+a5+a6+a7+a8+a9+a10+a11+a12)<<32 | 0x0badf00d
195+ })
196+ var fn func(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 int) int64
197+ purego.RegisterFunc(&fn, imp)
198+ const want = int64(wantSum)<<32 | 0x0badf00d
199+ if got := fn(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12); got != want {
200+ t.Errorf("callback() = %#x, want %#x", uint64(got), uint64(want))
201+ }
202+}
203+
157204 func ExampleNewCallback() {
158205 cb := purego.NewCallback(func(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 int) int {
159206 fmt.Println(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15)
@@ -154,6 +154,53 @@ func TestNewCallbackFloat32AndFloat64(t *testing.T) {
154 }154 }
155 }155 }
156 156
157+func TestNewCallbackInt64Result(t *testing.T) {
158+ // A 64-bit result needs two words: EDX:EAX on 386 and R1:R0 on arm.
159+ // The trampoline must forward both halves of the value.
160+ const mask = int64(0x0123456789abcdef)
161+ imp := purego.NewCallback(func(v int64) int64 { return v ^ mask })
162+ var fn func(v int64) int64
163+ purego.RegisterFunc(&fn, imp)
164+ for _, v := range []int64{
165+ 0,
166+ -1,
167+ 1 << 32,
168+ -0x7edcba9876543210,
169+ } {
170+ if got, want := fn(v), v^mask; got != want {
171+ t.Errorf("callback(%#x) = %#x, want %#x", uint64(v), uint64(got), uint64(want))
172+ }
173+ }
174+}
175+
176+func TestNewCallbackUint64Result(t *testing.T) {
177+ // The upper half of a uint64 result must not be dropped by the trampoline.
178+ imp := purego.NewCallback(func(lo, hi uint32) uint64 { return uint64(hi)<<32 | uint64(lo) })
179+ var fn func(lo, hi uint32) uint64
180+ purego.RegisterFunc(&fn, imp)
181+ const want = uint64(0x0123456789abcdef)
182+ if got := fn(0x89abcdef, 0x01234567); got != want {
183+ t.Errorf("callback() = %#x, want %#x", got, want)
184+ }
185+}
186+
187+func TestNewCallbackInt64ResultWithStackArgs(t *testing.T) {
188+ // On 386 all the arguments are passed on the stack, so this also checks
189+ // that the copied arguments do not overlap the result of the callback.
190+ // The number of arguments is kept small enough for ppc64le, which only
191+ // has maxArgs(15) slots in total, 8 of them in integer registers.
192+ const wantSum = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12
193+ imp := purego.NewCallback(func(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 int) int64 {
194+ return int64(a1+a2+a3+a4+a5+a6+a7+a8+a9+a10+a11+a12)<<32 | 0x0badf00d
195+ })
196+ var fn func(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 int) int64
197+ purego.RegisterFunc(&fn, imp)
198+ const want = int64(wantSum)<<32 | 0x0badf00d
199+ if got := fn(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12); got != want {
200+ t.Errorf("callback() = %#x, want %#x", uint64(got), uint64(want))
201+ }
202+}
203+
157 func ExampleNewCallback() {204 func ExampleNewCallback() {
158 cb := purego.NewCallback(func(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 int) int {205 cb := purego.NewCallback(func(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 int) int {
159 fmt.Println(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15)206 fmt.Println(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15)
M sys_unix_386.s +82 -74
@@ -29,9 +29,10 @@ TEXT callbackasm1(SB), NOSPLIT|NOFRAME, $0
2929 // 0-15: saved callee-saved registers (BX, SI, DI, BP)
3030 // 16-19: saved callback index
3131 // 20-23: saved return address
32- // 24-35: callbackArgs struct (12 bytes)
33- // 36-291: copy of C arguments (256 bytes for 64 args, matching callbackMaxFrame)
34- // Total: 292 bytes, round up to 304 for alignment
32+ // 24-47: callbackArgs struct (24 bytes: index, args, result[4],
33+ // matching Go's callbackArgs with room for 64-bit returns)
34+ // 48-303: copy of C arguments (256 bytes for 64 args, matching callbackMaxFrame)
35+ // Total: 304 bytes, already 16-byte aligned
3536 SUBL $304, SP
3637
3738 // Save callee-saved registers
@@ -46,148 +47,152 @@ TEXT callbackasm1(SB), NOSPLIT|NOFRAME, $0
4647
4748 // Copy C arguments from original stack location to our frame
4849 // Original args start at 304+4(SP) = 308(SP) (past our frame + original return addr)
49- // Copy to our frame at 36(SP)
50+ // Copy to our frame at 48(SP)
5051 // Copy 64 arguments (256 bytes, matching callbackMaxFrame = 64 * ptrSize)
5152 MOVL 308(SP), AX
52- MOVL AX, 36(SP)
53+ MOVL AX, 48(SP)
5354 MOVL 312(SP), AX
54- MOVL AX, 40(SP)
55+ MOVL AX, 52(SP)
5556 MOVL 316(SP), AX
56- MOVL AX, 44(SP)
57+ MOVL AX, 56(SP)
5758 MOVL 320(SP), AX
58- MOVL AX, 48(SP)
59+ MOVL AX, 60(SP)
5960 MOVL 324(SP), AX
60- MOVL AX, 52(SP)
61+ MOVL AX, 64(SP)
6162 MOVL 328(SP), AX
62- MOVL AX, 56(SP)
63+ MOVL AX, 68(SP)
6364 MOVL 332(SP), AX
64- MOVL AX, 60(SP)
65+ MOVL AX, 72(SP)
6566 MOVL 336(SP), AX
66- MOVL AX, 64(SP)
67+ MOVL AX, 76(SP)
6768 MOVL 340(SP), AX
68- MOVL AX, 68(SP)
69+ MOVL AX, 80(SP)
6970 MOVL 344(SP), AX
70- MOVL AX, 72(SP)
71+ MOVL AX, 84(SP)
7172 MOVL 348(SP), AX
72- MOVL AX, 76(SP)
73+ MOVL AX, 88(SP)
7374 MOVL 352(SP), AX
74- MOVL AX, 80(SP)
75+ MOVL AX, 92(SP)
7576 MOVL 356(SP), AX
76- MOVL AX, 84(SP)
77+ MOVL AX, 96(SP)
7778 MOVL 360(SP), AX
78- MOVL AX, 88(SP)
79+ MOVL AX, 100(SP)
7980 MOVL 364(SP), AX
80- MOVL AX, 92(SP)
81+ MOVL AX, 104(SP)
8182 MOVL 368(SP), AX
82- MOVL AX, 96(SP)
83+ MOVL AX, 108(SP)
8384 MOVL 372(SP), AX
84- MOVL AX, 100(SP)
85+ MOVL AX, 112(SP)
8586 MOVL 376(SP), AX
86- MOVL AX, 104(SP)
87+ MOVL AX, 116(SP)
8788 MOVL 380(SP), AX
88- MOVL AX, 108(SP)
89+ MOVL AX, 120(SP)
8990 MOVL 384(SP), AX
90- MOVL AX, 112(SP)
91+ MOVL AX, 124(SP)
9192 MOVL 388(SP), AX
92- MOVL AX, 116(SP)
93+ MOVL AX, 128(SP)
9394 MOVL 392(SP), AX
94- MOVL AX, 120(SP)
95+ MOVL AX, 132(SP)
9596 MOVL 396(SP), AX
96- MOVL AX, 124(SP)
97+ MOVL AX, 136(SP)
9798 MOVL 400(SP), AX
98- MOVL AX, 128(SP)
99+ MOVL AX, 140(SP)
99100 MOVL 404(SP), AX
100- MOVL AX, 132(SP)
101+ MOVL AX, 144(SP)
101102 MOVL 408(SP), AX
102- MOVL AX, 136(SP)
103+ MOVL AX, 148(SP)
103104 MOVL 412(SP), AX
104- MOVL AX, 140(SP)
105+ MOVL AX, 152(SP)
105106 MOVL 416(SP), AX
106- MOVL AX, 144(SP)
107+ MOVL AX, 156(SP)
107108 MOVL 420(SP), AX
108- MOVL AX, 148(SP)
109+ MOVL AX, 160(SP)
109110 MOVL 424(SP), AX
110- MOVL AX, 152(SP)
111+ MOVL AX, 164(SP)
111112 MOVL 428(SP), AX
112- MOVL AX, 156(SP)
113+ MOVL AX, 168(SP)
113114 MOVL 432(SP), AX
114- MOVL AX, 160(SP)
115+ MOVL AX, 172(SP)
115116 MOVL 436(SP), AX
116- MOVL AX, 164(SP)
117+ MOVL AX, 176(SP)
117118 MOVL 440(SP), AX
118- MOVL AX, 168(SP)
119+ MOVL AX, 180(SP)
119120 MOVL 444(SP), AX
120- MOVL AX, 172(SP)
121+ MOVL AX, 184(SP)
121122 MOVL 448(SP), AX
122- MOVL AX, 176(SP)
123+ MOVL AX, 188(SP)
123124 MOVL 452(SP), AX
124- MOVL AX, 180(SP)
125+ MOVL AX, 192(SP)
125126 MOVL 456(SP), AX
126- MOVL AX, 184(SP)
127+ MOVL AX, 196(SP)
127128 MOVL 460(SP), AX
128- MOVL AX, 188(SP)
129+ MOVL AX, 200(SP)
129130 MOVL 464(SP), AX
130- MOVL AX, 192(SP)
131+ MOVL AX, 204(SP)
131132 MOVL 468(SP), AX
132- MOVL AX, 196(SP)
133+ MOVL AX, 208(SP)
133134 MOVL 472(SP), AX
134- MOVL AX, 200(SP)
135+ MOVL AX, 212(SP)
135136 MOVL 476(SP), AX
136- MOVL AX, 204(SP)
137+ MOVL AX, 216(SP)
137138 MOVL 480(SP), AX
138- MOVL AX, 208(SP)
139+ MOVL AX, 220(SP)
139140 MOVL 484(SP), AX
140- MOVL AX, 212(SP)
141+ MOVL AX, 224(SP)
141142 MOVL 488(SP), AX
142- MOVL AX, 216(SP)
143+ MOVL AX, 228(SP)
143144 MOVL 492(SP), AX
144- MOVL AX, 220(SP)
145+ MOVL AX, 232(SP)
145146 MOVL 496(SP), AX
146- MOVL AX, 224(SP)
147+ MOVL AX, 236(SP)
147148 MOVL 500(SP), AX
148- MOVL AX, 228(SP)
149+ MOVL AX, 240(SP)
149150 MOVL 504(SP), AX
150- MOVL AX, 232(SP)
151+ MOVL AX, 244(SP)
151152 MOVL 508(SP), AX
152- MOVL AX, 236(SP)
153+ MOVL AX, 248(SP)
153154 MOVL 512(SP), AX
154- MOVL AX, 240(SP)
155+ MOVL AX, 252(SP)
155156 MOVL 516(SP), AX
156- MOVL AX, 244(SP)
157+ MOVL AX, 256(SP)
157158 MOVL 520(SP), AX
158- MOVL AX, 248(SP)
159+ MOVL AX, 260(SP)
159160 MOVL 524(SP), AX
160- MOVL AX, 252(SP)
161+ MOVL AX, 264(SP)
161162 MOVL 528(SP), AX
162- MOVL AX, 256(SP)
163+ MOVL AX, 268(SP)
163164 MOVL 532(SP), AX
164- MOVL AX, 260(SP)
165+ MOVL AX, 272(SP)
165166 MOVL 536(SP), AX
166- MOVL AX, 264(SP)
167+ MOVL AX, 276(SP)
167168 MOVL 540(SP), AX
168- MOVL AX, 268(SP)
169+ MOVL AX, 280(SP)
169170 MOVL 544(SP), AX
170- MOVL AX, 272(SP)
171+ MOVL AX, 284(SP)
171172 MOVL 548(SP), AX
172- MOVL AX, 276(SP)
173+ MOVL AX, 288(SP)
173174 MOVL 552(SP), AX
174- MOVL AX, 280(SP)
175+ MOVL AX, 292(SP)
175176 MOVL 556(SP), AX
176- MOVL AX, 284(SP)
177+ MOVL AX, 296(SP)
177178 MOVL 560(SP), AX
178- MOVL AX, 288(SP)
179+ MOVL AX, 300(SP)
179180
180181 // Set up callbackArgs struct at 24(SP)
181182 // struct callbackArgs {
182- // index uintptr // offset 0
183- // args *byte // offset 4
184- // result uintptr // offset 8
183+ // index uintptr // offset 0
184+ // args unsafe.Pointer // offset 4
185+ // result [4]uintptr // offset 8: result[0] and result[1] hold
186+ // a 64-bit return, result[2:] are unused
185187 // }
186188 MOVL 16(SP), AX // callback index
187189 MOVL AX, 24(SP) // callbackArgs.index
188- LEAL 36(SP), AX // pointer to copied arguments
190+ LEAL 48(SP), AX // pointer to copied arguments
189191 MOVL AX, 28(SP) // callbackArgs.args
190- MOVL $0, 32(SP) // callbackArgs.result = 0
192+ MOVL $0, 32(SP) // callbackArgs.result[0] = 0
193+ MOVL $0, 36(SP) // callbackArgs.result[1] = 0
194+ MOVL $0, 40(SP) // callbackArgs.result[2] = 0
195+ MOVL $0, 44(SP) // callbackArgs.result[3] = 0
191196
192197 // Call crosscall2(fn, frame, 0, ctxt)
193198 // crosscall2 expects arguments on stack:
@@ -209,8 +214,11 @@ TEXT callbackasm1(SB), NOSPLIT|NOFRAME, $0
209214
210215 ADDL $16, SP
211216
212- // Get result from callbackArgs.result
217+ // Get result from callbackArgs.result. i386 cdecl returns 64-bit
218+ // values in EDX:EAX, so forward both halves written by
219+ // setInt64Result/setUint64Result.
213220 MOVL 32(SP), AX
221+ MOVL 36(SP), DX
214222
215223 // Restore callee-saved registers
216224 MOVL 0(SP), BX
@@ -29,9 +29,10 @@ TEXT callbackasm1(SB), NOSPLIT|NOFRAME, $0
29 // 0-15: saved callee-saved registers (BX, SI, DI, BP)29 // 0-15: saved callee-saved registers (BX, SI, DI, BP)
30 // 16-19: saved callback index30 // 16-19: saved callback index
31 // 20-23: saved return address31 // 20-23: saved return address
32- // 24-35: callbackArgs struct (12 bytes)32+ // 24-47: callbackArgs struct (24 bytes: index, args, result[4],
33- // 36-291: copy of C arguments (256 bytes for 64 args, matching callbackMaxFrame)33+ // matching Go's callbackArgs with room for 64-bit returns)
34- // Total: 292 bytes, round up to 304 for alignment34+ // 48-303: copy of C arguments (256 bytes for 64 args, matching callbackMaxFrame)
35+ // Total: 304 bytes, already 16-byte aligned
35 SUBL $304, SP36 SUBL $304, SP
36 37
37 // Save callee-saved registers38 // Save callee-saved registers
@@ -46,148 +47,152 @@ TEXT callbackasm1(SB), NOSPLIT|NOFRAME, $0
46 47
47 // Copy C arguments from original stack location to our frame48 // Copy C arguments from original stack location to our frame
48 // Original args start at 304+4(SP) = 308(SP) (past our frame + original return addr)49 // Original args start at 304+4(SP) = 308(SP) (past our frame + original return addr)
49- // Copy to our frame at 36(SP)50+ // Copy to our frame at 48(SP)
50 // Copy 64 arguments (256 bytes, matching callbackMaxFrame = 64 * ptrSize)51 // Copy 64 arguments (256 bytes, matching callbackMaxFrame = 64 * ptrSize)
51 MOVL 308(SP), AX52 MOVL 308(SP), AX
52- MOVL AX, 36(SP)53+ MOVL AX, 48(SP)
53 MOVL 312(SP), AX54 MOVL 312(SP), AX
54- MOVL AX, 40(SP)55+ MOVL AX, 52(SP)
55 MOVL 316(SP), AX56 MOVL 316(SP), AX
56- MOVL AX, 44(SP)57+ MOVL AX, 56(SP)
57 MOVL 320(SP), AX58 MOVL 320(SP), AX
58- MOVL AX, 48(SP)59+ MOVL AX, 60(SP)
59 MOVL 324(SP), AX60 MOVL 324(SP), AX
60- MOVL AX, 52(SP)61+ MOVL AX, 64(SP)
61 MOVL 328(SP), AX62 MOVL 328(SP), AX
62- MOVL AX, 56(SP)63+ MOVL AX, 68(SP)
63 MOVL 332(SP), AX64 MOVL 332(SP), AX
64- MOVL AX, 60(SP)65+ MOVL AX, 72(SP)
65 MOVL 336(SP), AX66 MOVL 336(SP), AX
66- MOVL AX, 64(SP)67+ MOVL AX, 76(SP)
67 MOVL 340(SP), AX68 MOVL 340(SP), AX
68- MOVL AX, 68(SP)69+ MOVL AX, 80(SP)
69 MOVL 344(SP), AX70 MOVL 344(SP), AX
70- MOVL AX, 72(SP)71+ MOVL AX, 84(SP)
71 MOVL 348(SP), AX72 MOVL 348(SP), AX
72- MOVL AX, 76(SP)73+ MOVL AX, 88(SP)
73 MOVL 352(SP), AX74 MOVL 352(SP), AX
74- MOVL AX, 80(SP)75+ MOVL AX, 92(SP)
75 MOVL 356(SP), AX76 MOVL 356(SP), AX
76- MOVL AX, 84(SP)77+ MOVL AX, 96(SP)
77 MOVL 360(SP), AX78 MOVL 360(SP), AX
78- MOVL AX, 88(SP)79+ MOVL AX, 100(SP)
79 MOVL 364(SP), AX80 MOVL 364(SP), AX
80- MOVL AX, 92(SP)81+ MOVL AX, 104(SP)
81 MOVL 368(SP), AX82 MOVL 368(SP), AX
82- MOVL AX, 96(SP)83+ MOVL AX, 108(SP)
83 MOVL 372(SP), AX84 MOVL 372(SP), AX
84- MOVL AX, 100(SP)85+ MOVL AX, 112(SP)
85 MOVL 376(SP), AX86 MOVL 376(SP), AX
86- MOVL AX, 104(SP)87+ MOVL AX, 116(SP)
87 MOVL 380(SP), AX88 MOVL 380(SP), AX
88- MOVL AX, 108(SP)89+ MOVL AX, 120(SP)
89 MOVL 384(SP), AX90 MOVL 384(SP), AX
90- MOVL AX, 112(SP)91+ MOVL AX, 124(SP)
91 MOVL 388(SP), AX92 MOVL 388(SP), AX
92- MOVL AX, 116(SP)93+ MOVL AX, 128(SP)
93 MOVL 392(SP), AX94 MOVL 392(SP), AX
94- MOVL AX, 120(SP)95+ MOVL AX, 132(SP)
95 MOVL 396(SP), AX96 MOVL 396(SP), AX
96- MOVL AX, 124(SP)97+ MOVL AX, 136(SP)
97 MOVL 400(SP), AX98 MOVL 400(SP), AX
98- MOVL AX, 128(SP)99+ MOVL AX, 140(SP)
99 MOVL 404(SP), AX100 MOVL 404(SP), AX
100- MOVL AX, 132(SP)101+ MOVL AX, 144(SP)
101 MOVL 408(SP), AX102 MOVL 408(SP), AX
102- MOVL AX, 136(SP)103+ MOVL AX, 148(SP)
103 MOVL 412(SP), AX104 MOVL 412(SP), AX
104- MOVL AX, 140(SP)105+ MOVL AX, 152(SP)
105 MOVL 416(SP), AX106 MOVL 416(SP), AX
106- MOVL AX, 144(SP)107+ MOVL AX, 156(SP)
107 MOVL 420(SP), AX108 MOVL 420(SP), AX
108- MOVL AX, 148(SP)109+ MOVL AX, 160(SP)
109 MOVL 424(SP), AX110 MOVL 424(SP), AX
110- MOVL AX, 152(SP)111+ MOVL AX, 164(SP)
111 MOVL 428(SP), AX112 MOVL 428(SP), AX
112- MOVL AX, 156(SP)113+ MOVL AX, 168(SP)
113 MOVL 432(SP), AX114 MOVL 432(SP), AX
114- MOVL AX, 160(SP)115+ MOVL AX, 172(SP)
115 MOVL 436(SP), AX116 MOVL 436(SP), AX
116- MOVL AX, 164(SP)117+ MOVL AX, 176(SP)
117 MOVL 440(SP), AX118 MOVL 440(SP), AX
118- MOVL AX, 168(SP)119+ MOVL AX, 180(SP)
119 MOVL 444(SP), AX120 MOVL 444(SP), AX
120- MOVL AX, 172(SP)121+ MOVL AX, 184(SP)
121 MOVL 448(SP), AX122 MOVL 448(SP), AX
122- MOVL AX, 176(SP)123+ MOVL AX, 188(SP)
123 MOVL 452(SP), AX124 MOVL 452(SP), AX
124- MOVL AX, 180(SP)125+ MOVL AX, 192(SP)
125 MOVL 456(SP), AX126 MOVL 456(SP), AX
126- MOVL AX, 184(SP)127+ MOVL AX, 196(SP)
127 MOVL 460(SP), AX128 MOVL 460(SP), AX
128- MOVL AX, 188(SP)129+ MOVL AX, 200(SP)
129 MOVL 464(SP), AX130 MOVL 464(SP), AX
130- MOVL AX, 192(SP)131+ MOVL AX, 204(SP)
131 MOVL 468(SP), AX132 MOVL 468(SP), AX
132- MOVL AX, 196(SP)133+ MOVL AX, 208(SP)
133 MOVL 472(SP), AX134 MOVL 472(SP), AX
134- MOVL AX, 200(SP)135+ MOVL AX, 212(SP)
135 MOVL 476(SP), AX136 MOVL 476(SP), AX
136- MOVL AX, 204(SP)137+ MOVL AX, 216(SP)
137 MOVL 480(SP), AX138 MOVL 480(SP), AX
138- MOVL AX, 208(SP)139+ MOVL AX, 220(SP)
139 MOVL 484(SP), AX140 MOVL 484(SP), AX
140- MOVL AX, 212(SP)141+ MOVL AX, 224(SP)
141 MOVL 488(SP), AX142 MOVL 488(SP), AX
142- MOVL AX, 216(SP)143+ MOVL AX, 228(SP)
143 MOVL 492(SP), AX144 MOVL 492(SP), AX
144- MOVL AX, 220(SP)145+ MOVL AX, 232(SP)
145 MOVL 496(SP), AX146 MOVL 496(SP), AX
146- MOVL AX, 224(SP)147+ MOVL AX, 236(SP)
147 MOVL 500(SP), AX148 MOVL 500(SP), AX
148- MOVL AX, 228(SP)149+ MOVL AX, 240(SP)
149 MOVL 504(SP), AX150 MOVL 504(SP), AX
150- MOVL AX, 232(SP)151+ MOVL AX, 244(SP)
151 MOVL 508(SP), AX152 MOVL 508(SP), AX
152- MOVL AX, 236(SP)153+ MOVL AX, 248(SP)
153 MOVL 512(SP), AX154 MOVL 512(SP), AX
154- MOVL AX, 240(SP)155+ MOVL AX, 252(SP)
155 MOVL 516(SP), AX156 MOVL 516(SP), AX
156- MOVL AX, 244(SP)157+ MOVL AX, 256(SP)
157 MOVL 520(SP), AX158 MOVL 520(SP), AX
158- MOVL AX, 248(SP)159+ MOVL AX, 260(SP)
159 MOVL 524(SP), AX160 MOVL 524(SP), AX
160- MOVL AX, 252(SP)161+ MOVL AX, 264(SP)
161 MOVL 528(SP), AX162 MOVL 528(SP), AX
162- MOVL AX, 256(SP)163+ MOVL AX, 268(SP)
163 MOVL 532(SP), AX164 MOVL 532(SP), AX
164- MOVL AX, 260(SP)165+ MOVL AX, 272(SP)
165 MOVL 536(SP), AX166 MOVL 536(SP), AX
166- MOVL AX, 264(SP)167+ MOVL AX, 276(SP)
167 MOVL 540(SP), AX168 MOVL 540(SP), AX
168- MOVL AX, 268(SP)169+ MOVL AX, 280(SP)
169 MOVL 544(SP), AX170 MOVL 544(SP), AX
170- MOVL AX, 272(SP)171+ MOVL AX, 284(SP)
171 MOVL 548(SP), AX172 MOVL 548(SP), AX
172- MOVL AX, 276(SP)173+ MOVL AX, 288(SP)
173 MOVL 552(SP), AX174 MOVL 552(SP), AX
174- MOVL AX, 280(SP)175+ MOVL AX, 292(SP)
175 MOVL 556(SP), AX176 MOVL 556(SP), AX
176- MOVL AX, 284(SP)177+ MOVL AX, 296(SP)
177 MOVL 560(SP), AX178 MOVL 560(SP), AX
178- MOVL AX, 288(SP)179+ MOVL AX, 300(SP)
179 180
180 // Set up callbackArgs struct at 24(SP)181 // Set up callbackArgs struct at 24(SP)
181 // struct callbackArgs {182 // struct callbackArgs {
182- // index uintptr // offset 0183+ // index uintptr // offset 0
183- // args *byte // offset 4184+ // args unsafe.Pointer // offset 4
184- // result uintptr // offset 8185+ // result [4]uintptr // offset 8: result[0] and result[1] hold
186+ // a 64-bit return, result[2:] are unused
185 // }187 // }
186 MOVL 16(SP), AX // callback index188 MOVL 16(SP), AX // callback index
187 MOVL AX, 24(SP) // callbackArgs.index189 MOVL AX, 24(SP) // callbackArgs.index
188- LEAL 36(SP), AX // pointer to copied arguments190+ LEAL 48(SP), AX // pointer to copied arguments
189 MOVL AX, 28(SP) // callbackArgs.args191 MOVL AX, 28(SP) // callbackArgs.args
190- MOVL $0, 32(SP) // callbackArgs.result = 0192+ MOVL $0, 32(SP) // callbackArgs.result[0] = 0
193+ MOVL $0, 36(SP) // callbackArgs.result[1] = 0
194+ MOVL $0, 40(SP) // callbackArgs.result[2] = 0
195+ MOVL $0, 44(SP) // callbackArgs.result[3] = 0
191 196
192 // Call crosscall2(fn, frame, 0, ctxt)197 // Call crosscall2(fn, frame, 0, ctxt)
193 // crosscall2 expects arguments on stack:198 // crosscall2 expects arguments on stack:
@@ -209,8 +214,11 @@ TEXT callbackasm1(SB), NOSPLIT|NOFRAME, $0
209 214
210 ADDL $16, SP215 ADDL $16, SP
211 216
212- // Get result from callbackArgs.result217+ // Get result from callbackArgs.result. i386 cdecl returns 64-bit
218+ // values in EDX:EAX, so forward both halves written by
219+ // setInt64Result/setUint64Result.
213 MOVL 32(SP), AX220 MOVL 32(SP), AX
221+ MOVL 36(SP), DX
214 222
215 // Restore callee-saved registers223 // Restore callee-saved registers
216 MOVL 0(SP), BX224 MOVL 0(SP), BX

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