fix(asm): treat the arm64 $-8 frame as frameless and encode the RET forms
Assisted-by: GLM 5.3 Flash
This commit is contained in:
1 parent
d853432dba
commit
f20aa156d0
2 files changed
+52
-11
No files matched your search
@@ -396,7 +396,7 @@ func encodeARM64Instr(instr *ast.Instr, pc int, offsets map[string]int, fi arm64
|
||||
// Pseudo-instructions and special cases first.
|
||||
switch mnem {
|
||||
case "RET":
|
||||
return arm64Return(fi), nil
|
||||
return arm64RetInstr(fi, ops, relocs), nil
|
||||
case "NOP", "NOOP":
|
||||
return a64wordLE(a64NOP), nil
|
||||
case "UNDEF":
|
||||
|
||||
+51
-10
@@ -87,18 +87,28 @@ func arm64ComputeFrame(t *ast.Text) arm64FrameInfo {
|
||||
if fi.frame != 0 || !fi.leaf {
|
||||
fi.autosize = fi.frame + 8 // space for the saved LR
|
||||
// The toolchain always adds an extrasize: 8 when the total leaves a
|
||||
// 16-byte alignment gap, another 16 when already aligned.
|
||||
switch fi.autosize % 16 {
|
||||
case 8:
|
||||
fi.autosize += 8
|
||||
case 0:
|
||||
fi.autosize += 16
|
||||
default:
|
||||
// The toolchain rejects unaligned frames; round up so such
|
||||
// sources still assemble.
|
||||
fi.autosize += 16 - (fi.autosize % 16)
|
||||
// 16-byte alignment gap, another 16 when already aligned. An
|
||||
// autosize of zero (the $-8 convention included) is frameless and
|
||||
// takes neither.
|
||||
if fi.autosize != 0 {
|
||||
switch fi.autosize % 16 {
|
||||
case 8:
|
||||
fi.autosize += 8
|
||||
case 0:
|
||||
fi.autosize += 16
|
||||
default:
|
||||
// The toolchain rejects unaligned frames; round up so such
|
||||
// sources still assemble.
|
||||
fi.autosize += 16 - (fi.autosize % 16)
|
||||
}
|
||||
}
|
||||
}
|
||||
if fi.autosize == 0 {
|
||||
// The NOFRAME shape: the toolchain forces the leaf mark on any
|
||||
// autosize-zero function (calls included), so nothing saves LR and
|
||||
// no stack-split guard runs.
|
||||
fi.leaf = true
|
||||
}
|
||||
switch {
|
||||
case fi.noSplit:
|
||||
case fi.autosize < stackSmall && fi.leaf:
|
||||
@@ -301,6 +311,37 @@ func arm64Return(fi arm64FrameInfo) []byte {
|
||||
return a64WordsLE(ws...)
|
||||
}
|
||||
|
||||
// arm64RetInstr encodes a RET. The plain form runs the frame epilogue and
|
||||
// branches to LR; RET Rn runs the epilogue and branches to the register
|
||||
// (asm7.go case 78); RET sym(SB) runs the epilogue and branches to the
|
||||
// symbol with the call relocation, the toolchain's retJMP tail call.
|
||||
func arm64RetInstr(fi arm64FrameInfo, ops []*ast.Operand, relocs *[]Reloc) []byte {
|
||||
out := arm64Return(fi)
|
||||
if len(ops) != 1 {
|
||||
return out
|
||||
}
|
||||
op := ops[0]
|
||||
switch {
|
||||
case op.Addr.Sym != nil && op.Addr.Sym.Pseudo == "" && op.Addr.Base == "" && op.Addr.Index == "":
|
||||
if rn := arm64RegNum(op.Addr.Sym.Name); rn >= 0 {
|
||||
// The operand form replaces the default BR LR word.
|
||||
return append(out[:len(out)-4], a64wordLE(0xd65f0000|uint32(rn)<<5)...)
|
||||
}
|
||||
case op.Addr.Sym != nil && op.Addr.Sym.Pseudo == "SB" && op.Addr.Base == "" && op.Addr.Index == "":
|
||||
if relocs != nil {
|
||||
*relocs = append(*relocs, Reloc{
|
||||
Off: 0,
|
||||
After: 4,
|
||||
Name: op.Addr.Sym.Name,
|
||||
Addend: op.Addr.Sym.Offset,
|
||||
Kind: RelArm64Branch,
|
||||
})
|
||||
}
|
||||
return append(out[:len(out)-4], a64wordLE(0x14000000)...) // B sym(SB)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// arm64PrologueSpadjPC returns the function-relative byte offset where the
|
||||
// prologue has finished decrementing SP (the delta becomes autosize).
|
||||
func arm64PrologueSpadjPC(fi arm64FrameInfo) int {
|
||||
|
||||
Reference in new issue
Block a user