w6a: MOVB REX for SI/DI/BP/SP; LEAQ/CALL shapes err; honest diag lengths
Three w6a defects, one component. MOVB with an SP/BP/SI/DI register operand encoded AH/CH/DH/BH -- emit_rex suppressed the bare 0x40 that selects SPL/BPL/SIL/DIL (the comment claimed "we always emit REX"; encode probe: `MOVB SI,(AX)` -> `88 30` = %dh). emit_rex8 forces the byte for low-byte codes 4-7; no current w6c output emits those shapes, so all existing objects are unchanged. LEAQ and CALL unsupported operand shapes fell through with zero bytes and no errs++ (every MOV arm reports); both now err. Every hardcoded os.write diagnostic length in the wwstage was one byte short (truncating the newline/quote); all converted to the .len idiom so the length cannot drift again.
This commit is contained in:
@@ -147,6 +147,19 @@ emit_rex(Asm *a, int regbit, int rmbit, int w)
|
||||
if (b != 0x40 || w) a_emit_byte(a, b);
|
||||
}
|
||||
|
||||
/* 8-bit register operands: SPL/BPL/SIL/DIL exist only WITH a REX
|
||||
* prefix — bare, codes 4-7 select AH/CH/DH/BH. Force the 0x40 byte
|
||||
* when the named r8 is one of them. */
|
||||
static void
|
||||
emit_rex8(Asm *a, int regbit, int rmbit, int r8)
|
||||
{
|
||||
u8 b = 0x40;
|
||||
if (regbit) b |= 0x04;
|
||||
if (rmbit) b |= 0x01;
|
||||
if (b != 0x40 || (!rhi(r8) && rcode(r8) >= 4))
|
||||
a_emit_byte(a, b);
|
||||
}
|
||||
|
||||
/* Special-cases SP (needs SIB) and BP (forces disp). */
|
||||
static void
|
||||
emit_modrm_mem(Asm *a, int reg_field, int base, i64 disp)
|
||||
@@ -521,17 +534,20 @@ a_encode(Asm *a)
|
||||
}
|
||||
break;
|
||||
case A_MOVB:
|
||||
/* MOV r/m8, r8 — 88 /r. No REX.W. We always emit REX
|
||||
* to allow access to SIL/DIL/BPL/SPL. */
|
||||
/* MOV r/m8, r8 — 88 /r. No REX.W. emit_rex8 forces
|
||||
* the bare REX so SI/DI/BP/SP name SIL/DIL/BPL/SPL,
|
||||
* never AH/CH/DH/BH. */
|
||||
if (p->from.type >= D_AX && p->from.type <= D_R15
|
||||
&& p->to.type == D_INDIR) {
|
||||
emit_rex(a, rhi(p->from.type), rhi(p->to.reg), 0);
|
||||
emit_rex8(a, rhi(p->from.type), rhi(p->to.reg),
|
||||
p->from.type);
|
||||
a_emit_byte(a, 0x88);
|
||||
emit_modrm_mem(a, rcode(p->from.type),
|
||||
p->to.reg, p->to.offset);
|
||||
} else if (p->from.type == D_INDIR
|
||||
&& p->to.type >= D_AX && p->to.type <= D_R15) {
|
||||
emit_rex(a, rhi(p->to.type), rhi(p->from.reg), 0);
|
||||
emit_rex8(a, rhi(p->to.type), rhi(p->from.reg),
|
||||
p->to.type);
|
||||
a_emit_byte(a, 0x8A); /* MOV r8, r/m8 */
|
||||
emit_modrm_mem(a, rcode(p->to.type),
|
||||
p->from.reg, p->from.offset);
|
||||
@@ -772,6 +788,9 @@ a_encode(Asm *a)
|
||||
Asym *s = a_intern(a, p->from.sym);
|
||||
/* R_X86_64_PC32 (2) with addend -4 */
|
||||
a_addreloc(a, reloff, 2, s, -4);
|
||||
} else {
|
||||
fprintf(stderr, "w6a: line %d: unsupported LEAQ shape\n", p->line);
|
||||
a->errs++;
|
||||
}
|
||||
break;
|
||||
case A_CALL:
|
||||
@@ -790,6 +809,9 @@ a_encode(Asm *a)
|
||||
if (rhi(p->to.type)) a_emit_byte(a, 0x41);
|
||||
a_emit_byte(a, 0xFF);
|
||||
a_emit_byte(a, modrm(3, 2, rcode(p->to.type)));
|
||||
} else {
|
||||
fprintf(stderr, "w6a: line %d: unsupported CALL shape\n", p->line);
|
||||
a->errs++;
|
||||
}
|
||||
break;
|
||||
case A_JMP:
|
||||
|
||||
Reference in New Issue
Block a user