wincallback.go raw

   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  
  10  package main
  11  
  12  import (
  13  	"bytes"
  14  	"fmt"
  15  	"os"
  16  )
  17  
  18  const maxCallback = 2000
  19  
  20  func 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  
  36  TEXT 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  
  48  func 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  
  64  TEXT 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  
  75  func 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  
  91  TEXT 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  
 103  func 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  
 119  TEXT 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  
 131  func 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  
 147  TEXT 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  
 159  func 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  
 175  TEXT callbackasm(SB), NOSPLIT|NOFRAME, $0
 176  `)
 177  	for i := 0; i < maxCallback; i++ {
 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  
 187  func 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  
 207  TEXT callbackasm(SB), NOSPLIT|NOFRAME, $0
 208  `)
 209  	for i := 0; i < maxCallback; i++ {
 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  
 224  func 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  
 241  TEXT callbackasm(SB), NOSPLIT|NOFRAME, $0
 242  `)
 243  	for i := 0; i < maxCallback; i++ {
 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  
 253  func main() {
 254  	genasm386()
 255  	genasmAmd64()
 256  	genasmArm()
 257  	genasmArm64()
 258  	genasmLoong64()
 259  	genasmPpc64le()
 260  	genasmRiscv64()
 261  	genasmS390x()
 262  }
 263