diff options
Diffstat (limited to 'src/cmd/internal/obj/x86/obj6_test.go')
-rw-r--r-- | src/cmd/internal/obj/x86/obj6_test.go | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/src/cmd/internal/obj/x86/obj6_test.go b/src/cmd/internal/obj/x86/obj6_test.go new file mode 100644 index 0000000..f9dd584 --- /dev/null +++ b/src/cmd/internal/obj/x86/obj6_test.go @@ -0,0 +1,165 @@ +package x86_test + +import ( + "bufio" + "bytes" + "fmt" + "internal/testenv" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "regexp" + "strconv" + "strings" + "testing" +) + +const testdata = ` +MOVQ AX, AX -> MOVQ AX, AX + +LEAQ name(SB), AX -> MOVQ name@GOT(SB), AX +LEAQ name+10(SB), AX -> MOVQ name@GOT(SB), AX; LEAQ 10(AX), AX +MOVQ $name(SB), AX -> MOVQ name@GOT(SB), AX +MOVQ $name+10(SB), AX -> MOVQ name@GOT(SB), AX; LEAQ 10(AX), AX + +MOVQ name(SB), AX -> NOP; MOVQ name@GOT(SB), R15; MOVQ (R15), AX +MOVQ name+10(SB), AX -> NOP; MOVQ name@GOT(SB), R15; MOVQ 10(R15), AX + +CMPQ name(SB), $0 -> NOP; MOVQ name@GOT(SB), R15; CMPQ (R15), $0 + +MOVQ $1, name(SB) -> NOP; MOVQ name@GOT(SB), R15; MOVQ $1, (R15) +MOVQ $1, name+10(SB) -> NOP; MOVQ name@GOT(SB), R15; MOVQ $1, 10(R15) +` + +type ParsedTestData struct { + input string + marks []int + marker_to_input map[int][]string + marker_to_expected map[int][]string + marker_to_output map[int][]string +} + +const marker_start = 1234 + +func parseTestData(t *testing.T) *ParsedTestData { + r := &ParsedTestData{} + scanner := bufio.NewScanner(strings.NewReader(testdata)) + r.marker_to_input = make(map[int][]string) + r.marker_to_expected = make(map[int][]string) + marker := marker_start + input_insns := []string{} + for scanner.Scan() { + line := scanner.Text() + if len(strings.TrimSpace(line)) == 0 { + continue + } + parts := strings.Split(line, "->") + if len(parts) != 2 { + t.Fatalf("malformed line %v", line) + } + r.marks = append(r.marks, marker) + marker_insn := fmt.Sprintf("MOVQ $%d, AX", marker) + input_insns = append(input_insns, marker_insn) + for _, input_insn := range strings.Split(parts[0], ";") { + input_insns = append(input_insns, input_insn) + r.marker_to_input[marker] = append(r.marker_to_input[marker], normalize(input_insn)) + } + for _, expected_insn := range strings.Split(parts[1], ";") { + r.marker_to_expected[marker] = append(r.marker_to_expected[marker], normalize(expected_insn)) + } + marker++ + } + r.input = "TEXT ·foo(SB),$0\n" + strings.Join(input_insns, "\n") + "\n" + return r +} + +var spaces_re *regexp.Regexp = regexp.MustCompile(`\s+`) + +func normalize(s string) string { + return spaces_re.ReplaceAllLiteralString(strings.TrimSpace(s), " ") +} + +func asmOutput(t *testing.T, s string) []byte { + tmpdir, err := ioutil.TempDir("", "progedittest") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmpdir) + tmpfile, err := os.Create(filepath.Join(tmpdir, "input.s")) + if err != nil { + t.Fatal(err) + } + defer tmpfile.Close() + _, err = tmpfile.WriteString(s) + if err != nil { + t.Fatal(err) + } + cmd := exec.Command( + testenv.GoToolPath(t), "tool", "asm", "-S", "-dynlink", + "-o", filepath.Join(tmpdir, "output.6"), tmpfile.Name()) + + cmd.Env = append(os.Environ(), + "GOARCH=amd64", "GOOS=linux", "GOPATH="+filepath.Join(tmpdir, "_gopath")) + asmout, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("error %s output %s", err, asmout) + } + return asmout +} + +func parseOutput(t *testing.T, td *ParsedTestData, asmout []byte) { + scanner := bufio.NewScanner(bytes.NewReader(asmout)) + marker := regexp.MustCompile(`MOVQ \$([0-9]+), AX`) + mark := -1 + td.marker_to_output = make(map[int][]string) + for scanner.Scan() { + line := scanner.Text() + if line[0] != '\t' { + continue + } + parts := strings.SplitN(line, "\t", 3) + if len(parts) != 3 { + continue + } + n := normalize(parts[2]) + mark_matches := marker.FindStringSubmatch(n) + if mark_matches != nil { + mark, _ = strconv.Atoi(mark_matches[1]) + if _, ok := td.marker_to_input[mark]; !ok { + t.Fatalf("unexpected marker %d", mark) + } + } else if mark != -1 { + td.marker_to_output[mark] = append(td.marker_to_output[mark], n) + } + } +} + +func TestDynlink(t *testing.T) { + testenv.MustHaveGoBuild(t) + + if os.Getenv("GOHOSTARCH") != "" { + // TODO: make this work? It was failing due to the + // GOARCH= filtering above and skipping is easiest for + // now. + t.Skip("skipping when GOHOSTARCH is set") + } + + testdata := parseTestData(t) + asmout := asmOutput(t, testdata.input) + parseOutput(t, testdata, asmout) + for _, m := range testdata.marks { + i := strings.Join(testdata.marker_to_input[m], "; ") + o := strings.Join(testdata.marker_to_output[m], "; ") + e := strings.Join(testdata.marker_to_expected[m], "; ") + if o != e { + if o == i { + t.Errorf("%s was unchanged; should have become %s", i, e) + } else { + t.Errorf("%s became %s; should have become %s", i, o, e) + } + } else if i != e { + t.Logf("%s correctly became %s", i, o) + } + } +} |