refactor(arch): extract the displacement tail and SIB builders

Assisted-by: GLM 5.3 Flash
This commit is contained in:
petrbalvin committed 2026-10-07 19:49:15 +02:00
1 parent 27ef71859b
commit 47d561b229
1 file changed
+36 -43
+36 -43
View File
@@ -183,34 +183,48 @@ func (in ExtInstr) amd64Memory(op ExtOperand, pos int) (base int, disp int64, er
return op.Reg, op.Imm, nil
}
// amd64DispTail lays the displacement bytes and their ModR/M mod field: no
// bytes at displacement zero, a disp8 when the value fits a signed byte and
// a disp32 otherwise. The force flag makes a zero displacement encode
// anyway, the mod-01 shape the RBP and R13 bases demand, whose bare r/m 101
// would otherwise address RIP-relative.
func amd64DispTail(disp int64, force bool) (mod byte, tail []byte) {
if !force && disp == 0 {
return 0, nil
}
if disp >= -128 && disp <= 127 {
return 1, []byte{byte(disp)}
}
return 2, []byte{byte(disp), byte(disp >> 8), byte(disp >> 16), byte(disp >> 24)}
}
// amd64Sib builds the SIB byte the scaled forms carry: the scale field over
// the index and the base, whose number rides the r/m field.
func amd64Sib(base, index, scale int) byte {
sib := byte(base & 7)
sib |= byte(index&7) << 3
switch scale {
case 2:
sib |= 1 << 6
case 4:
sib |= 2 << 6
case 8:
sib |= 3 << 6
}
return sib
}
// amd64EncodeMemory returns the register-form template with a base-relative
// memory operand filled in: dest and vvvv keep their register meanings, the
// ModR/M r/m field carries the base, and the high base bit rides EVEX.B as
// amd64Encode lays it. The ModR/M mod bits and the trailing SIB and
// displacement bytes follow the canonical choices the GNU assembler makes
// for the plain, unscaled SDM displacements: no displacement bytes at
// displacement zero, a disp8 when the value fits a signed byte and a disp32
// otherwise, the SIB byte 0x24 when the base is RSP or R12, whose r/m
// encoding 100 demands it, and a forced displacement on RBP and R13, whose
// mod-00 r/m encoding 101 means RIP-relative. The operand must have passed
// amd64Memory first.
// for the plain, unscaled SDM displacements, and the operand must have
// passed amd64Memory first.
func amd64EncodeMemory(b []byte, dest, vvvv, base int, disp int64) []byte {
out := amd64Encode(b, dest, vvvv, base)
rm := base & 7
var tail []byte
mod := byte(0)
switch {
case rm == 5 || disp != 0:
// RBP and R13 cannot drop the displacement: mod 00 with r/m 101
// addresses RIP-relative, not through the base.
if disp >= -128 && disp <= 127 {
mod = 1
tail = []byte{byte(disp)}
} else {
mod = 2
tail = []byte{byte(disp), byte(disp >> 8), byte(disp >> 16), byte(disp >> 24)}
}
}
mod, tail := amd64DispTail(disp, rm == 5)
if rm == 4 {
// RSP and R12 need the SIB byte: no index, base 100.
tail = append([]byte{0x24}, tail...)
@@ -247,29 +261,8 @@ func amd64EncodeScaledMemory(b []byte, dest, vvvv, base, index, scale int, disp
out[1] &^= 0x40
}
rm := base & 7
var tail []byte
mod := byte(0)
switch {
case rm == 5 || disp != 0:
if disp >= -128 && disp <= 127 {
mod = 1
tail = []byte{byte(disp)}
} else {
mod = 2
tail = []byte{byte(disp), byte(disp >> 8), byte(disp >> 16), byte(disp >> 24)}
}
}
sib := byte(rm)
sib |= byte(index&7) << 3
switch scale {
case 2:
sib |= 1 << 6
case 4:
sib |= 2 << 6
case 8:
sib |= 3 << 6
}
tail = append([]byte{sib}, tail...)
mod, tail := amd64DispTail(disp, rm == 5)
tail = append([]byte{amd64Sib(rm, index, scale)}, tail...)
out[5] = out[5]&0x38 | mod<<6 | 4
return append(out, tail...)
}