w6a: bare negative constant parses honestly; name(reg) rejects

Two parse.c operand defects. A bare `-8` (no $) double-negated to
+8: a_parsenum lets strtoll consume the sign, and the caller's
`off * sign` re-applied it (the D_INDIR arm never multiplied, which
is why -8(BP) always worked); the wwstage twin was already correct,
so this was a latent cs!=ww on hand-written source. The name(REG)
non-SB arm faked a D_INDIR off an UNCHECKED reg_lookup and silently
discarded the parsed ident and +disp -- both stages; the shape has
no encoding and now rejects loud.
This commit is contained in:
2026-08-09 01:12:41 +09:00
parent 5006bf4fb9
commit 4a5f64fc3d
2 changed files with 17 additions and 11 deletions

View File

@@ -197,8 +197,11 @@ parse_operand(Asm *a, const char *s, Aoperand *out)
out->offset = off; out->offset = off;
return 0; return 0;
} }
/* a_parsenum consumed the sign itself (strtoll); the local
* `sign` exists only so isdigit() sees past the '-'.
* Multiplying re-applied it: bare `-8` parsed as +8. */
out->type = D_CONST; out->type = D_CONST;
out->offset = off * sign; out->offset = off;
return 0; return 0;
} }
@@ -233,11 +236,12 @@ parse_operand(Asm *a, const char *s, Aoperand *out)
out->offset = sym_disp; out->offset = sym_disp;
return 0; return 0;
} }
out->type = D_INDIR; /* name(REG) with a non-SB register has no encoding
out->reg = r; * here; the old arm faked D_INDIR off an UNCHECKED
out->offset = 0; * reg_lookup and silently discarded the ident and
/* unusual case: name(REG) with named offset; not used */ * +disp (rule 7). */
return 0; err(a, "unsupported name(reg) operand");
return -1;
} }
int r = reg_lookup(buf); int r = reg_lookup(buf);

View File

@@ -338,12 +338,14 @@ fn parseoperand(a: *asm_, p: *u8, offin: u64, n: u64, out: *aoperand) u64 = {
out.atype = D_EXTERN; out.atype = D_EXTERN;
out.asym = dupstr(p + istart, in_); out.asym = dupstr(p + istart, in_);
out.offset = symdisp; out.offset = symdisp;
} else { return cur2 + 1u64;
out.atype = D_INDIR;
out.reg = r;
out.offset = 0i64;
}; };
return cur2 + 1u64; // name(REG) with a non-SB register has no
// encoding here; the old arm faked D_INDIR
// off an UNCHECKED reglookup and silently
// discarded the ident and +disp (rule 7).
perr(a, "unsupported name(reg) operand");
return n;
}; };
perr(a, "missing ')'"); perr(a, "missing ')'");
return n; return n;