Skip to content

Commit 4ebc651

Browse files
Mark RyanTocarIP
Mark Ryan
authored andcommitted
cmd/asm: Fix EVEX RIP-relative addressing
AVX-512 instructions that use RIP-relative addressing and require the R bit of the EVEX prefix to be zero, i.e., instructions that use Z8-Z15 or Z24-Z31, are incorrectly encoded by the assembler. The reason is that the location of the offset at which the relative address is to be written is incorrectly computed when the R bit is clear. For example, VMOVUPS bInitX<>+0(SB), Z0 encodes correctly to 62 f1 7c 48 10 05 66 e9 02 00 whereas VMOVUPS bInitX<>+0(SB), Z8 encodes incorrectly to 62 71 7c 48 10 05 00 56 e9 02 00 Note the extra zero byte between the ModR/M byte (05) and the relative address starting with 56. This error results in the first byte of the following instruction being overwritten and typically, a program crash. This commit fixes the issue in the same way that is fixed for VEX encoded instructions, by simply not incrementing the offset for EVEX instructions. Existing test code created for a similar VEX encoding issue (19518) has been modified to also test for the issue addressed by this commit. Fixes #31001 Change-Id: If84719ac22ebb5fb3c42ff96cd32b611ad497414 Reviewed-on: https://go-review.googlesource.com/c/go/+/168562 Run-TryBot: Ilya Tocar <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Ilya Tocar <[email protected]>
1 parent 3aacfce commit 4ebc651

File tree

2 files changed

+19
-16
lines changed

2 files changed

+19
-16
lines changed

src/cmd/internal/obj/x86/asm6.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -5374,7 +5374,7 @@ func (ab *AsmBuf) asmins(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog) {
53745374
if int64(r.Off) < p.Pc {
53755375
break
53765376
}
5377-
if ab.rexflag != 0 && !ab.vexflag {
5377+
if ab.rexflag != 0 && !ab.vexflag && !ab.evexflag {
53785378
r.Off++
53795379
}
53805380
if r.Type == objabi.R_PCREL {

src/cmd/internal/obj/x86/issue19518_test.go renamed to src/cmd/internal/obj/x86/pcrelative_test.go

+18-15
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package x86_test
66

77
import (
88
"bytes"
9+
"fmt"
910
"internal/testenv"
1011
"io/ioutil"
1112
"os"
@@ -17,7 +18,7 @@ import (
1718
const asmData = `
1819
GLOBL zeros<>(SB),8,$64
1920
TEXT ·testASM(SB),4,$0
20-
VMOVDQU zeros<>(SB), Y8 // PC relative relocation is off by 1, for Y8-15
21+
VMOVUPS zeros<>(SB), %s // PC relative relocation is off by 1, for Y8-Y15, Z8-15 and Z24-Z31
2122
RET
2223
`
2324

@@ -31,13 +32,13 @@ func main() {
3132
}
3233
`
3334

34-
func objdumpOutput(t *testing.T) []byte {
35-
tmpdir, err := ioutil.TempDir("", "19518")
35+
func objdumpOutput(t *testing.T, mname, source string) []byte {
36+
tmpdir, err := ioutil.TempDir("", mname)
3637
if err != nil {
3738
t.Fatal(err)
3839
}
3940
defer os.RemoveAll(tmpdir)
40-
err = ioutil.WriteFile(filepath.Join(tmpdir, "go.mod"), []byte("module issue19518\n"), 0666)
41+
err = ioutil.WriteFile(filepath.Join(tmpdir, "go.mod"), []byte(fmt.Sprintf("module %s\n", mname)), 0666)
4142
if err != nil {
4243
t.Fatal(err)
4344
}
@@ -46,7 +47,7 @@ func objdumpOutput(t *testing.T) []byte {
4647
t.Fatal(err)
4748
}
4849
defer tmpfile.Close()
49-
_, err = tmpfile.WriteString(asmData)
50+
_, err = tmpfile.WriteString(source)
5051
if err != nil {
5152
t.Fatal(err)
5253
}
@@ -85,17 +86,19 @@ func objdumpOutput(t *testing.T) []byte {
8586
return objout
8687
}
8788

88-
func TestVexPCrelative(t *testing.T) {
89+
func TestVexEvexPCrelative(t *testing.T) {
8990
testenv.MustHaveGoBuild(t)
90-
objout := objdumpOutput(t)
91-
data := bytes.Split(objout, []byte("\n"))
92-
for idx := len(data) - 1; idx >= 0; idx-- {
93-
// OBJDUMP doesn't know about VMOVDQU,
94-
// so instead of checking that it was assembled correctly,
95-
// check that RET wasn't overwritten.
96-
if bytes.Index(data[idx], []byte("RET")) != -1 {
97-
return
91+
LOOP:
92+
for _, reg := range []string{"Y0", "Y8", "Z0", "Z8", "Z16", "Z24"} {
93+
asm := fmt.Sprintf(asmData, reg)
94+
objout := objdumpOutput(t, "pcrelative", asm)
95+
data := bytes.Split(objout, []byte("\n"))
96+
for idx := len(data) - 1; idx >= 0; idx-- {
97+
// check that RET wasn't overwritten.
98+
if bytes.Index(data[idx], []byte("RET")) != -1 {
99+
continue LOOP
100+
}
98101
}
102+
t.Errorf("VMOVUPS zeros<>(SB), %s overwrote RET", reg)
99103
}
100-
t.Fatal("RET was overwritten")
101104
}

0 commit comments

Comments
 (0)