Skip to content

Fix Thumb2 conditinal branch - #601

Open
Highbor wants to merge 1 commit into
keystone-engine:masterfrom
Highbor:fix/thumb2-condbranch-pc-offset
Open

Fix Thumb2 conditinal branch#601
Highbor wants to merge 1 commit into
keystone-engine:masterfrom
Highbor:fix/thumb2-condbranch-pc-offset

Conversation

@Highbor

@Highbor Highbor commented Jun 5, 2026

Copy link
Copy Markdown

kstool thumb "bne.w 0x680168E0" 0x68016578
should generate '40 F0 B2 81' which is the same as the one
from IDA-Pro "0x68016578: 40 F0 B2 81 BNE.W loc_680168E0"
or
capstone.Cs(CS_ARCH_ARM,CS_MODE_THUMB).disasm(the-generate-bytes,0x8016578) should match the raw-asm "bne.w 0x680168E0"

the bug code generate the wrong result: [ 56 f0 6e 84 ] which capstone can not disasm out the raw-asm

kstool thumb 'bne.w 0x680168E0' 0x68016578 should generate '40 F0 B2 81'

that is the same as the one from capstone/IDA-Pro '0x68016578: 40 F0 B2 81  BNE.W  loc_680168E0'
@xintenseapple

Copy link
Copy Markdown

Confirming this fix independently — I hit the same bug via #451 and arrived at the same root cause before finding this PR. I've closed my duplicate (#607) in favor of this one, which is the better patch.

For maintainers weighing it up, some verification that may help move it along:

The diagnosis here is correct, and notably it is not what #451 proposed. That issue blamed the ARM::t2Bcc bit-shifting in ARMGenMCCodeEmitter.inc. I patched that first and the output did not change — the bit math is fine, it was just being fed an absolute address instead of a PC-relative offset. This PR fixes the actual source.

The one-line change is safe despite the helper having 16 callers. I checked each one: every other caller guards with if (MO.isExpr()) and does its own address arithmetic for immediates, so none of them ever reach the MO.isImm() line. The Thumb2 conditional path was the only caller falling through to it. I built both this patch and my more targeted variant and diffed the output across ARM and Thumb b/bl/blx/bcc/cbz/adr — byte-for-byte identical everywhere, so the narrower diff here is preferable.

Test results on top of 0d9567f:

  • bne.w 0x680168E0 at 0x6801657840 f0 b2 81, matching IDA.
  • bne 0x15f0 at 0x124840 f0 d2 81, matching the expected encoding in keystone can not encode thumb2 bcc instructions correctlly #451.
  • Round-tripped 14 offsets through a T3 decoder (forward, backward, ±1MB range limits), as both bne and forced-wide bne.w — all decode back to the requested target.
  • Short offsets still correctly select the narrow T1 encoding.
  • ARM regression tests in suite/regress show no change versus master. (arm_sym_resolver.py and arm_sym_resolver_thumb.py fail both with and without this patch — pre-existing and unrelated.)

Two details worth noting beyond the report: the bug affects every wide conditional branch, including bne.w to the very next instruction, and backward branches additionally fail to set the sign bit.

This resolves #451.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants