arm64-asm.c: validate operand types before encoding

Multiple instruction handlers were extracting op->reg without checking
that the operand was actually a register. When parse_operand() failed
to recognize a token, it set op->reg = -1, which when masked with 0x1F
became 31 (xzr/sp), silently encoding wrong instructions.

Now each handler validates operand types before extraction:
- asm_shift: validates op1 and op2 are registers
- asm_data_proc: validates op1, op2, and op3 are registers
- asm_ldst: validates op1 is register, op2 is address
- asm_ldst_pair: validates op1 and op2 are registers, op3 is address

This implements fail-fast behavior to catch typos and invalid operands
immediately rather than producing silently incorrect code.
This commit is contained in:
Benjamin Oldenburg 2026-03-20 18:51:20 +07:00
parent a1bf1d187d
commit 5497f87f59

View File

@ -692,6 +692,16 @@ static void asm_shift(TCCState *s1, int token)
parse_operand(s1, &op1);
if (tok == ',') next();
parse_operand(s1, &op2);
if (!(op1.type & OP_REG)) {
tcc_error("expected register in first operand");
return;
}
if (!(op2.type & OP_REG)) {
tcc_error("expected register in second operand");
return;
}
rd = op1.reg;
rn = op2.reg;
@ -872,6 +882,16 @@ static void asm_data_proc(TCCState *s1, int token)
parse_operand(s1, &op1);
if (tok == ',') next();
parse_operand(s1, &op2);
if (!(op1.type & OP_REG)) {
tcc_error("expected register in first operand");
return;
}
if (!(op2.type & OP_REG)) {
tcc_error("expected register in second operand");
return;
}
rd = op1.reg;
rn = op2.reg;
@ -889,6 +909,10 @@ static void asm_data_proc(TCCState *s1, int token)
else
tcc_error("immediate operand not valid for this instruction");
} else {
if (!(op3.type & OP_REG)) {
tcc_error("expected register in third operand");
return;
}
rm = op3.reg;
is_64bit = (op1.reg_type & REG_X);
if (is_64bit != !!(op2.reg_type & REG_X) || is_64bit != !!(op3.reg_type & REG_X))
@ -916,6 +940,15 @@ static void asm_ldst(TCCState *s1, int token)
if (tok == ',') next();
parse_operand(s1, &op2);
if (!(op1.type & OP_REG)) {
tcc_error("expected register in first operand");
return;
}
if (op2.type != OP_ADDR) {
tcc_error("expected address operand in second operand");
return;
}
rt = op1.reg;
rn = op2.reg;
offset = op2.e.v;
@ -991,6 +1024,14 @@ static void asm_ldst_pair(TCCState *s1, int token)
next();
parse_operand(s1, &op3);
if (!(op1.type & OP_REG)) {
tcc_error("expected register in first operand");
return;
}
if (!(op2.type & OP_REG)) {
tcc_error("expected register in second operand");
return;
}
if (!(op3.type & OP_ADDR))
tcc_error("pair load/store requires an address operand");