Skip to content

arm encoder audit: CMN register-form lacks high-register guard (sibling of #180) #184

@avrabe

Description

@avrabe

Context

While fixing #180 (16-bit Thumb Add/Adds/Subs reg-forms corrupting high registers), an audit of the sibling 16-bit reg-form encoders in `arm_encoder.rs` found one more unguarded case:

```rust
ArmOp::Cmn { rn, op2 } => {
...
} else if let Operand2::Reg(rm) = op2 {
let rm_bits = reg_to_bits(rm) as u16;
// CMN Rn, Rm (16-bit): 0100 0010 11 Rm Rn
let instr: u16 = 0x42C0 | (rm_bits << 3) | rn_bits; // <-- no rn/rm < 8 guard
Ok(instr.to_le_bytes().to_vec())
}
```

16-bit CMN (T1) only encodes R0–R7; for high registers (R8–R11/R12) the 3-bit fields overflow and corrupt the operands — same class as #180. CMN has no high-register 16-bit form, so the fix is to fall back to 32-bit `CMN.W` (T2) for high registers.

Why this is filed rather than fixed in #180

Not currently reachable: the only optimized-path CMN use (the divide-by-zero/INT_MIN overflow guard in `optimizer_bridge.rs`) uses the immediate form (`Operand2::Imm(1)` → 32-bit CMN.W, which handles any register). The reg-form is only emitted by the non-optimized `instruction_selector` path, which uses its own (low) register conventions. So this is a latent defect with no current reproducer; #180 stayed scoped to the demonstrably-reachable Add/Adds/Subs.

Done when

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions