1
2
3
4
5
6
7
8
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 && go1.12
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 }
138
View as plain text