1
2
3
4
5 package x86_test
6
7 import (
8 "bufio"
9 "bytes"
10 "fmt"
11 "internal/testenv"
12 "os"
13 "path/filepath"
14 "regexp"
15 "strconv"
16 "strings"
17 "testing"
18 )
19
20 const testdata = `
21 MOVQ AX, AX -> MOVQ AX, AX
22
23 LEAQ name(SB), AX -> MOVQ name@GOT(SB), AX
24 LEAQ name+10(SB), AX -> MOVQ name@GOT(SB), AX; LEAQ 10(AX), AX
25 MOVQ $name(SB), AX -> MOVQ name@GOT(SB), AX
26 MOVQ $name+10(SB), AX -> MOVQ name@GOT(SB), AX; LEAQ 10(AX), AX
27
28 MOVQ name(SB), AX -> NOP; MOVQ name@GOT(SB), R15; MOVQ (R15), AX
29 MOVQ name+10(SB), AX -> NOP; MOVQ name@GOT(SB), R15; MOVQ 10(R15), AX
30
31 CMPQ name(SB), $0 -> NOP; MOVQ name@GOT(SB), R15; CMPQ (R15), $0
32
33 MOVQ $1, name(SB) -> NOP; MOVQ name@GOT(SB), R15; MOVQ $1, (R15)
34 MOVQ $1, name+10(SB) -> NOP; MOVQ name@GOT(SB), R15; MOVQ $1, 10(R15)
35 `
36
37 type ParsedTestData struct {
38 input string
39 marks []int
40 marker_to_input map[int][]string
41 marker_to_expected map[int][]string
42 marker_to_output map[int][]string
43 }
44
45 const marker_start = 1234
46
47 func parseTestData(t *testing.T) *ParsedTestData {
48 r := &ParsedTestData{}
49 scanner := bufio.NewScanner(strings.NewReader(testdata))
50 r.marker_to_input = make(map[int][]string)
51 r.marker_to_expected = make(map[int][]string)
52 marker := marker_start
53 input_insns := []string{}
54 for scanner.Scan() {
55 line := scanner.Text()
56 if len(strings.TrimSpace(line)) == 0 {
57 continue
58 }
59 parts := strings.Split(line, "->")
60 if len(parts) != 2 {
61 t.Fatalf("malformed line %v", line)
62 }
63 r.marks = append(r.marks, marker)
64 marker_insn := fmt.Sprintf("MOVQ $%d, AX", marker)
65 input_insns = append(input_insns, marker_insn)
66 for _, input_insn := range strings.Split(parts[0], ";") {
67 input_insns = append(input_insns, input_insn)
68 r.marker_to_input[marker] = append(r.marker_to_input[marker], normalize(input_insn))
69 }
70 for _, expected_insn := range strings.Split(parts[1], ";") {
71 r.marker_to_expected[marker] = append(r.marker_to_expected[marker], normalize(expected_insn))
72 }
73 marker++
74 }
75 r.input = "TEXT ·foo(SB),$0\n" + strings.Join(input_insns, "\n") + "\n"
76 return r
77 }
78
79 var spaces_re *regexp.Regexp = regexp.MustCompile(`\s+`)
80
81 func normalize(s string) string {
82 return spaces_re.ReplaceAllLiteralString(strings.TrimSpace(s), " ")
83 }
84
85 func asmOutput(t *testing.T, s string) []byte {
86 tmpdir := t.TempDir()
87 tmpfile, err := os.Create(filepath.Join(tmpdir, "input.s"))
88 if err != nil {
89 t.Fatal(err)
90 }
91 defer tmpfile.Close()
92 _, err = tmpfile.WriteString(s)
93 if err != nil {
94 t.Fatal(err)
95 }
96 cmd := testenv.Command(t,
97 testenv.GoToolPath(t), "tool", "asm", "-S", "-dynlink",
98 "-o", filepath.Join(tmpdir, "output.6"), tmpfile.Name())
99
100 cmd.Env = append(os.Environ(),
101 "GOARCH=amd64", "GOOS=linux", "GOPATH="+filepath.Join(tmpdir, "_gopath"))
102 asmout, err := cmd.CombinedOutput()
103 if err != nil {
104 t.Fatalf("error %s output %s", err, asmout)
105 }
106 return asmout
107 }
108
109 func parseOutput(t *testing.T, td *ParsedTestData, asmout []byte) {
110 scanner := bufio.NewScanner(bytes.NewReader(asmout))
111 marker := regexp.MustCompile(`MOVQ \$([0-9]+), AX`)
112 mark := -1
113 td.marker_to_output = make(map[int][]string)
114 for scanner.Scan() {
115 line := scanner.Text()
116 if line[0] != '\t' {
117 continue
118 }
119 parts := strings.SplitN(line, "\t", 3)
120 if len(parts) != 3 {
121 continue
122 }
123 n := normalize(parts[2])
124 mark_matches := marker.FindStringSubmatch(n)
125 if mark_matches != nil {
126 mark, _ = strconv.Atoi(mark_matches[1])
127 if _, ok := td.marker_to_input[mark]; !ok {
128 t.Fatalf("unexpected marker %d", mark)
129 }
130 } else if mark != -1 {
131 td.marker_to_output[mark] = append(td.marker_to_output[mark], n)
132 }
133 }
134 }
135
136 func TestDynlink(t *testing.T) {
137 testenv.MustHaveGoBuild(t)
138
139 if os.Getenv("GOHOSTARCH") != "" {
140
141
142
143 t.Skip("skipping when GOHOSTARCH is set")
144 }
145
146 testdata := parseTestData(t)
147 asmout := asmOutput(t, testdata.input)
148 parseOutput(t, testdata, asmout)
149 for _, m := range testdata.marks {
150 i := strings.Join(testdata.marker_to_input[m], "; ")
151 o := strings.Join(testdata.marker_to_output[m], "; ")
152 e := strings.Join(testdata.marker_to_expected[m], "; ")
153 if o != e {
154 if o == i {
155 t.Errorf("%s was unchanged; should have become %s", i, e)
156 } else {
157 t.Errorf("%s became %s; should have become %s", i, o, e)
158 }
159 } else if i != e {
160 t.Logf("%s correctly became %s", i, o)
161 }
162 }
163 }
164
View as plain text