fix(amd64): correct guard displacements, frameless FP offsets and immediate ranges
Assisted-by: GLM 5.3
This commit is contained in:
@@ -160,6 +160,57 @@ TEXT ·loadarg(SB), NOSPLIT, $0-24
|
||||
}
|
||||
}
|
||||
|
||||
// TestAssembleFramelessCall verifies the forced base-pointer frame a $0-frame
|
||||
// function containing a CALL receives: the PUSHQ BP prologue with no stack
|
||||
// adjustment and the x+N(FP) → (N+16)(SP) translation, against the bytes the
|
||||
// Go assembler produces. The push is the frame, so the offset must not count
|
||||
// it twice.
|
||||
func TestAssembleFramelessCall(t *testing.T) {
|
||||
f, errs := parser.Parse("frameless_call_amd64.s", `
|
||||
#include "textflag.h"
|
||||
TEXT ·withcall(SB), NOSPLIT, $0-16
|
||||
MOVQ x+0(FP), AX
|
||||
CALL ·other(SB)
|
||||
MOVQ AX, ret+8(FP)
|
||||
RET
|
||||
TEXT ·other(SB), NOSPLIT, $0-0
|
||||
RET
|
||||
`)
|
||||
if len(errs) > 0 {
|
||||
t.Fatalf("parse: %v", errs)
|
||||
}
|
||||
img, err := AssembleFile(f)
|
||||
if err != nil {
|
||||
t.Fatalf("AssembleFile: %v", err)
|
||||
}
|
||||
code := append([]byte(nil), img.Code[img.Funcs[0].Offset:img.Funcs[0].Offset+img.Funcs[0].Size]...)
|
||||
for _, r := range img.Funcs[0].Relocs {
|
||||
for j := r.Off; j < r.Off+4 && j < len(code); j++ {
|
||||
code[j] = 0
|
||||
}
|
||||
}
|
||||
// From `go tool objdump` of the Go-assembled function:
|
||||
// PUSHQ BP 55
|
||||
// MOVQ SP, BP 4889e5
|
||||
// MOVQ 0x10(SP), AX 488b442410
|
||||
// CALL other e800000000
|
||||
// MOVQ AX, 0x18(SP) 4889442418
|
||||
// POPQ BP 5d
|
||||
// RET c3
|
||||
want := []byte{
|
||||
0x55,
|
||||
0x48, 0x89, 0xe5,
|
||||
0x48, 0x8b, 0x44, 0x24, 0x10,
|
||||
0xe8, 0x00, 0x00, 0x00, 0x00,
|
||||
0x48, 0x89, 0x44, 0x24, 0x18,
|
||||
0x5d,
|
||||
0xc3,
|
||||
}
|
||||
if hexBytes(code) != hexBytes(want) {
|
||||
t.Errorf("frameless CALL FP translation mismatch:\n got: %s\n want: %s", hexBytes(code), hexBytes(want))
|
||||
}
|
||||
}
|
||||
|
||||
// TestAssembleFrame verifies a function with a non-zero frame: the Go-style
|
||||
// prologue/epilogue and the x+N(FP) → (N+frame+16)(SP) translation, against
|
||||
// the bytes the Go assembler produces.
|
||||
@@ -353,6 +404,19 @@ TEXT ·pf(SB), NOSPLIT, $0
|
||||
}
|
||||
}
|
||||
|
||||
// TestAssembleBareJump checks that a zero-operand jump (which parses, because
|
||||
// the parser does not arity-check mnemonics) is rejected with an error rather
|
||||
// than panicking in the layout loop, which indexes Operands[0] before the
|
||||
// emission pass gets a chance to diagnose the arity.
|
||||
func TestAssembleBareJump(t *testing.T) {
|
||||
for _, mnem := range []string{"JE", "JMP", "JLT", "CALL"} {
|
||||
fn := firstText(t, "TEXT ·bare(SB), $16-0\n\t"+mnem+"\n")
|
||||
if _, _, err := Assemble(fn); err == nil {
|
||||
t.Errorf("%s with no operand: expected an error, got none", mnem)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestSubSPEncodings pins the prologue SUB against the bytes go tool asm
|
||||
// emits for SUBQ $size, SP: imm8 for -128..127, the imm32 form for anything
|
||||
// larger. The intermediate 129..255 range used to encode an ADD with a
|
||||
|
||||
Reference in New Issue
Block a user