fix(amd64): correct guard displacements, frameless FP offsets and immediate ranges
Assisted-by: GLM 5.3
This commit is contained in:
+28
-28
@@ -114,6 +114,11 @@ func assemble(t *ast.Text, link *linkInfo) ([]byte, []sbPatch, map[string]int, [
|
||||
if !isJumpMnemonic(mnem) || mnem == "CALL" || long[i] {
|
||||
continue
|
||||
}
|
||||
// A zero-operand jump parses; its arity is reported during
|
||||
// emission (encodeJump), so the layout must not index Operands.
|
||||
if len(s.Operands) != 1 {
|
||||
continue
|
||||
}
|
||||
name, ok := labelName(s.Operands[0])
|
||||
if !ok {
|
||||
continue // reported during emission
|
||||
@@ -137,28 +142,22 @@ func assemble(t *ast.Text, link *linkInfo) ([]byte, []sbPatch, map[string]int, [
|
||||
}
|
||||
if fi.splitClass == 2 && !guardJBlong {
|
||||
// The underflow JB sits before the CMPQ; its displacement spans
|
||||
// the rest of the guard plus the prologue and the body.
|
||||
jbLen := 2
|
||||
if guardJBlong {
|
||||
jbLen = 6
|
||||
}
|
||||
rest := fi.guardLen(guardJBlong, guardJBElong) - (9 + 3 + 7 + jbLen)
|
||||
// the rest of the guard plus the prologue and the body. The JB
|
||||
// is still the short form this branch tests (relaxing it is this
|
||||
// branch's job), so guardLen is taken with a short JB and the
|
||||
// subtraction drops the prefix and the JB's own 2 bytes.
|
||||
rest := fi.guardLen(false, guardJBElong) - (9 + 3 + 7 + 2)
|
||||
if !fits8(int64(rest + len(fi.prologue) + bodyLen)) {
|
||||
guardJBlong = true
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
// The morestack JMP returns to the function start, so its
|
||||
// displacement is the negated distance from its own end.
|
||||
if !moreJMPlong {
|
||||
jmpLen := 2
|
||||
if moreJMPlong {
|
||||
jmpLen = 5
|
||||
}
|
||||
if !fits8(-int64(guard + len(fi.prologue) + bodyLen + 5 + jmpLen)) {
|
||||
moreJMPlong = true
|
||||
changed = true
|
||||
}
|
||||
// displacement is the negated distance from its own end; while it is
|
||||
// still short, its own length is 2 bytes.
|
||||
if !moreJMPlong && !fits8(-int64(guard+len(fi.prologue)+bodyLen+5+2)) {
|
||||
moreJMPlong = true
|
||||
changed = true
|
||||
}
|
||||
if !changed {
|
||||
break
|
||||
@@ -181,7 +180,15 @@ func assemble(t *ast.Text, link *linkInfo) ([]byte, []sbPatch, map[string]int, [
|
||||
var out []byte
|
||||
var patches []sbPatch
|
||||
if fi.needSplit {
|
||||
guard, tlsPatch := buildGuard(fi, int32(len(fi.prologue)+bodyLen), int32(fi.guardLen(guardJBlong, guardJBElong)-(9+3+7+2)+len(fi.prologue)+bodyLen))
|
||||
// The JBE ends the guard, so its displacement is the prologue plus
|
||||
// the body; the underflow JB additionally spans the trailing CMPQ and
|
||||
// JBE, whose combined length is guardLen minus the prefix and the
|
||||
// JB's own length (2 short, 6 long).
|
||||
jbLen := 2
|
||||
if guardJBlong {
|
||||
jbLen = 6
|
||||
}
|
||||
guard, tlsPatch := buildGuard(fi, int32(len(fi.prologue)+bodyLen), int32(fi.guardLen(guardJBlong, guardJBElong)-(9+3+7+jbLen)+len(fi.prologue)+bodyLen))
|
||||
out = append(out, guard...)
|
||||
patches = append(patches, tlsPatch)
|
||||
}
|
||||
@@ -344,7 +351,10 @@ func computeFrame(t *ast.Text) frameInfo {
|
||||
// pass one extra slot, and the virtual SP is the hardware SP.
|
||||
fi.size = 8
|
||||
fi.useFP = true
|
||||
fi.fpAdjust = int64(fi.size) + 16 // return address + saved BP + args base
|
||||
// The push is the frame: the saved BP sits at SP+0 and the
|
||||
// return address at SP+8, so arguments begin at SP+16. Unlike
|
||||
// a SUBQ frame, the 8-byte size must not be added again.
|
||||
fi.fpAdjust = 16
|
||||
fi.spAdjust = 0
|
||||
fi.prologue = []byte{0x55, 0x48, 0x89, 0xE5} // PUSHQ BP; MOVQ SP, BP
|
||||
fi.epilogue = []byte{0x5D} // POPQ BP
|
||||
@@ -426,16 +436,6 @@ func (fi frameInfo) guardLen(jbLong, jbeLong bool) int {
|
||||
}
|
||||
}
|
||||
|
||||
// moreLen returns the byte length of the trailing morestack block: the CALL
|
||||
// (always rel32) plus the JMP back to the function start.
|
||||
func moreLen(jmpLong bool) int {
|
||||
jmp := 2
|
||||
if jmpLong {
|
||||
jmp = 5
|
||||
}
|
||||
return 5 + jmp
|
||||
}
|
||||
|
||||
// buildGuard emits the stack-split guard prefix. jbeDisp and jbDisp are the
|
||||
// already-computed displacements of the conditional branches that jump to the
|
||||
// morestack block (unused in classes without them). The TLS load carries a
|
||||
|
||||
Reference in New Issue
Block a user