github.com/neonyo/sys@v0.0.0-20230720094341-b1ee14be3ce8/unix/mkasm.go (about) 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 // +build ignore 7 8 // mkasm.go generates assembly trampolines to call library routines from Go. 9 // This program must be run after mksyscall.go. 10 package main 11 12 import ( 13 "bytes" 14 "fmt" 15 "io/ioutil" 16 "log" 17 "os" 18 "sort" 19 "strings" 20 ) 21 22 func archPtrSize(arch string) int { 23 switch arch { 24 case "386", "arm": 25 return 4 26 case "amd64", "arm64", "mips64", "ppc64", "riscv64": 27 return 8 28 default: 29 log.Fatalf("Unknown arch %q", arch) 30 return 0 31 } 32 } 33 34 func generateASMFile(goos, arch string, inFileNames []string, outFileName string) map[string]bool { 35 trampolines := map[string]bool{} 36 var orderedTrampolines []string 37 for _, inFileName := range inFileNames { 38 in, err := ioutil.ReadFile(inFileName) 39 if err != nil { 40 log.Fatalf("Failed to read file: %v", err) 41 } 42 for _, line := range strings.Split(string(in), "\n") { 43 const prefix = "var " 44 const suffix = "_trampoline_addr uintptr" 45 if !strings.HasPrefix(line, prefix) || !strings.HasSuffix(line, suffix) { 46 continue 47 } 48 fn := strings.TrimSuffix(strings.TrimPrefix(line, prefix), suffix) 49 if !trampolines[fn] { 50 orderedTrampolines = append(orderedTrampolines, fn) 51 trampolines[fn] = true 52 } 53 } 54 } 55 56 ptrSize := archPtrSize(arch) 57 58 var out bytes.Buffer 59 fmt.Fprintf(&out, "// go run mkasm.go %s\n", strings.Join(os.Args[1:], " ")) 60 fmt.Fprintf(&out, "// Code generated by the command above; DO NOT EDIT.\n") 61 fmt.Fprintf(&out, "\n") 62 fmt.Fprintf(&out, "#include \"textflag.h\"\n") 63 for _, fn := range orderedTrampolines { 64 fmt.Fprintf(&out, "\nTEXT %s_trampoline<>(SB),NOSPLIT,$0-0\n", fn) 65 if goos == "openbsd" && arch == "ppc64" { 66 fmt.Fprintf(&out, "\tCALL\t%s(SB)\n", fn) 67 fmt.Fprintf(&out, "\tRET\n") 68 } else { 69 fmt.Fprintf(&out, "\tJMP\t%s(SB)\n", fn) 70 } 71 fmt.Fprintf(&out, "GLOBL\t·%s_trampoline_addr(SB), RODATA, $%d\n", fn, ptrSize) 72 fmt.Fprintf(&out, "DATA\t·%s_trampoline_addr(SB)/%d, $%s_trampoline<>(SB)\n", fn, ptrSize, fn) 73 } 74 75 if err := ioutil.WriteFile(outFileName, out.Bytes(), 0644); err != nil { 76 log.Fatalf("Failed to write assembly file %q: %v", outFileName, err) 77 } 78 79 return trampolines 80 } 81 82 const darwinTestTemplate = `// go run mkasm.go %s 83 // Code generated by the command above; DO NOT EDIT. 84 85 //go:build darwin && go1.12 86 // +build darwin,go1.12 87 88 package unix 89 90 // All the _trampoline functions in zsyscall_darwin_%s.s. 91 var darwinTests = [...]darwinTest{ 92 %s} 93 ` 94 95 func writeDarwinTest(trampolines map[string]bool, fileName, arch string) { 96 var sortedTrampolines []string 97 for fn := range trampolines { 98 sortedTrampolines = append(sortedTrampolines, fn) 99 } 100 sort.Strings(sortedTrampolines) 101 102 var out bytes.Buffer 103 104 const prefix = "libc_" 105 for _, fn := range sortedTrampolines { 106 fmt.Fprintf(&out, fmt.Sprintf("\t{%q, %s_trampoline_addr},\n", strings.TrimPrefix(fn, prefix), fn)) 107 } 108 lines := out.String() 109 110 out.Reset() 111 fmt.Fprintf(&out, darwinTestTemplate, strings.Join(os.Args[1:], " "), arch, lines) 112 113 if err := ioutil.WriteFile(fileName, out.Bytes(), 0644); err != nil { 114 log.Fatalf("Failed to write test file %q: %v", fileName, err) 115 } 116 } 117 118 func main() { 119 if len(os.Args) != 3 { 120 log.Fatalf("Usage: %s <goos> <arch>", os.Args[0]) 121 } 122 goos, arch := os.Args[1], os.Args[2] 123 124 syscallFilename := fmt.Sprintf("syscall_%s.go", goos) 125 syscallArchFilename := fmt.Sprintf("syscall_%s_%s.go", goos, arch) 126 zsyscallArchFilename := fmt.Sprintf("zsyscall_%s_%s.go", goos, arch) 127 zsyscallASMFileName := fmt.Sprintf("zsyscall_%s_%s.s", goos, arch) 128 129 inFileNames := []string{ 130 syscallFilename, 131 syscallArchFilename, 132 zsyscallArchFilename, 133 } 134 135 trampolines := generateASMFile(goos, arch, inFileNames, zsyscallASMFileName) 136 137 if goos == "darwin" { 138 writeDarwinTest(trampolines, fmt.Sprintf("darwin_%s_test.go", arch), arch) 139 } 140 }