-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcallback_asm.go
More file actions
180 lines (176 loc) · 7.56 KB
/
Copy pathcallback_asm.go
File metadata and controls
180 lines (176 loc) · 7.56 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
// This file is a combined work.
//
// Portions of the callback assembly templates are adapted from Ebitengine
// PureGo v0.10.1 (Apache-2.0), audited against commit
// eaff005fcda6dae0d855da9c6ee3efb7e775ddad. The amd64 register-save sequence
// also derives from Go runtime code (BSD-3-Clause). C2Go modifications to this
// isolated file are made available under the same combined terms.
//
// Copyright 2022-2023 The Ebitengine Authors.
// Copyright 2021 The Go Authors.
// Modified by the c2go project in 2026 to emit per-callback trampolines with
// C2Go-specific callback frames and multi-word return handling.
// See NOTICE, THIRD_PARTY_NOTICES.md, and LICENSES/.
//
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
package main
import (
"fmt"
"strings"
)
// emitCallbackAsmArm64 emits the arm64 cdecl trampolines. Mirrors purego's
// callbackasm1 (spill F0..F7 then R0..R7 into the args region), but burns the
// converter + destFn into the cbFrame instead of a slot index.
func emitCallbackAsmArm64(cbs []Callback) string {
var a strings.Builder
a.WriteString("// Code generated by c2go-bind. DO NOT EDIT.\n")
a.WriteString("// Portions adapted from Ebitengine PureGo v0.10.1.\n")
a.WriteString("// Copyright 2023 The Ebitengine Authors. Licensed under Apache-2.0.\n")
a.WriteString("// Modified by the c2go project in 2026 for per-callback trampolines,\n")
a.WriteString("// c2go-specific callback frames, and multi-word return handling.\n")
a.WriteString("// Keep this notice and distribute the applicable third-party license text.\n")
a.WriteString("//go:build !windows\n\n")
a.WriteString("#include \"textflag.h\"\n\n")
for _, c := range cbs {
fmt.Fprintf(&a, "TEXT ·%s(SB), NOSPLIT|NOFRAME, $0\n", c.Tramp)
a.WriteString("\tSUB $(16*8), RSP, R14\n")
a.WriteString("\tFSTPD (F0, F1), (0*8)(R14)\n")
a.WriteString("\tFSTPD (F2, F3), (2*8)(R14)\n")
a.WriteString("\tFSTPD (F4, F5), (4*8)(R14)\n")
a.WriteString("\tFSTPD (F6, F7), (6*8)(R14)\n")
a.WriteString("\tSTP (R0, R1), (8*8)(R14)\n")
a.WriteString("\tSTP (R2, R3), (10*8)(R14)\n")
a.WriteString("\tSTP (R4, R5), (12*8)(R14)\n")
a.WriteString("\tSTP (R6, R7), (14*8)(R14)\n")
a.WriteString("\tSUB $208, RSP\n")
a.WriteString("\tSTP (R27, R30), 0(RSP)\n")
fmt.Fprintf(&a, "\tMOVD $·%s(SB), R1\n", c.Converter)
a.WriteString("\tMOVD R1, 16(RSP)\n")
fmt.Fprintf(&a, "\tMOVD $%s(SB), R1\n", c.TargetAsmSymbol)
a.WriteString("\tMOVD R1, 24(RSP)\n")
a.WriteString("\tMOVD R14, 32(RSP)\n")
a.WriteString("\tMOVD ZR, 40(RSP)\n")
a.WriteString("\tMOVD ·c2go_cbentry_fn(SB), R0\n")
a.WriteString("\tADD $16, RSP, R1\n")
a.WriteString("\tMOVD ZR, R3\n")
a.WriteString("\tBL crosscall2(SB)\n")
// Read the destFn's result words into native return registers. A single
// word goes to both R0 and F0 (the C ABI return register selects the
// right one). A multi-word homogeneous struct return (ret_words) fills
// consecutive int (R0,R1) or float (F0,F1) return registers.
if len(c.RetWords) <= 1 {
a.WriteString("\tMOVD 40(RSP), R0\n")
a.WriteString("\tFMOVD 40(RSP), F0\n")
} else {
intRegs := []string{"R0", "R1", "R2", "R3"}
fltRegs := []string{"F0", "F1", "F2", "F3"}
ii, fi := 0, 0
for k, cls := range c.RetWords {
off := 40 + k*8
if cls == "float" {
fmt.Fprintf(&a, "\tFMOVD %d(RSP), %s\n", off, fltRegs[fi])
fi++
} else {
fmt.Fprintf(&a, "\tMOVD %d(RSP), %s\n", off, intRegs[ii])
ii++
}
}
}
a.WriteString("\tLDP 0(RSP), (R27, R30)\n")
a.WriteString("\tADD $208, RSP\n")
a.WriteString("\tRET\n\n")
}
return a.String()
}
// emitCallbackAsmAmd64 emits the amd64 cdecl trampolines. The host->ABI0
// register save (PUSH_REGS_HOST_TO_ABI0, SysV: BX/BP/R12-R15) is inlined to
// avoid an abi_amd64.h include in the generated package. The 88-byte cbFrame
// allocation (24 cgocallback args + 56 cbFrame + 8 pad) flips SP to 16-byte
// alignment for the crosscall2 SysV call.
func emitCallbackAsmAmd64(cbs []Callback) string {
var a strings.Builder
a.WriteString("// Code generated by c2go-bind. DO NOT EDIT.\n")
a.WriteString("// Portions adapted from Ebitengine PureGo v0.10.1.\n")
a.WriteString("// Copyright 2022 The Ebitengine Authors. Licensed under Apache-2.0.\n")
a.WriteString("// The register-save sequence derives from Go runtime code.\n")
a.WriteString("// Copyright 2021 The Go Authors. Licensed under BSD-3-Clause.\n")
a.WriteString("// Modified by the c2go project in 2026 for per-callback trampolines,\n")
a.WriteString("// c2go-specific callback frames, and multi-word return handling.\n")
a.WriteString("// Keep this notice and distribute the applicable third-party license texts.\n")
a.WriteString("//go:build !windows\n\n")
a.WriteString("#include \"textflag.h\"\n\n")
for _, c := range cbs {
fmt.Fprintf(&a, "TEXT ·%s(SB), NOSPLIT|NOFRAME, $0\n", c.Tramp)
a.WriteString("\tADJSP $14*8, SP\n")
a.WriteString("\tMOVSD X0, (0*8)(SP)\n")
a.WriteString("\tMOVSD X1, (1*8)(SP)\n")
a.WriteString("\tMOVSD X2, (2*8)(SP)\n")
a.WriteString("\tMOVSD X3, (3*8)(SP)\n")
a.WriteString("\tMOVSD X4, (4*8)(SP)\n")
a.WriteString("\tMOVSD X5, (5*8)(SP)\n")
a.WriteString("\tMOVSD X6, (6*8)(SP)\n")
a.WriteString("\tMOVSD X7, (7*8)(SP)\n")
a.WriteString("\tMOVQ DI, (8*8)(SP)\n")
a.WriteString("\tMOVQ SI, (9*8)(SP)\n")
a.WriteString("\tMOVQ DX, (10*8)(SP)\n")
a.WriteString("\tMOVQ CX, (11*8)(SP)\n")
a.WriteString("\tMOVQ R8, (12*8)(SP)\n")
a.WriteString("\tMOVQ R9, (13*8)(SP)\n")
a.WriteString("\tMOVQ SP, R8\n")
// inline PUSH_REGS_HOST_TO_ABI0 (SysV): save BX/BP/R12-R15
a.WriteString("\tADJSP $(6*8), SP\n")
a.WriteString("\tMOVQ BP, (5*8)(SP)\n")
a.WriteString("\tLEAQ (5*8)(SP), BP\n")
a.WriteString("\tMOVQ BX, (0*8)(SP)\n")
a.WriteString("\tMOVQ R12, (1*8)(SP)\n")
a.WriteString("\tMOVQ R13, (2*8)(SP)\n")
a.WriteString("\tMOVQ R14, (3*8)(SP)\n")
a.WriteString("\tMOVQ R15, (4*8)(SP)\n")
a.WriteString("\tSUBQ $88, SP\n")
fmt.Fprintf(&a, "\tMOVQ $·%s(SB), AX\n", c.Converter)
a.WriteString("\tMOVQ AX, (24+0)(SP)\n")
fmt.Fprintf(&a, "\tMOVQ $%s(SB), AX\n", c.TargetAsmSymbol)
a.WriteString("\tMOVQ AX, (24+8)(SP)\n")
a.WriteString("\tMOVQ R8, (24+16)(SP)\n")
a.WriteString("\tMOVQ $0, (24+24)(SP)\n")
a.WriteString("\tLEAQ 24(SP), AX\n")
a.WriteString("\tMOVQ ·c2go_cbentry_fn(SB), DI\n")
a.WriteString("\tMOVQ AX, SI\n")
a.WriteString("\tMOVQ $0, CX\n")
a.WriteString("\tCALL crosscall2(SB)\n")
// Read the destFn's result words into native return registers. A single
// word goes to both AX and X0 (the C ABI return register selects). A
// multi-word homogeneous struct return (ret_words) fills consecutive
// INTEGER (AX,DX) or SSE (X0,X1) return registers.
if len(c.RetWords) <= 1 {
a.WriteString("\tMOVQ (24+24)(SP), AX\n")
a.WriteString("\tMOVSD (24+24)(SP), X0\n")
} else {
intRegs := []string{"AX", "DX"}
fltRegs := []string{"X0", "X1"}
ii, fi := 0, 0
for k, cls := range c.RetWords {
off := 24 + 24 + k*8
if cls == "float" {
fmt.Fprintf(&a, "\tMOVSD %d(SP), %s\n", off, fltRegs[fi])
fi++
} else {
fmt.Fprintf(&a, "\tMOVQ %d(SP), %s\n", off, intRegs[ii])
ii++
}
}
}
a.WriteString("\tADDQ $88, SP\n")
// inline POP_REGS_HOST_TO_ABI0 (SysV)
a.WriteString("\tMOVQ (0*8)(SP), BX\n")
a.WriteString("\tMOVQ (1*8)(SP), R12\n")
a.WriteString("\tMOVQ (2*8)(SP), R13\n")
a.WriteString("\tMOVQ (3*8)(SP), R14\n")
a.WriteString("\tMOVQ (4*8)(SP), R15\n")
a.WriteString("\tMOVQ (5*8)(SP), BP\n")
a.WriteString("\tADJSP $-(6*8), SP\n")
a.WriteString("\tADJSP $-14*8, SP\n")
a.WriteString("\tRET\n\n")
}
return a.String()
}