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