fix(asm): settle the byte-form width from the register operands
The suffixed scalar families derived the operand width from the mnemonic alone, so a byte-spelled register under the L spelling or no suffix at all encoded the widened form: XADDL DL, DL emitted 0F C1 where the byte form is 0F C0, CMPL AL, $7 emitted the 32-bit immediate form where the AL form is 3C 07, and CRC32 DL, R11 widened past the F0 byte opcode. operandWidth now reconciles the suffix with the operands: a byte register (AL, DL, R8B, ...) forces the 8-bit form, which is the text the toolchain's own disassembly prints for those encodings, while the W and Q spellings never ride a byte register and are refused as go tool asm refuses them (MOVQ AL, AX). The shift count and the two- and three-operand IMUL forms stay out of the reconciliation, and the byte accumulator short forms now belong to the AL spelling alone, matching the toolchain's division (ADDB $3, AX is 80 c0 03, TESTB $7, AX is f6 c0 07). Assisted-by: GLM 5.3
This commit is contained in:
1 parent
33e7fdac98
commit
98a562d8b3
3 files changed
+110
-5
No files matched your search
+18
-1
@@ -257,6 +257,19 @@ func (e *enc) encode(mnem string, ops []Operand) error {
|
||||
}
|
||||
|
||||
base, size := splitSize(upper)
|
||||
// The scalar families that own byte forms settle the width against the
|
||||
// register operands here, before the unsuffixed 64-bit default applies,
|
||||
// so a literal Q suffix stays distinguishable from no suffix at all
|
||||
// (CRC32 DL, R11 is the byte form; CRC32Q DL, R11 is a conflict).
|
||||
if byteFormBase[base] {
|
||||
w, err := operandWidth(mnem, size, widthOperands(base, ops))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if w != 0 {
|
||||
size = w
|
||||
}
|
||||
}
|
||||
if size == 0 {
|
||||
size = 8 // default operand size in 64-bit mode (e.g. PUSHQ)
|
||||
}
|
||||
@@ -306,8 +319,12 @@ func (e *enc) encode(mnem string, ops []Operand) error {
|
||||
case "MOV":
|
||||
return e.encodeMov(ops, size)
|
||||
// MOVD is the Go assembler's alias of MOVQ: the same byte forms, 64-bit
|
||||
// REX.W and all.
|
||||
// REX.W and all. The alias takes no byte register either, the same
|
||||
// conflict rule the Q-suffixed spelling answers to.
|
||||
case "MOVD":
|
||||
if _, err := operandWidth(mnem, 8, ops); err != nil {
|
||||
return err
|
||||
}
|
||||
return e.encodeMov(ops, 8)
|
||||
case "ADD", "SUB", "AND", "OR", "XOR", "CMP", "ADC", "SBB":
|
||||
return e.encodeALU(aluOp[base], ops, size)
|
||||
|
||||
Reference in new issue
Block a user