1// Copyright 2017 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package x86_test 6 7import ( 8 "bytes" 9 "fmt" 10 "internal/testenv" 11 "os" 12 "path/filepath" 13 "testing" 14) 15 16const asmData = ` 17GLOBL zeros<>(SB),8,$64 18TEXT ·testASM(SB),4,$0 19VMOVUPS zeros<>(SB), %s // PC relative relocation is off by 1, for Y8-Y15, Z8-15 and Z24-Z31 20RET 21` 22 23const goData = ` 24package main 25 26func testASM() 27 28func main() { 29 testASM() 30} 31` 32 33func objdumpOutput(t *testing.T, mname, source string) []byte { 34 tmpdir, err := os.MkdirTemp("", mname) 35 if err != nil { 36 t.Fatal(err) 37 } 38 defer os.RemoveAll(tmpdir) 39 err = os.WriteFile(filepath.Join(tmpdir, "go.mod"), []byte(fmt.Sprintf("module %s\n", mname)), 0666) 40 if err != nil { 41 t.Fatal(err) 42 } 43 tmpfile, err := os.Create(filepath.Join(tmpdir, "input.s")) 44 if err != nil { 45 t.Fatal(err) 46 } 47 defer tmpfile.Close() 48 _, err = tmpfile.WriteString(source) 49 if err != nil { 50 t.Fatal(err) 51 } 52 tmpfile2, err := os.Create(filepath.Join(tmpdir, "input.go")) 53 if err != nil { 54 t.Fatal(err) 55 } 56 defer tmpfile2.Close() 57 _, err = tmpfile2.WriteString(goData) 58 if err != nil { 59 t.Fatal(err) 60 } 61 62 cmd := testenv.Command(t, 63 testenv.GoToolPath(t), "build", "-o", 64 filepath.Join(tmpdir, "output")) 65 66 cmd.Env = append(os.Environ(), 67 "GOARCH=amd64", "GOOS=linux", "GOPATH="+filepath.Join(tmpdir, "_gopath")) 68 cmd.Dir = tmpdir 69 70 out, err := cmd.CombinedOutput() 71 if err != nil { 72 t.Fatalf("error %s output %s", err, out) 73 } 74 cmd2 := testenv.Command(t, 75 testenv.GoToolPath(t), "tool", "objdump", "-s", "testASM", 76 filepath.Join(tmpdir, "output")) 77 cmd2.Env = cmd.Env 78 cmd2.Dir = tmpdir 79 objout, err := cmd2.CombinedOutput() 80 if err != nil { 81 t.Fatalf("error %s output %s", err, objout) 82 } 83 84 return objout 85} 86 87func TestVexEvexPCrelative(t *testing.T) { 88 testenv.MustHaveGoBuild(t) 89LOOP: 90 for _, reg := range []string{"Y0", "Y8", "Z0", "Z8", "Z16", "Z24"} { 91 asm := fmt.Sprintf(asmData, reg) 92 objout := objdumpOutput(t, "pcrelative", asm) 93 data := bytes.Split(objout, []byte("\n")) 94 for idx := len(data) - 1; idx >= 0; idx-- { 95 // check that RET wasn't overwritten. 96 if bytes.Contains(data[idx], []byte("RET")) { 97 if testing.Short() { 98 break LOOP 99 } 100 continue LOOP 101 } 102 } 103 t.Errorf("VMOVUPS zeros<>(SB), %s overwrote RET", reg) 104 } 105} 106