ELF: do not relocate an image the linker has already finished with - #801
ELF: do not relocate an image the linker has already finished with#801zardus wants to merge 1 commit into
Conversation
|
THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS Loading import cle
path = "binaries/tests/i386/linked_with_emit_relocs"
ld = cle.Loader(path, auto_load_libs=False)
obj = ld.main_object
text = obj.sections_map[".text"]
with open(path, "rb") as fp:
fp.seek(text.offset)
on_disk = fp.read(text.memsize)
mem = ld.memory.load(text.vaddr, text.memsize)
print("relocations registered:", len(obj.relocs))
print(".text bytes differing:", sum(a != b for a, b in zip(mem, on_disk)), "of", text.memsize)Before — the loaded cle master 3812052After — only the two allocated entries in with this changeThe pointer table in |
|
THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS Validation record for head 2026-09-04. The relative-relocation half of this change has been dropped. It replaced the same line of Focused, The three are master's, not this change's: The regression fails on master CI's Lint and Typecheck rules, run at this head against master
u-boot 2026.07.
The MIPS repair is this change on its own and needs nothing else; the loaded image is byte-identical to the one the earlier two-part version of this pull request produced. The x86 image reaches this code only once #802 restores its section table, and there this change and #773 are both needed:
The last row's loaded image is byte-identical (sha256 Corpus: loading every ELF file under The branch has been rebased from Not run on this head, and not claimed: angr's Python and Rust suites, the GUI and fixture suites, and pre-commit across every repository. cle's own suite above ran against an existing build of the compiled libraries rather than a fresh one. The CI disposition this record carried for head |
|
Corpus decompilation diffs can be found at angr/dec-snapshots@master...angr/cle_801 |
43e8f06 to
8326d9f
Compare
__register_sections applies every relocation section when the object carries no dynamic relocation tags. That is right for a relocatable object, where nothing has been applied yet and no relocation section is allocated. A linked image built with --emit-relocs -- which is how u-boot keeps its .rel.text -- has had every one of those entries applied by the linker already, and a REL entry reads its addend out of memory, so applying it again computes S + (S + A) and rewrites the code. Run a relocation section only when it is SHF_ALLOC, or when the object is relocatable and therefore has none allocated. On the i386 fixture that drops the registered relocations from 8 to the 2 that are still outstanding, and takes the loaded .text from 5 of its 128 bytes differing from the file to none. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
8326d9f to
88a2363
Compare
THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS
Problem
CLE applies relocations the linker has already applied, so every analysis
downstream reads bytes that are not in the binary. On
binaries/tests/i386/linked_with_emit_relocscle registers 8 relocations where2 are still outstanding, and 5 of the 128 bytes of
.textcome back fromcle.Loaderdifferent from the file:Nothing raises.
The same fault on real firmware: on u-boot 2026.07's big-endian MIPS image cle
applies 29228 entries and 65495 of the 413956 bytes of
.textdiffer from thefile; on the little-endian one, 10200 entries and 23807 of 214932 bytes.
Root cause
__register_sectionsapplies every relocation section when the object carriesno dynamic relocation tags:
That is right for a relocatable object, where nothing has been applied yet and
no relocation section is allocated. A linked image built with
--emit-relocs,which is how u-boot keeps its
.rel.text, has had every one of those entriesapplied by the linker already, and a REL entry takes its addend from memory, so
applying it again computes
S + (S + A).Fix
Run a relocation section only when it is
SHF_ALLOC, or when the object isrelocatable and therefore has no allocated relocation section at all. On the
fixture that leaves the 2 outstanding entries and
.textbyte-identical to thefile; on both u-boot MIPS images it takes the applied relocations to 0 and
.textto byte-identical.Deliberately not done here:
GenericRelativeReloc.valueaddsmapped_basewhere a relative relocation wants the distance the object moved. That is a
separate defect, and #773 fixes it with the identical one-line change this pull
request used to carry as well. Dropping it here is what lets the two apply
together.
Testing
tests/test_linked_image_relocations.pyloads the fixture above -- afreestanding clang and GNU ld build, linked at
0x1000, with--emit-relocs--and asserts that the loaded
.textmatches the file. It fails on master.Validation: #801 (comment)
sync: angr/binaries#219
session: sharpen