-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathgo_translate_test.go
More file actions
146 lines (134 loc) · 3.76 KB
/
Copy pathgo_translate_test.go
File metadata and controls
146 lines (134 loc) · 3.76 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package plan9asm
import (
"go/ast"
"go/parser"
"go/token"
"go/types"
"strings"
"testing"
)
func TestTranslateGoModule_UsesDeclsAndLinkname(t *testing.T) {
pkg := mustGoPackage(t, "test/pkg", `package testpkg
func Compare(a, b int) int
//go:linkname cmp runtime.cmp
func cmp(a, b int) int
`)
asm := []byte(`TEXT ·Compare(SB),NOSPLIT,$0-24
CALL runtime·cmp(SB)
MOVD $0, R0
RET
`)
tr, err := TranslateGoModule(pkg, asm, GoModuleOptions{
FileName: "compare_arm64.s",
GOARCH: "arm64",
TargetTriple: "aarch64-unknown-linux-gnu",
ResolveSym: testResolveSym("test/pkg"),
})
if err != nil {
t.Fatal(err)
}
defer tr.Module.Dispose()
if _, ok := tr.Signatures["test/pkg.Compare"]; !ok {
t.Fatalf("missing package function signature")
}
if _, ok := tr.Signatures["runtime.cmp"]; !ok {
t.Fatalf("missing go:linkname target signature")
}
if got := tr.Functions[0].ResolvedSymbol; got != "test/pkg.Compare" {
t.Fatalf("resolved symbol: got %q", got)
}
}
func TestTranslateGoModule_UsesManualSigForPlainLocalHelper(t *testing.T) {
pkg := mustGoPackage(t, "test/pkg", `package testpkg
func IndexByte(b []byte, c byte) int
`)
manualCalled := false
asm := []byte(`TEXT ·IndexByte(SB),NOSPLIT,$0-40
B indexbytebody<>(SB)
TEXT indexbytebody<>(SB),NOSPLIT,$0
MOVD $0, R0
RET
`)
tr, err := TranslateGoModule(pkg, asm, GoModuleOptions{
FileName: "indexbyte_arm64.s",
GOARCH: "arm64",
TargetTriple: "aarch64-unknown-linux-gnu",
ResolveSym: testResolveSym("test/pkg"),
ManualSig: func(resolved string) (FuncSig, bool) {
if resolved != "test/pkg.indexbytebody" {
return FuncSig{}, false
}
manualCalled = true
return FuncSig{Name: resolved, Args: []LLVMType{"{ ptr, i64, i64 }", "i8"}, Ret: I64}, true
},
})
if err != nil {
t.Fatal(err)
}
defer tr.Module.Dispose()
if !manualCalled {
t.Fatalf("manual signature callback was not used")
}
if _, ok := tr.Signatures["test/pkg.indexbytebody"]; !ok {
t.Fatalf("missing manual helper signature")
}
}
func TestTranslateGoModule_UsesManualSigExternalName(t *testing.T) {
pkg := mustGoPackage(t, "test/pkg", `package testpkg
func Call()
`)
asm := []byte(`TEXT ·Call(SB),NOSPLIT,$0-0
CALL runtime·memmove(SB)
RET
`)
for _, goarch := range []string{"amd64", "arm64"} {
t.Run(goarch, func(t *testing.T) {
tr, err := TranslateGoModule(pkg, asm, GoModuleOptions{
FileName: "call_" + goarch + ".s",
GOARCH: goarch,
ResolveSym: testResolveSym("test/pkg"),
ManualSig: func(resolved string) (FuncSig, bool) {
if resolved != "runtime.memmove" {
return FuncSig{}, false
}
return FuncSig{Name: "memmove", Args: []LLVMType{Ptr, Ptr, I64}, Ret: Ptr}, true
},
})
if err != nil {
t.Fatal(err)
}
defer tr.Module.Dispose()
ir := tr.Module.String()
if !strings.Contains(ir, "@memmove") || strings.Contains(ir, "runtime.memmove") {
t.Fatalf("manual external name not applied:\n%s", ir)
}
})
}
}
func mustGoPackage(t *testing.T, pkgPath, src string) GoPackage {
t.Helper()
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, "pkg.go", src, parser.ParseComments)
if err != nil {
t.Fatal(err)
}
conf := types.Config{}
pkg, err := conf.Check(pkgPath, fset, []*ast.File{f}, nil)
if err != nil {
t.Fatal(err)
}
return GoPackage{Path: pkgPath, Types: pkg, Syntax: []*ast.File{f}}
}
func testResolveSym(pkgPath string) func(string) string {
return func(sym string) string {
sym = goStripABISuffix(sym)
if strings.HasPrefix(sym, "·") {
return pkgPath + "." + strings.TrimPrefix(sym, "·")
}
if !strings.Contains(sym, "·") && !strings.Contains(sym, ".") && !strings.Contains(sym, "/") {
return pkgPath + "." + sym
}
sym = strings.ReplaceAll(sym, "∕", "/")
return strings.ReplaceAll(sym, "·", ".")
}
}