github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/obj/x86/pcrelative_test.go (about)

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