Relocate MIPS HI16 and LO16 from the RELA addend - #722
Conversation
|
THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS Validation record for head What changed since the previous head.
The fixtures are one assembly source built for n64, n32 and o32 by GNU as 2.46, so the same five relocations reach the loader as Caveats. Only the cle suite ran: the change is confined to two relocation classes in the ELF MIPS backend, and the complete workspace gate reinstalls the shared editable environment, which other work on this machine had live workers mapped into. The editables state was recomputed and matched byte for byte before entering the shell, and no Corpus population this closes, 2026-08-28Measured at
40 of those objects were run at three revisions: all 40 raise The inputs are legitimate. Reading the section headers of the 40 directly: every one carries Example object, cited by architecture, container and digest because the corpus is not public: MIPS ELF, sha256 Method: the corpus was scanned for every object erroring inside cle, and the objects attributed to this frame were sampled 417 units over 332 objects across 91 strata of site x backend x architecture x object kind x load options; 40 of those objects belong to this site. Each was loaded three times — at this effort's pin, at cle master, and at this pull request's head in its own worktree — with every worker printing the resolved CI state, head That includes the three jobs outside the
An earlier version of this record predicted that |
d501cec to
4b00dde
Compare
|
Corpus decompilation diffs can be found at angr/dec-snapshots@master...angr/cle_722 |
4b00dde to
3733a70
Compare
79f75ec to
7b5db29
Compare
7b5db29 to
807f03f
Compare
R_MIPS_HI16.relocate ran the REL algorithm unconditionally: it recovered the low half of the addend from the immediate field of a matching R_MIPS_LO16, found with a next() that had no default. A RELA object carries its whole addend in r_addend and leaves those immediate fields zero, so the search was both unnecessary and, whenever a %hi had no later %lo against the same symbol, fatal. The bare StopIteration escaped cle.Loader.__init__ with no message and is not a CLEError; under PEP 479 a generator between the two turns it into an unrelated RuntimeError. A corpus sweep hit this on 3523 real MIPS kernel modules, the usual shape being a lui in a branch delay slot whose %lo sits at the branch target, earlier in the relocation table. Both relocations now read r_addend when the entry came from a RELA section and only consult the pair for REL, where the ABI does require the R_MIPS_LO16 to follow. That fixes the value as well: deriving from GenericAbsoluteReloc dropped r_addend, so a RELA R_MIPS_LO16 wrote S & 0xffff where it owed (S + A) & 0xffff, and R_MIPS_HI16 wrote %high(S) where it owed %high(S + A). A REL object with a genuinely missing partner now logs a warning and leaves the instruction alone instead of aborting the load. The tests load three assembled objects added in angr/binaries#210, one per MIPS ABI, so the same relocations are exercised as Elf64_Rela, Elf32_Rela and Elf32_Rel. Only a real assembler can produce the arrangement this fix is about, since the defect is that a shape no synthetic RELA reproduces reaches the loader.
807f03f to
97d49c5
Compare
|
THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS Full relocation report for the four MIPS objects, before and after this change. Before — the three new objects do not load, and applied one at a time the second pair builds cle at the merge base, 46a3733After — all four load, both pairs build the intended address on every ABI, and the unpaired with this change, 97d49c5 |
|
THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS How much of a corpus's failure surface this removes, measured rather than Sample. 12,000 objects drawn uniformly at random, from a seeded permutation, Method. Each object is loaded with the catalogue's declared load recipe and Before. 8 / 11,989 = 0.067% of the sample (CI 0.034–0.132) die with a After. This head clears all 8, and all 8 go on to reach CFG — the whole Control. 722 objects that already reached CFG on This is a small class in absolute terms, and worth saying plainly: 8 objects out The corpus is not redistributable, so its objects are described by architecture, session: sharpen |
THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS
Problem
A MIPS object whose relocations are RELA does not load at all:
tests/mips64/mips64-hilo-rela.o,tests/mips64/mipsn32-hilo-rela.oandtests/mips/mips-hilo-unpaired.oall end in anR_MIPS_HI16with no following%lo, which is legal — a compiler emits one whenever the low half of the address is used elsewhere or not at all. The exception escapescle.Loader, so the object and every relocation after the failing one are lost. Applying the relocations one at a time shows the second defect underneath: the pairs that do run build the wrong address.Root cause
R_MIPS_HI16always ran the SHT_REL algorithm. It found its partner with a barenextthat had no default:and recovered the addend by reading the in-place field of that partner,
c_int16(self.owner.memory.unpack_word(matching_lo16_reloc_dest_addr, size=2)).value. A RELA object carries its whole addend inr_addend, so that search bought nothing — and both relocations derived fromGenericAbsoluteReloc, whosevalueis the symbol address alone, sor_addendwas simply dropped: the second pair sits0x8000past its section symbol and came out at0x21030.Fix
A shared
MipsHalfwordRelocbase gives both relocations avaluethat addsself.addendwhenself.is_rela, animmediate_addrthat picks the low halfword of the instruction on big-endian, and animplicit_addendthat reads the in-place field only for REL, where the ABI does require the%loto follow.find_matching_lo16_relocationpassesNoneas the default, and a REL object whose partner really is missing warns instead of aborting; an unpairedHI16is deliberately not patched at all, so its immediate keeps what the assembler left in it.Testing
tests/test_mips_relocations.py::TestMipsRellocations::test_mips_hilo16_relaloads the o32-RELA, n32 and mips64 objects and asserts_computed_address(ld, BASE_ADDR + hi_offset, BASE_ADDR + lo_offset) == addressfor each pair;::test_mips_hi16_without_lo16pins the warning and the untouched immediate. These replace RELA variants the tests used to synthesise in memory, and the pre-existing REL objecttests/mips/mips-hilo.ois byte-identical on both sides. Every job resolves the fixture branch throughbinaries-ref, so the matrix does not wait on it merging.sync: angr/binaries#210
Validation: #722 (comment)
session: sharpen