feat(asm): encode the amd64 and loong64 tails of the corpus testdata
Assisted-by: GLM 5.3
This commit is contained in:
+156
-2
@@ -265,7 +265,11 @@ func TestImul(t *testing.T) {
|
||||
|
||||
func TestControl(t *testing.T) {
|
||||
checkSyntax(t, "ret", "RET")
|
||||
checkSyntax(t, "nop", "NOP")
|
||||
// NOP contributes nothing on amd64, consumed whole by the toolchain as
|
||||
// a pseudo; only the bytes pin it (no decodable instruction remains).
|
||||
if code, err := Encode("NOP"); err != nil || len(code) != 0 {
|
||||
t.Errorf("NOP: bytes %x (err %v), want empty", code, err)
|
||||
}
|
||||
checkOp(t, x86asm.JMP, "JMP", Imm(0))
|
||||
checkOp(t, x86asm.CALL, "CALL", Imm(0))
|
||||
checkOp(t, x86asm.JGE, "JGE", Imm(0))
|
||||
@@ -1193,7 +1197,7 @@ func TestBookkeepingGroundTruth(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("assemble: %v", err)
|
||||
}
|
||||
want := "90c3"
|
||||
want := "c3"
|
||||
if got := hexCompact(img.Code); got != want {
|
||||
t.Errorf("body %s, want %s (the bookkeeping lines contribute nothing)", got, want)
|
||||
}
|
||||
@@ -1221,3 +1225,153 @@ func mustParse(t *testing.T, src string) *ast.File {
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
// TestCorpusTailSystem pins the system and control forms the toolchain's own
|
||||
// amd64 testdata carries, byte for byte: the one-operand IMUL, the compare
|
||||
// family, the far return, the loop, the MMX moves, the CR/DR and segment
|
||||
// register moves, the TLS pseudo-base and the 0F AE/1C/C7 controls.
|
||||
func TestCorpusTailSystem(t *testing.T) {
|
||||
regBPT := Reg{idx: 5, size: 8}
|
||||
X0, X1, X2 := vreg(t, "X0"), vreg(t, "X1"), vreg(t, "X2")
|
||||
Y1, Y2, Y7 := vreg(t, "Y1"), vreg(t, "Y2"), vreg(t, "Y7")
|
||||
X5, X20 := vreg(t, "X5"), vreg(t, "X20")
|
||||
cases := []struct {
|
||||
name string
|
||||
mnem string
|
||||
ops []Operand
|
||||
want string
|
||||
}{
|
||||
{"IMUL one-op byte", "IMULB", []Operand{DX}, "f6ea"},
|
||||
{"IMUL one-op long", "IMULL", []Operand{AX}, "f7e8"},
|
||||
{"CMPPD", "CMPPD", []Operand{X1, X2, Imm(4)}, "660fc2d104"},
|
||||
{"CMPSS", "CMPSS", []Operand{X1, X2, Imm(4)}, "f30fc2d104"},
|
||||
{"CMPPS", "CMPPS", []Operand{X1, X2, Imm(4)}, "0fc2d104"},
|
||||
{"RETFL", "RETFL", []Operand{Imm(4)}, "ca0400"},
|
||||
{"LOOP", "LOOP", []Operand{Imm(-2)}, "e2fe"},
|
||||
{"LOOPE", "LOOPE", []Operand{Imm(-2)}, "e1fe"},
|
||||
{"LOOPNE", "LOOPNE", []Operand{Imm(-2)}, "e0fe"},
|
||||
{"PADDD MMX", "PADDD", []Operand{Reg{idx: 2, size: 8, mmx: true}, Reg{idx: 1, size: 8, mmx: true}}, "0ffeca"},
|
||||
{"MOVDQ2Q", "MOVDQ2Q", []Operand{X1, Reg{idx: 1, size: 8, mmx: true}}, "f20fd6c9"},
|
||||
{"MOVNTDQ", "MOVNTDQ", []Operand{X1, Ptr(AX, 0, 16)}, "660fe708"},
|
||||
{"MOVQ mmx load", "MOVQ", []Operand{Ptr(AX, 0, 8), Reg{idx: 0, size: 8, mmx: true}}, "0f6f00"},
|
||||
{"MOVQ mmx store", "MOVQ", []Operand{Reg{idx: 0, size: 8, mmx: true}, Ptr(SI, 0, 8)}, "0f7f06"},
|
||||
{"MOVQ CR0 load", "MOVQ", []Operand{Reg{idx: 0, size: 8, ctl: 1}, AX}, "0f20c0"},
|
||||
{"MOVQ CR4 load", "MOVQ", []Operand{Reg{idx: 4, size: 8, ctl: 1}, DI}, "0f20e7"},
|
||||
{"MOVQ CR0 store", "MOVQ", []Operand{AX, Reg{idx: 0, size: 8, ctl: 1}}, "0f22c0"},
|
||||
{"MOVQ DR0 load", "MOVQ", []Operand{Reg{idx: 0, size: 8, ctl: 2}, AX}, "0f21c0"},
|
||||
{"MOVQ DR7 load", "MOVQ", []Operand{Reg{idx: 7, size: 8, ctl: 2}, SI}, "0f21fe"},
|
||||
{"PUSHQ FS", "PUSHQ", []Operand{Reg{idx: 4, size: 2, seg: 5}}, "0fa0"},
|
||||
{"PUSHQ GS", "PUSHQ", []Operand{Reg{idx: 5, size: 2, seg: 6}}, "0fa8"},
|
||||
{"POPQ FS", "POPQ", []Operand{Reg{idx: 4, size: 2, seg: 5}}, "0fa1"},
|
||||
{"POPQ GS", "POPQ", []Operand{Reg{idx: 5, size: 2, seg: 6}}, "0fa9"},
|
||||
{"ENDBR64", "ENDBR64", nil, "f30f1efa"},
|
||||
{"CLWB", "CLWB", []Operand{Ptr(BX, 0, 8)}, "660fae33"},
|
||||
{"CLDEMOTE", "CLDEMOTE", []Operand{Ptr(BX, 0, 8)}, "0f1c03"},
|
||||
{"TPAUSE", "TPAUSE", []Operand{BX}, "660faef3"},
|
||||
{"UMONITOR", "UMONITOR", []Operand{BX}, "f30faef3"},
|
||||
{"UMWAIT", "UMWAIT", []Operand{BX}, "f20faef3"},
|
||||
{"RDPID", "RDPID", []Operand{DX}, "f30fc7fa"},
|
||||
{"RDPID r11", "RDPID", []Operand{Reg{idx: 11, size: 8}}, "f3410fc7fb"},
|
||||
{"LEAL wide disp", "LEAL", []Operand{Idx(regBPT, Reg{idx: 10, size: 8}, 1, 0x8f1bbcdc, 8), regBPT}, "428dac15dcbc1b8f"},
|
||||
{"VPERMPD", "VPERMPD", []Operand{Imm(0xd8), Y7, Y7}, "c4e3fd01ffd8"},
|
||||
{"VPERMILPD", "VPERMILPD", []Operand{Imm(0xff), X1, X2}, "c4e37905d1ff"},
|
||||
{"VPERMILPS", "VPERMILPS", []Operand{Imm(0xff), X1, X2}, "c4e37904d1ff"},
|
||||
{"VROUNDPD", "VROUNDPD", []Operand{Imm(-1), X1, X2}, "c4e37909d1ff"},
|
||||
{"VROUNDPS", "VROUNDPS", []Operand{Imm(-1), Y1, Y2}, "c4e37d08d1ff"},
|
||||
{"VAESKEYGENASSIST", "VAESKEYGENASSIST", []Operand{Imm(-1), X1, X2}, "c4e379dfd1ff"},
|
||||
{"VPCMPESTRI", "VPCMPESTRI", []Operand{Imm(-1), X1, X2}, "c4e37961d1ff"},
|
||||
{"VPCMPESTRM", "VPCMPESTRM", []Operand{Imm(-1), X1, X2}, "c4e37960d1ff"},
|
||||
{"VPCMPISTRI", "VPCMPISTRI", []Operand{Imm(-1), X1, X2}, "c4e37963d1ff"},
|
||||
{"VPCMPISTRM", "VPCMPISTRM", []Operand{Imm(-1), X1, X2}, "c4e37962d1ff"},
|
||||
{"VEXTRACTPS", "VEXTRACTPS", []Operand{Imm(-1), X1, AX}, "c4e37917c8ff"},
|
||||
{"VPEXTRW", "VPEXTRW", []Operand{Imm(0xff), X1, AX}, "c4e37915c8ff"},
|
||||
{"VPBLENDVB", "VPBLENDVB", []Operand{X0, Ptr(BX, 0, 16), X1, X2}, "c4e3714c1300"},
|
||||
{"VMOVHPD load", "VMOVHPD", []Operand{Ptr(AX, 0, 8), X5, X5}, "c5d11628"},
|
||||
{"VMOVHPD load disp", "VMOVHPD", []Operand{Ptr(DX, 7, 8), X5, X5}, "c5d1166a07"},
|
||||
{"VMOVHPD store", "VMOVHPD", []Operand{X5, Ptr(AX, 0, 8)}, "c5f91728"},
|
||||
{"VMOVLPD load", "VMOVLPD", []Operand{Ptr(AX, 0, 8), X5, X5}, "c5d11228"},
|
||||
{"VMOVLPD store", "VMOVLPD", []Operand{X5, Ptr(AX, 0, 8)}, "c5f91328"},
|
||||
{"VMOVQ EVEX gpr load", "VMOVQ", []Operand{Reg{idx: 4, size: 8}, X20}, "62e1fd086ee4"},
|
||||
{"VMOVQ EVEX mem store", "VMOVQ", []Operand{X20, Ptr(AX, 0, 8)}, "62e1fd087e20"},
|
||||
{"VMOVQ EVEX mem load", "VMOVQ", []Operand{Ptr(AX, 0, 8), X20}, "62e1fd086e20"},
|
||||
}
|
||||
for _, c := range cases {
|
||||
code, err := Encode(c.mnem, c.ops...)
|
||||
if err != nil {
|
||||
t.Errorf("%s: Encode: %v", c.name, err)
|
||||
continue
|
||||
}
|
||||
if got := hexCompact(code); got != c.want {
|
||||
t.Errorf("%s: bytes %s, want %s", c.name, got, c.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestCorpusTailFileForms pins the file-level forms the toolchain's amd64
|
||||
// testdata carries: the star-marked indirect jumps, the TLS pseudo-base, the
|
||||
// paired-register shift spelling, the absolute RET and the jump to an
|
||||
// undefined static symbol (its displacement and the TLS slot offsets are
|
||||
// relocation sites, zeroed here as the kernel parity suites do).
|
||||
func TestCorpusTailFileForms(t *testing.T) {
|
||||
mask32 := func(b []byte, at int) { b[at], b[at+1], b[at+2], b[at+3] = 0, 0, 0, 0 }
|
||||
cases := []struct {
|
||||
name string
|
||||
src string
|
||||
want string // hex, with X marking a masked 32-bit relocation site
|
||||
}{
|
||||
{"star reg jump", "\tJMP *(R12)\n\tRET\n", "41ff2424c3"},
|
||||
{"star sp jump", "\tJMP *4(SP)\n\tRET\n", "ff642404c3"},
|
||||
{"star indexed jump", "\tJMP *(R12)(R13*4)\n\tRET\n", "43ff24acc3"},
|
||||
{"TLS load", "\tMOVQ (TLS), AX\n\tRET\n", "64488b0425XXXXXXXXc3"},
|
||||
{"TLS load offset", "\tMOVQ 8(TLS), DX\n\tRET\n", "64488b1425XXXXXXXXc3"},
|
||||
{"colon shift", "\tSHLL CX, R11:AX\n\tRET\n", "410fa5c3c3"},
|
||||
{"SP indexed local", "\tMOVQ foo(SP)(AX*1), BX\n\tRET\n", "488b1c04c3"},
|
||||
}
|
||||
for _, c := range cases {
|
||||
f, errs := parser.Parse("t_amd64.s", "#include \"textflag.h\"\nTEXT ·f(SB), NOSPLIT, $0\n"+c.src)
|
||||
if len(errs) > 0 {
|
||||
t.Errorf("%s: parse: %v", c.name, errs)
|
||||
continue
|
||||
}
|
||||
img, err := AssembleFile(f)
|
||||
if err != nil {
|
||||
t.Errorf("%s: assemble: %v", c.name, err)
|
||||
continue
|
||||
}
|
||||
fn := img.Funcs[0]
|
||||
code := append([]byte(nil), img.Code[fn.Offset:fn.Offset+fn.Size]...)
|
||||
if at := strings.Index(c.want, "XXXXXXXX"); at >= 0 {
|
||||
mask32(code, at/2) // the masked relocation site
|
||||
}
|
||||
if got := hexCompact(code); got != strings.ReplaceAll(c.want, "X", "0") {
|
||||
t.Errorf("%s: bytes %s, want %s", c.name, got, c.want)
|
||||
}
|
||||
}
|
||||
// JMP to an undefined static symbol and the absolute RET: their rel32
|
||||
// carries a call relocation against the symbol, masked to zero here.
|
||||
for _, c := range []struct{ name, src string }{
|
||||
{"static external jump", "\tJMP bar<>+4(SB)\n\tRET\n"},
|
||||
{"static external indexed jump", "\tJMP bar<>+4(SB)(R11*4)\n\tRET\n"},
|
||||
{"absolute ret", "\tRET\n\tRET foo(SB)\n"},
|
||||
} {
|
||||
f, errs := parser.Parse("t_amd64.s", "#include \"textflag.h\"\nTEXT ·f(SB), NOSPLIT, $0\n"+c.src)
|
||||
if len(errs) > 0 {
|
||||
t.Errorf("%s: parse: %v", c.name, errs)
|
||||
continue
|
||||
}
|
||||
img, err := AssembleFile(f)
|
||||
if err != nil {
|
||||
t.Errorf("%s: assemble: %v", c.name, err)
|
||||
continue
|
||||
}
|
||||
fn := img.Funcs[0]
|
||||
code := maskCode(append([]byte(nil), img.Code[fn.Offset:fn.Offset+fn.Size]...), fn.Relocs)
|
||||
want := "e900000000c3"
|
||||
if c.name == "absolute ret" {
|
||||
want = "c3e900000000"
|
||||
}
|
||||
if got := hexCompact(code); got != want {
|
||||
t.Errorf("%s: bytes %s, want %s", c.name, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user