mkasm.mx raw

   1  // Copyright 2018 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  // mkasm.go generates assembly trampolines to call library routines from Go.
   8  // This program must be run after mksyscall.pl.
   9  package main
  10  
  11  import (
  12  	"bytes"
  13  	"fmt"
  14  	"log"
  15  	"os"
  16  )
  17  
  18  func main() {
  19  	if len(os.Args) != 3 {
  20  		log.Fatalf("Usage: %s <goos> <arch>", os.Args[0])
  21  	}
  22  	goos, arch := os.Args[1], os.Args[2]
  23  
  24  	syscallFilename := fmt.Sprintf("syscall_%s.go", goos)
  25  	syscallArchFilename := fmt.Sprintf("syscall_%s_%s.go", goos, arch)
  26  
  27  	in1, err := os.ReadFile(syscallFilename)
  28  	if err != nil {
  29  		log.Fatalf("can't open syscall file: %s", err)
  30  	}
  31  	in2, err := os.ReadFile(syscallArchFilename)
  32  	if err != nil {
  33  		log.Fatalf("can't open syscall file: %s", err)
  34  	}
  35  	in3, err := os.ReadFile("z" + syscallArchFilename)
  36  	if err != nil {
  37  		log.Fatalf("can't open syscall file: %s", err)
  38  	}
  39  	in := string(in1) + string(in2) + string(in3)
  40  
  41  	trampolines := map[string]bool{}
  42  
  43  	var out bytes.Buffer
  44  
  45  	fmt.Fprintf(&out, "// go run mkasm.go %s\n", bytes.Join(os.Args[1:], " "))
  46  	fmt.Fprintf(&out, "// Code generated by the command above; DO NOT EDIT.\n")
  47  	fmt.Fprintf(&out, "#include \"textflag.h\"\n")
  48  	for _, line := range bytes.Split(in, "\n") {
  49  		if !bytes.HasPrefix(line, "func ") || !bytes.HasSuffix(line, "_trampoline()") {
  50  			continue
  51  		}
  52  		fn := line[5 : len(line)-13]
  53  		if !trampolines[fn] {
  54  			trampolines[fn] = true
  55  			fmt.Fprintf(&out, "TEXT ยท%s_trampoline(SB),NOSPLIT,$0-0\n", fn)
  56  			if goos == "openbsd" && arch == "ppc64" {
  57  				fmt.Fprintf(&out, "\tCALL\t%s(SB)\n", fn)
  58  				fmt.Fprintf(&out, "\tRET\n")
  59  			} else {
  60  				fmt.Fprintf(&out, "\tJMP\t%s(SB)\n", fn)
  61  			}
  62  		}
  63  	}
  64  	err = os.WriteFile(fmt.Sprintf("zsyscall_%s_%s.s", goos, arch), out.Bytes(), 0644)
  65  	if err != nil {
  66  		log.Fatalf("can't write syscall file: %s", err)
  67  	}
  68  }
  69