Encode R_ARM_THM_CALL over its full 25-bit displacement - #733
Conversation
The encoder writes the displacement as x[24:1], a signed 25-bit field reaching +-16 MiB, but the addend decoder read back only 24 of those bits and the range check rejected anything wider than a signed 24-bit value. Loading an ARM static archive therefore aborted with CLEOperationError, returning no object at all, once CLE had spread the members and the extern object more than 8 MiB apart -- which it does by default past nine members. Decode the addend over the same 25 bits the encoder writes, widen the range check to match, and warn instead of raising when a displacement genuinely does not fit, as the AArch64 branch relocations already do. A call CLE cannot reach is no more fatal than any other unresolved external call.
|
THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS Validation record for head
Reproducer. cle.Loader("libmbed.a", auto_load_libs=False)The baseline raises Caveats: the finding came from a corpus sweep of real ARM static archives that cannot be published, but the case it found reproduces on a library already in angr/binaries, so no binaries PR is needed. |
|
Corpus decompilation diffs can be found at angr/dec-snapshots@master...angr/cle_733 |
The archive test wrote its own ar container at run time, stacking copies of one object until the extern stubs landed out of reach. That is a test input committed to the wrong repository with extra steps, and a container no toolchain emits: the members were identical, the symbol table was absent, and the member spacing was whatever the test chose rather than whatever a real library happens to have. binaries already carries a real one. libmbed.a is the static library from the mbed GCC ARM build that produced tests/armel/i2c_api.o, and loading it puts 251 Thumb branches in reach of their extern stub -- 57 of them past the 8 MiB the old sign extension allowed -- and 219 past 16 MiB, so both the widened range and the out-of-reach warning come from one real load. Classify each branch by the displacement it has to encode rather than by the distance to its symbol, so the boundary between the two cases is the 25-bit field itself and not a megabyte threshold that happens to work. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS
Loading an ARM static archive aborts with
CLEOperationError: Jump target out of range for reloc R_ARM_THM_CALLand nothing loads. The relocation encodes its displacement asx[24:1], a signed 25-bit field reaching ±16 MiB, but decodes the implicit addend from 24 bits and range-checks against 24. CLE maps each archive member on its ownrebase_granularityboundary and the extern object last, so a ten-member archive already puts the extern stubs out of that range.This widens both to the 25 bits the encoder writes, and warns rather than raises when a displacement really does not fit, matching
R_AARCH64_CALL26. Mapping the extern object within reach would avoid the truncation, but that is a loader-wide layout change.The regression loads
libmbed.afromtests_src/i2c_master_read-nucleol152rein angr/binaries, the 43-member mbed GCC ARM static library built alongsidetests/armel/i2c_api.o. Spread over its members, 251 Thumb branches land within reach of their extern stub and 57 of those are past the 8 MiB the old sign extension allowed, while 219 are past 16 MiB, so the widened range and the out-of-range warning both come out of one real load. That library is already on angr/binaries master, so this needs no binaries PR.Validation: #733 (comment)