1// Copyright 2014 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5//go:build ignore
6
7// Generate Windows callback assembly file.
8// This was copied from the Go repository and modified to generate non-Windows assembly files.
9
10package main
11
12import (
13 "bytes"
14 "fmt"
15 "os"
16)
17
18const maxCallback = 2000
19
20func genasm386() {
21 var buf bytes.Buffer
22
23 buf.WriteString(`// Code generated by wincallback.go using 'go generate'. DO NOT EDIT.
24
25//go:build linux
26
27// External code calls into callbackasm at an offset corresponding
28// to the callback index. Callbackasm is a table of MOVL and JMP instructions.
29// The MOVL instruction loads CX with the callback index, and the
30// JMP instruction branches to callbackasm1.
31// callbackasm1 takes the callback index from CX and
32// indexes into an array that stores information about each callback.
33// It then calls the Go implementation for that callback.
34#include "textflag.h"
35
36TEXT callbackasm(SB), NOSPLIT|NOFRAME, $0
37`)
38 for i := range maxCallback {
39 fmt.Fprintf(&buf, "\tMOVL $%d, CX\n", i)
40 buf.WriteString("\tJMP callbackasm1(SB)\n")
41 }
42 if err := os.WriteFile("zcallback_386.s", buf.Bytes(), 0644); err != nil {
43 fmt.Fprintf(os.Stderr, "wincallback: %s\n", err)
44 os.Exit(2)
45 }
46}
47
48func genasmAmd64() {
49 var buf bytes.Buffer
50
51 buf.WriteString(`// Code generated by wincallback.go using 'go generate'. DO NOT EDIT.
52
53//go:build darwin || freebsd || linux || netbsd
54
55// runtime·callbackasm is called by external code to
56// execute Go implemented callback function. It is not
57// called from the start, instead runtime·compilecallback
58// always returns address into runtime·callbackasm offset
59// appropriately so different callbacks start with different
60// CALL instruction in runtime·callbackasm. This determines
61// which Go callback function is executed later on.
62#include "textflag.h"
63
64TEXT callbackasm(SB), NOSPLIT|NOFRAME, $0
65`)
66 for range maxCallback {
67 buf.WriteString("\tCALL callbackasm1(SB)\n")
68 }
69 if err := os.WriteFile("zcallback_amd64.s", buf.Bytes(), 0644); err != nil {
70 fmt.Fprintf(os.Stderr, "wincallback: %s\n", err)
71 os.Exit(2)
72 }
73}
74
75func genasmArm() {
76 var buf bytes.Buffer
77
78 buf.WriteString(`// Code generated by wincallback.go using 'go generate'. DO NOT EDIT.
79
80//go:build linux
81
82// External code calls into callbackasm at an offset corresponding
83// to the callback index. Callbackasm is a table of MOVW and B instructions.
84// The MOVW instruction loads R12 with the callback index, and the
85// B instruction branches to callbackasm1.
86// callbackasm1 takes the callback index from R12 and
87// indexes into an array that stores information about each callback.
88// It then calls the Go implementation for that callback.
89#include "textflag.h"
90
91TEXT callbackasm(SB), NOSPLIT|NOFRAME, $0
92`)
93 for i := range maxCallback {
94 fmt.Fprintf(&buf, "\tMOVW $%d, R12\n", i)
95 buf.WriteString("\tB callbackasm1(SB)\n")
96 }
97 if err := os.WriteFile("zcallback_arm.s", buf.Bytes(), 0644); err != nil {
98 fmt.Fprintf(os.Stderr, "wincallback: %s\n", err)
99 os.Exit(2)
100 }
101}
102
103func genasmArm64() {
104 var buf bytes.Buffer
105
106 buf.WriteString(`// Code generated by wincallback.go using 'go generate'. DO NOT EDIT.
107
108//go:build darwin || freebsd || linux || netbsd
109
110// External code calls into callbackasm at an offset corresponding
111// to the callback index. Callbackasm is a table of MOV and B instructions.
112// The MOV instruction loads R12 with the callback index, and the
113// B instruction branches to callbackasm1.
114// callbackasm1 takes the callback index from R12 and
115// indexes into an array that stores information about each callback.
116// It then calls the Go implementation for that callback.
117#include "textflag.h"
118
119TEXT callbackasm(SB), NOSPLIT|NOFRAME, $0
120`)
121 for i := range maxCallback {
122 fmt.Fprintf(&buf, "\tMOVD $%d, R12\n", i)
123 buf.WriteString("\tB callbackasm1(SB)\n")
124 }
125 if err := os.WriteFile("zcallback_arm64.s", buf.Bytes(), 0644); err != nil {
126 fmt.Fprintf(os.Stderr, "wincallback: %s\n", err)
127 os.Exit(2)
128 }
129}
130
131func genasmLoong64() {
132 var buf bytes.Buffer
133
134 buf.WriteString(`// Code generated by wincallback.go using 'go generate'. DO NOT EDIT.
135
136//go:build darwin || freebsd || linux || netbsd
137
138// External code calls into callbackasm at an offset corresponding
139// to the callback index. Callbackasm is a table of MOVV and JMP instructions.
140// The MOVV instruction loads R12 with the callback index, and the
141// JMP instruction branches to callbackasm1.
142// callbackasm1 takes the callback index from R12 and
143// indexes into an array that stores information about each callback.
144// It then calls the Go implementation for that callback.
145#include "textflag.h"
146
147TEXT callbackasm(SB), NOSPLIT|NOFRAME, $0
148`)
149 for i := range maxCallback {
150 fmt.Fprintf(&buf, "\tMOVV $%d, R12\n", i)
151 buf.WriteString("\tJMP callbackasm1(SB)\n")
152 }
153 if err := os.WriteFile("zcallback_loong64.s", buf.Bytes(), 0644); err != nil {
154 fmt.Fprintf(os.Stderr, "wincallback: %s\n", err)
155 os.Exit(2)
156 }
157}
158
159func genasmPpc64le() {
160 var buf bytes.Buffer
161
162 buf.WriteString(`// Code generated by wincallback.go using 'go generate'. DO NOT EDIT.
163
164//go:build linux
165
166// External code calls into callbackasm at an offset corresponding
167// to the callback index. Callbackasm is a table of MOVD and BR instructions.
168// The MOVD instruction loads R11 with the callback index, and the
169// BR instruction branches to callbackasm1.
170// callbackasm1 takes the callback index from R11 and
171// indexes into an array that stores information about each callback.
172// It then calls the Go implementation for that callback.
173#include "textflag.h"
174
175TEXT callbackasm(SB), NOSPLIT|NOFRAME, $0
176`)
177 for i := range maxCallback {
178 fmt.Fprintf(&buf, "\tMOVD $%d, R11\n", i)
179 buf.WriteString("\tBR callbackasm1(SB)\n")
180 }
181 if err := os.WriteFile("zcallback_ppc64le.s", buf.Bytes(), 0644); err != nil {
182 fmt.Fprintf(os.Stderr, "wincallback: %s\n", err)
183 os.Exit(2)
184 }
185}
186
187func genasmRiscv64() {
188 var buf bytes.Buffer
189
190 buf.WriteString(`// Code generated by wincallback.go using 'go generate'. DO NOT EDIT.
191
192//go:build darwin || freebsd || linux || netbsd
193
194// External code calls into callbackasm at an offset corresponding
195// to the callback index. Callbackasm is a table of MOV and JMP instructions.
196// Since Go 1.26, MOV instructions with immediate values lower than or equal to 32
197// are encoded in 2 bytes rather than 4 bytes, which breaks the assumption that each
198// callback entry is 8 bytes long. Therefore, for callback indices less than or equal to 32,
199// add a PCALIGN directive to align the next instruction to an 8-byte boundary.
200// The MOV instruction loads X7 with the callback index, and the
201// JMP instruction branches to callbackasm1.
202// callbackasm1 takes the callback index from X7 and
203// indexes into an array that stores information about each callback.
204// It then calls the Go implementation for that callback.
205#include "textflag.h"
206
207TEXT callbackasm(SB), NOSPLIT|NOFRAME, $0
208`)
209 for i := range maxCallback {
210 space := " "
211 if i <= 32 {
212 fmt.Fprintf(&buf, "\tPCALIGN $8\n")
213 space = " "
214 }
215 fmt.Fprintf(&buf, "\tMOV%s$%d, X7\n", space, i)
216 fmt.Fprintf(&buf, "\tJMP%scallbackasm1(SB)\n", space)
217 }
218 if err := os.WriteFile("zcallback_riscv64.s", buf.Bytes(), 0644); err != nil {
219 fmt.Fprintf(os.Stderr, "wincallback: %s\n", err)
220 os.Exit(2)
221 }
222}
223
224func genasmS390x() {
225 var buf bytes.Buffer
226
227 buf.WriteString(`// Code generated by wincallback.go using 'go generate'. DO NOT EDIT.
228
229//go:build linux
230
231// External code calls into callbackasm at an offset corresponding
232// to the callback index. Callbackasm is a table of MOVD and BR instructions.
233// The MOVD instruction loads R0 with the callback index, and the
234// BR instruction branches to callbackasm1.
235// callbackasm1 takes the callback index from R0 and
236// indexes into an array that stores information about each callback.
237// It then calls the Go implementation for that callback.
238// NOTE: We use R0 instead of R11 because R11 is callee-saved on S390X.
239#include "textflag.h"
240
241TEXT callbackasm(SB), NOSPLIT|NOFRAME, $0
242`)
243 for i := range maxCallback {
244 fmt.Fprintf(&buf, "\tMOVD $%d, R0\n", i)
245 buf.WriteString("\tBR callbackasm1(SB)\n")
246 }
247 if err := os.WriteFile("zcallback_s390x.s", buf.Bytes(), 0644); err != nil {
248 fmt.Fprintf(os.Stderr, "wincallback: %s\n", err)
249 os.Exit(2)
250 }
251}
252
253func main() {
254 genasm386()
255 genasmAmd64()
256 genasmArm()
257 genasmArm64()
258 genasmLoong64()
259 genasmPpc64le()
260 genasmRiscv64()
261 genasmS390x()
262}