Fix Thumb2 conditional branch encoding with absolute targets - #607
Closed
xintenseapple wants to merge 1 commit into
Closed
Fix Thumb2 conditional branch encoding with absolute targets#607xintenseapple wants to merge 1 commit into
xintenseapple wants to merge 1 commit into
Conversation
Thumb2 conditional branches to an absolute address were encoded from the raw target address instead of a PC-relative offset, producing branches to the wrong location. ARMMCCodeEmitter::getBranchTargetOpValue() dispatched Thumb2 to the generic helper, which returns immediate operands unchanged. The T3 encoder then extracted S/J1/J2/imm6/imm11 from what it assumed was a PC-relative offset but was actually the absolute address. The unconditional t2B path already subtracts the instruction address; the conditional path did not. Assembling "bne 0x15f0" at 0x1248 emitted 41 f0 f8 82, which decodes to 0x283c. It now emits 40 f0 d2 81, which decodes to 0x15f0. Every wide conditional branch was affected, including backward branches, which failed to set the sign bit. Symbolic targets are unaffected: they still take the fixup_t2_condbranch path, which was already correct. Fixes keystone-engine#451 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This was referenced Aug 24, 2026
Author
|
Closing as a duplicate of #601, which was opened first and fixes the same root cause with a smaller diff. I verified both patches produce byte-for-byte identical output across ARM and Thumb Detailed verification posted at #601. My analysis of the root cause remains in #451 for reference. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #451.
Problem
Thumb2 conditional branches to an absolute address are encoded from the raw target address rather than a PC-relative offset, so they branch to the wrong location.
Every wide (T3) conditional branch is affected, including branches to a nearby instruction. Backward branches additionally fail to set the sign bit.
Root cause
This is not in the
t2Bccbit-shifting inARMGenMCCodeEmitter.inc, which is where the issue report pointed. Patching that code changes nothing, because the value reaching it is already wrong.ARMMCCodeEmitter::getBranchTargetOpValue()dispatched Thumb2 to the generic::getBranchTargetOpValue()helper, which returns immediate operands unchanged. The T3 encoder then extractedS/J1/J2/imm6/imm11from what it assumed was a PC-relative offset, but was in fact the absolute target address.The unconditional
t2Bpath already does this subtraction:The conditional path simply omitted it. That is why
b,bl,blx, and the narrow T1 conditional form are all correct, and only the wide conditional form is broken.Fix
Mirror the
t2Bstructure: expression operands still take thefixup_t2_condbranchpath (unchanged — that path was already correct), while immediates are converted to a PC-relative byte offset. The value is left as a byte offset because the existing encoder masks shift out the low bit themselves.Verification
This matches the encoding expected in the issue report.
bneand forced-widebne.w. All decode back to the requested target.b/bl/blx/cbz, and all condition codes are unaffected.suite/regressshow no change versus master.arm_sym_resolver.pyandarm_sym_resolver_thumb.pyfail both with and without this change (pre-existing, unrelated to branch encoding).Note:
suite/regress/regress.pyhalts partway through on a pre-existing Python 2 syntax error inx86_issue293.py(except Exception, e:), so the tests above were run individually.🤖 Generated with Claude Code