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:
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user