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 := 0; i < maxCallback; i++ {
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 i := 0; i < maxCallback; i++ {
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 := 0; i < maxCallback; i++ {
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 := 0; i < maxCallback; i++ {
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 := 0; i < maxCallback; i++ {
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 genasmRiscv64() {
160 var buf bytes.Buffer
161
162 buf.WriteString(`// Code generated by wincallback.go using 'go generate'. DO NOT EDIT.
163
164//go:build darwin || freebsd || linux || netbsd
165
166// External code calls into callbackasm at an offset corresponding
167// to the callback index. Callbackasm is a table of MOV and JMP instructions.
168// Since Go 1.26, MOV instructions with immediate values lower than or equal to 32
169// are encoded in 2 bytes rather than 4 bytes, which breaks the assumption that each
170// callback entry is 8 bytes long. Therefore, for callback indices less than or equal to 32,
171// add a PCALIGN directive to align the next instruction to an 8-byte boundary.
172// The MOV instruction loads X7 with the callback index, and the
173// JMP instruction branches to callbackasm1.
174// callbackasm1 takes the callback index from X7 and
175// indexes into an array that stores information about each callback.
176// It then calls the Go implementation for that callback.
177#include "textflag.h"
178
179TEXT callbackasm(SB), NOSPLIT|NOFRAME, $0
180`)
181 for i := 0; i < maxCallback; i++ {
182 space := " "
183 if i <= 32 {
184 fmt.Fprintf(&buf, "\tPCALIGN $8\n")
185 space = " "
186 }
187 fmt.Fprintf(&buf, "\tMOV%s$%d, X7\n", space, i)
188 fmt.Fprintf(&buf, "\tJMP%scallbackasm1(SB)\n", space)
189 }
190 if err := os.WriteFile("zcallback_riscv64.s", buf.Bytes(), 0644); err != nil {
191 fmt.Fprintf(os.Stderr, "wincallback: %s\n", err)
192 os.Exit(2)
193 }
194}
195
196func main() {
197 genasm386()
198 genasmAmd64()
199 genasmArm()
200 genasmArm64()
201 genasmLoong64()
202 genasmRiscv64()
203}