Skip to content

fix(encoder): T3 ADD.W raw-imm packing — ADDW (T4) for static offsets 0x100..0xFFF (#681) - #690

Merged
avrabe merged 1 commit into
mainfrom
fix/681-addw-imm-packing
Jul 10, 2026
Merged

fix(encoder): T3 ADD.W raw-imm packing — ADDW (T4) for static offsets 0x100..0xFFF (#681)#690
avrabe merged 1 commit into
mainfrom
fix/681-addw-imm-packing

Conversation

@avrabe

@avrabe avrabe commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Fixes #681.

Bug

encode_thumb32_add_imm packed a raw immediate into the T3 ADD.W i:imm3:imm8 field. That field is a ThumbExpandImm modified immediate (raw == expanded only for imm <= 0xFF): ThumbExpandImm(0x200) = 0, ThumbExpandImm(0x400) = 0x8000_0000. Every dynamic-address i32/i64/i8/i16 load/store with a static offset ∈ [0x100, 0xFFF] silently accessed the wrong address — and in --safety-bounds software the guard (correct T4 ADDW) checked the intended address while the access used the mis-encoded one: a bounds-check bypass. Exact #253/#255 ThumbExpandImm class, in a helper #255's audit didn't cover, reached via the #382 paths.

Fix

imm <= 0xFFF now delegates to encode_thumb32_add, which already implements the correct split per #253:

Byte sizes are unchanged everywhere, so the #511 estimator↔encoder agreement oracle stays green as-is.

Class audit (no wildcard survives)

Site Finding Action
encode_thumb32_add_imm the #681 bug T3/T4 split via encode_thumb32_add
ArmOp::Rsb (Thumb T2) raw-packed ThumbExpandImm field; no plain-imm12 form exists gated on try_thumb_expand_imm, Err on non-representable. All emitters use #32 → byte-identical
ArmOp::Rsb (A32) *imm & 0xFF silent masking (#378 class) Err for imm > 0xFF
encode_thumb32_and_imm_raw raw-packed ThumbExpandImm field gated; only caller (POPCNT #0x3F) byte-identical
encode_thumb32_sub / adds / subs / cmp / orr / eor / cmn already T4-split or expand-gated (#253/#255) pinned, no change

Oracles

🤖 Generated with Claude Code

….0xFFF (#681)

encode_thumb32_add_imm packed the RAW immediate into the T3 ADD.W
i:imm3:imm8 field, which is a ThumbExpandImm MODIFIED immediate —
correct only for imm <= 0xFF. ThumbExpandImm(0x200) = 0 and
ThumbExpandImm(0x400) = 0x8000_0000, so every dynamic-address
load/store with a static offset in [256, 4095] silently computed a
WRONG address. In --safety-bounds software the guard (correct T4 ADDW)
checked the intended address while the access used the mis-encoded one
— a bounds-check bypass. #253/#255 ThumbExpandImm class, reached via
the #382 paths.

Fix: imm <= 0xFFF delegates to encode_thumb32_add, which already picks
T3 (<= 0xFF, raw == expanded, bit-identical) vs ADDW T4 plain imm12
(0x100..=0xFFF) per #253. The > 0xFFF MOVW/MOVT path is unchanged, so
byte sizes are unchanged (estimator agreement #511 stays green).

Class audit (no wildcard survives, #634 style):
- ArmOp::Rsb (Thumb T2): field is ThumbExpandImm-coded with NO plain
  imm12 form — now gated on try_thumb_expand_imm, Err on
  non-representable. All emitters use imm 32 (byte-identical).
- ArmOp::Rsb (A32): imm was silently masked & 0xFF (#378 class) — now
  Err for imm > 0xFF.
- encode_thumb32_and_imm_raw: raw-packed ThumbExpandImm field — now
  gated; only caller (POPCNT, #0x3F) byte-identical.
- encode_thumb32_sub/adds/subs/cmp already correct (T4 / expand-gated).

Oracles:
- test_encode_add_imm_thumb_expand_681: clang -target thumbv7m pinned
  bit-for-bit (0xFF/0x100/0x104/0x200/0x3FC/0x400/0xFFF + rd/rn perm).
- test_encode_add_imm_large_350's 0x123 assertion upgraded from
  length-only (which let the mis-encoding pass CI) to exact bytes.
- scripts/repro/addw_offset_681_differential.py: unicorn-vs-wasmtime,
  dynamic base + static offsets, i32/i8/i16/i64 load+store, bounds
  none+software incl. the bypass pin and OOB trap-to-trap. RED on
  pre-fix main (36 mismatches: clobber returns 4660 not 111; offset
  1024 faults 2 GiB past base), GREEN post-fix (49/49). CI-wired in
  the trap-semantics oracle job.
- Frozen anchors 10/10 byte-identical; estimator agreement green;
  workspace tests, fmt, clippy -D warnings clean.

Closes #681

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@codecov

codecov Bot commented Jul 10, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@avrabe
avrabe merged commit 963967d into main Jul 10, 2026
34 checks passed
@avrabe
avrabe deleted the fix/681-addw-imm-packing branch July 10, 2026 16:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant