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:
|
||||
|
||||
@@ -105,6 +105,17 @@ fn emitrex(a: *asm_, regbit: i32, rmbit: i32, w: i32) void = {
|
||||
else { if (w != 0) { emitbyte(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.
|
||||
fn emitrex8(a: *asm_, regbit: i32, rmbit: i32, r8: i32) void = {
|
||||
let b: u8 = 64u8; // 0x40
|
||||
if (regbit != 0) { b = b | 4u8; };
|
||||
if (rmbit != 0) { b = b | 1u8; };
|
||||
if (b != 64u8) { emitbyte(a, b); }
|
||||
else { if (rhi(r8) == 0 && rcode(r8) >= 4) { emitbyte(a, b); }; };
|
||||
};
|
||||
|
||||
// ModR/M + (optional) SIB + displacement for [base+disp].
|
||||
// Special-cases SP (needs SIB) and BP (forces explicit disp).
|
||||
fn emitmodrmmem(a: *asm_, regfield: i32, base: i32, disp: i64) void = {
|
||||
@@ -283,7 +294,8 @@ export fn encode(a: *asm_) i32 = {
|
||||
let msg: str = "w6a: DATAR slot not yet defined as DATAW: ";
|
||||
os.write(2, msg.ptr, msg.len: u64);
|
||||
os.write(2, p.from.asym.ptr, p.from.asym.len: u64);
|
||||
os.write(2, "\n".ptr, 1u64);
|
||||
let wm1: str = "\n";
|
||||
os.write(2, wm1.ptr, wm1.len: u64);
|
||||
a.errs += 1;
|
||||
p = p.link; continue;
|
||||
};
|
||||
@@ -382,27 +394,31 @@ export fn encode(a: *asm_) i32 = {
|
||||
addreloc(a, reloff, 2, s, -4i64);
|
||||
p = p.link; continue;
|
||||
};};
|
||||
os.write(2, "w6a: unsupported MOVQ shape\n".ptr, 27u64);
|
||||
let wm2: str = "w6a: unsupported MOVQ shape\n";
|
||||
os.write(2, wm2.ptr, wm2.len: u64);
|
||||
a.errs += 1;
|
||||
p = p.link; continue;
|
||||
};
|
||||
|
||||
if (op == A_MOVB) {
|
||||
// emitrex8 forces the bare REX so SI/DI/BP/SP name
|
||||
// SIL/DIL/BPL/SPL, never AH/CH/DH/BH.
|
||||
let ft: i32 = p.from.atype;
|
||||
let tt: i32 = p.to.atype;
|
||||
if (isgpr(ft)) { if (tt == D_INDIR) {
|
||||
emitrex(a, rhi(ft), rhi(p.to.reg), 0);
|
||||
emitrex8(a, rhi(ft), rhi(p.to.reg), ft);
|
||||
emitbyte(a, 136u8); // 0x88
|
||||
emitmodrmmem(a, rcode(ft), p.to.reg, p.to.offset);
|
||||
p = p.link; continue;
|
||||
};};
|
||||
if (ft == D_INDIR) { if (isgpr(tt)) {
|
||||
emitrex(a, rhi(tt), rhi(p.from.reg), 0);
|
||||
emitrex8(a, rhi(tt), rhi(p.from.reg), tt);
|
||||
emitbyte(a, 138u8); // 0x8A
|
||||
emitmodrmmem(a, rcode(tt), p.from.reg, p.from.offset);
|
||||
p = p.link; continue;
|
||||
};};
|
||||
os.write(2, "w6a: unsupported MOVB shape\n".ptr, 27u64);
|
||||
let wm3: str = "w6a: unsupported MOVB shape\n";
|
||||
os.write(2, wm3.ptr, wm3.len: u64);
|
||||
a.errs += 1;
|
||||
p = p.link; continue;
|
||||
};
|
||||
@@ -426,7 +442,8 @@ export fn encode(a: *asm_) i32 = {
|
||||
emitmodrmmem(a, rcode(tt), p.from.reg, p.from.offset);
|
||||
p = p.link; continue;
|
||||
};};
|
||||
os.write(2, "w6a: unsupported MOVW shape\n".ptr, 27u64);
|
||||
let wm4: str = "w6a: unsupported MOVW shape\n";
|
||||
os.write(2, wm4.ptr, wm4.len: u64);
|
||||
a.errs += 1;
|
||||
p = p.link; continue;
|
||||
};
|
||||
@@ -442,7 +459,8 @@ export fn encode(a: *asm_) i32 = {
|
||||
emitmodrmmem(a, rcode(tt), p.from.reg, p.from.offset);
|
||||
p = p.link; continue;
|
||||
};};
|
||||
os.write(2, "w6a: unsupported MOVZWQ shape\n".ptr, 29u64);
|
||||
let wm5: str = "w6a: unsupported MOVZWQ shape\n";
|
||||
os.write(2, wm5.ptr, wm5.len: u64);
|
||||
a.errs += 1;
|
||||
p = p.link; continue;
|
||||
};
|
||||
@@ -465,7 +483,8 @@ export fn encode(a: *asm_) i32 = {
|
||||
emitbyte(a, modrmbyte(3, rcode(tt), rcode(ft)));
|
||||
p = p.link; continue;
|
||||
};};
|
||||
os.write(2, "w6a: unsupported MOVSWQ shape\n".ptr, 29u64);
|
||||
let wm6: str = "w6a: unsupported MOVSWQ shape\n";
|
||||
os.write(2, wm6.ptr, wm6.len: u64);
|
||||
a.errs += 1;
|
||||
p = p.link; continue;
|
||||
};
|
||||
@@ -488,7 +507,8 @@ export fn encode(a: *asm_) i32 = {
|
||||
emitbyte(a, modrmbyte(3, rcode(tt), rcode(ft)));
|
||||
p = p.link; continue;
|
||||
};};
|
||||
os.write(2, "w6a: unsupported MOVSBQ shape\n".ptr, 29u64);
|
||||
let wm7: str = "w6a: unsupported MOVSBQ shape\n";
|
||||
os.write(2, wm7.ptr, wm7.len: u64);
|
||||
a.errs += 1;
|
||||
p = p.link; continue;
|
||||
};
|
||||
@@ -503,7 +523,8 @@ export fn encode(a: *asm_) i32 = {
|
||||
emitmodrmmem(a, rcode(tt), p.from.reg, p.from.offset);
|
||||
p = p.link; continue;
|
||||
};};
|
||||
os.write(2, "w6a: unsupported MOVZBQ shape\n".ptr, 29u64);
|
||||
let wm8: str = "w6a: unsupported MOVZBQ shape\n";
|
||||
os.write(2, wm8.ptr, wm8.len: u64);
|
||||
a.errs += 1;
|
||||
p = p.link; continue;
|
||||
};
|
||||
@@ -529,7 +550,8 @@ export fn encode(a: *asm_) i32 = {
|
||||
emitbyte(a, modrmbyte(3, rcode(ft), rcode(tt)));
|
||||
p = p.link; continue;
|
||||
};};
|
||||
os.write(2, "w6a: unsupported MOVL shape\n".ptr, 27u64);
|
||||
let wm9: str = "w6a: unsupported MOVL shape\n";
|
||||
os.write(2, wm9.ptr, wm9.len: u64);
|
||||
a.errs += 1;
|
||||
p = p.link; continue;
|
||||
};
|
||||
@@ -549,7 +571,8 @@ export fn encode(a: *asm_) i32 = {
|
||||
emitbyte(a, modrmbyte(3, rcode(tt), rcode(ft)));
|
||||
p = p.link; continue;
|
||||
};};
|
||||
os.write(2, "w6a: unsupported MOVSXD shape\n".ptr, 29u64);
|
||||
let wm10: str = "w6a: unsupported MOVSXD shape\n";
|
||||
os.write(2, wm10.ptr, wm10.len: u64);
|
||||
a.errs += 1;
|
||||
p = p.link; continue;
|
||||
};
|
||||
@@ -569,7 +592,8 @@ export fn encode(a: *asm_) i32 = {
|
||||
ssemrload(a, 242u8, 17u8, ft, p.to.reg, p.to.offset);
|
||||
p = p.link; continue;
|
||||
};};
|
||||
os.write(2, "w6a: unsupported MOVSD shape\n".ptr, 28u64);
|
||||
let wm11: str = "w6a: unsupported MOVSD shape\n";
|
||||
os.write(2, wm11.ptr, wm11.len: u64);
|
||||
a.errs += 1;
|
||||
p = p.link; continue;
|
||||
};
|
||||
@@ -596,7 +620,8 @@ export fn encode(a: *asm_) i32 = {
|
||||
ssemrload(a, 243u8, 17u8, ft, p.to.reg, p.to.offset);
|
||||
p = p.link; continue;
|
||||
};};
|
||||
os.write(2, "w6a: unsupported MOVSS shape\n".ptr, 28u64);
|
||||
let wm12: str = "w6a: unsupported MOVSS shape\n";
|
||||
os.write(2, wm12.ptr, wm12.len: u64);
|
||||
a.errs += 1;
|
||||
p = p.link; continue;
|
||||
};
|
||||
@@ -737,6 +762,9 @@ export fn encode(a: *asm_) i32 = {
|
||||
addreloc(a, reloff, 2, s, -4i64);
|
||||
p = p.link; continue;
|
||||
};};
|
||||
let wml: str = "w6a: unsupported LEAQ shape\n";
|
||||
os.write(2, wml.ptr, wml.len: u64);
|
||||
a.errs += 1;
|
||||
p = p.link; continue;
|
||||
};
|
||||
|
||||
@@ -762,6 +790,9 @@ export fn encode(a: *asm_) i32 = {
|
||||
emitbyte(a, modrmbyte(3, 2, rcode(tt)));
|
||||
p = p.link; continue;
|
||||
};
|
||||
let wmc: str = "w6a: unsupported CALL shape\n";
|
||||
os.write(2, wmc.ptr, wmc.len: u64);
|
||||
a.errs += 1;
|
||||
p = p.link; continue;
|
||||
};
|
||||
|
||||
@@ -799,7 +830,8 @@ export fn encode(a: *asm_) i32 = {
|
||||
p = p.link; continue;
|
||||
};
|
||||
|
||||
os.write(2, "w6a: unsupported opcode\n".ptr, 23u64);
|
||||
let wm13: str = "w6a: unsupported opcode\n";
|
||||
os.write(2, wm13.ptr, wm13.len: u64);
|
||||
a.errs += 1;
|
||||
p = p.link;
|
||||
};
|
||||
@@ -808,10 +840,12 @@ export fn encode(a: *asm_) i32 = {
|
||||
let f: *afixup = a.fixups;
|
||||
for (f != nil) {
|
||||
if (!labeldefined(a, f.label)) {
|
||||
os.write(2, "w6a: undefined label '".ptr, 21u64);
|
||||
let wm14: str = "w6a: undefined label '";
|
||||
os.write(2, wm14.ptr, wm14.len: u64);
|
||||
let lbl: str = f.label;
|
||||
os.write(2, lbl.ptr, lbl.len: u64);
|
||||
os.write(2, "'\n".ptr, 2u64);
|
||||
let wm15: str = "'\n";
|
||||
os.write(2, wm15.ptr, wm15.len: u64);
|
||||
a.errs += 1;
|
||||
f = f.fnext;
|
||||
continue;
|
||||
|
||||
@@ -73,16 +73,19 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
if (cstreq(a, "-o")) {
|
||||
i += 1;
|
||||
if (i >= argc) {
|
||||
os.write(2, "w6a: -o requires arg\n".ptr, 20u64);
|
||||
let wm1: str = "w6a: -o requires arg\n";
|
||||
os.write(2, wm1.ptr, wm1.len: u64);
|
||||
return 2;
|
||||
};
|
||||
out = argv[i];
|
||||
} else { if (a[0u64] == 45u8) {
|
||||
os.write(2, "w6a: unknown flag\n".ptr, 17u64);
|
||||
let wm2: str = "w6a: unknown flag\n";
|
||||
os.write(2, wm2.ptr, wm2.len: u64);
|
||||
return 2;
|
||||
} else {
|
||||
if (src != nil) {
|
||||
os.write(2, "w6a: only one input\n".ptr, 19u64);
|
||||
let wm3: str = "w6a: only one input\n";
|
||||
os.write(2, wm3.ptr, wm3.len: u64);
|
||||
return 2;
|
||||
};
|
||||
src = a;
|
||||
@@ -91,11 +94,13 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
};
|
||||
|
||||
if (src == nil) {
|
||||
os.write(2, "usage: w6a_ww -o file.o file.s\n".ptr, 30u64);
|
||||
let wm4: str = "usage: w6a_ww -o file.o file.s\n";
|
||||
os.write(2, wm4.ptr, wm4.len: u64);
|
||||
return 2;
|
||||
};
|
||||
if (out == nil) {
|
||||
os.write(2, "w6a: missing -o\n".ptr, 15u64);
|
||||
let wm5: str = "w6a: missing -o\n";
|
||||
os.write(2, wm5.ptr, wm5.len: u64);
|
||||
return 2;
|
||||
};
|
||||
|
||||
@@ -103,7 +108,8 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
let blen: u64;
|
||||
buf, blen = slurp(src);
|
||||
if (buf == nil) {
|
||||
os.write(2, "w6a: cannot read input\n".ptr, 22u64);
|
||||
let wm6: str = "w6a: cannot read input\n";
|
||||
os.write(2, wm6.ptr, wm6.len: u64);
|
||||
return 1;
|
||||
};
|
||||
|
||||
@@ -120,7 +126,8 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
|
||||
let fd: i32 = os.open(pathstr(out), os.flag.WRONLY | os.flag.CREATE | os.flag.TRUNC, 420i32); // 0o644
|
||||
if (fd < 0) {
|
||||
os.write(2, "w6a: cannot open output\n".ptr, 23u64);
|
||||
let wm7: str = "w6a: cannot open output\n";
|
||||
os.write(2, wm7.ptr, wm7.len: u64);
|
||||
return 1;
|
||||
};
|
||||
let rc: i32 = emitelf(&s, fd);
|
||||
|
||||
Reference in New Issue
Block a user