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, err := os.MkdirTemp("", "progedittest")
87 if err != nil {
88 t.Fatal(err)
89 }
90 defer os.RemoveAll(tmpdir)
91 tmpfile, err := os.Create(filepath.Join(tmpdir, "input.s"))
92 if err != nil {
93 t.Fatal(err)
94 }
95 defer tmpfile.Close()
96 _, err = tmpfile.WriteString(s)
97 if err != nil {
98 t.Fatal(err)
99 }
100 cmd := testenv.Command(t,
101 testenv.GoToolPath(t), "tool", "asm", "-S", "-dynlink",
102 "-o", filepath.Join(tmpdir, "output.6"), tmpfile.Name())
103
104 cmd.Env = append(os.Environ(),
105 "GOARCH=amd64", "GOOS=linux", "GOPATH="+filepath.Join(tmpdir, "_gopath"))
106 asmout, err := cmd.CombinedOutput()
107 if err != nil {
108 t.Fatalf("error %s output %s", err, asmout)
109 }
110 return asmout
111 }
112
113 func parseOutput(t *testing.T, td *ParsedTestData, asmout []byte) {
114 scanner := bufio.NewScanner(bytes.NewReader(asmout))
115 marker := regexp.MustCompile(`MOVQ \$([0-9]+), AX`)
116 mark := -1
117 td.marker_to_output = make(map[int][]string)
118 for scanner.Scan() {
119 line := scanner.Text()
120 if line[0] != '\t' {
121 continue
122 }
123 parts := strings.SplitN(line, "\t", 3)
124 if len(parts) != 3 {
125 continue
126 }
127 n := normalize(parts[2])
128 mark_matches := marker.FindStringSubmatch(n)
129 if mark_matches != nil {
130 mark, _ = strconv.Atoi(mark_matches[1])
131 if _, ok := td.marker_to_input[mark]; !ok {
132 t.Fatalf("unexpected marker %d", mark)
133 }
134 } else if mark != -1 {
135 td.marker_to_output[mark] = append(td.marker_to_output[mark], n)
136 }
137 }
138 }
139
140 func TestDynlink(t *testing.T) {
141 testenv.MustHaveGoBuild(t)
142
143 if os.Getenv("GOHOSTARCH") != "" {
144
145
146
147 t.Skip("skipping when GOHOSTARCH is set")
148 }
149
150 testdata := parseTestData(t)
151 asmout := asmOutput(t, testdata.input)
152 parseOutput(t, testdata, asmout)
153 for _, m := range testdata.marks {
154 i := strings.Join(testdata.marker_to_input[m], "; ")
155 o := strings.Join(testdata.marker_to_output[m], "; ")
156 e := strings.Join(testdata.marker_to_expected[m], "; ")
157 if o != e {
158 if o == i {
159 t.Errorf("%s was unchanged; should have become %s", i, e)
160 } else {
161 t.Errorf("%s became %s; should have become %s", i, o, e)
162 }
163 } else if i != e {
164 t.Logf("%s correctly became %s", i, o)
165 }
166 }
167 }
168
View as plain text