Add MIPS HI16/LO16 relocation fixtures with RELA addends - #210
Conversation
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.
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.
|
THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS Validation record for head Built with GNU as 2.46 from nixpkgs
Container shape read back out of the files with pyelftools rather than taken from the target triple:
Consumer check, with cle's This repository has no executable suite of its own; the fixtures are exercised by angr/cle#722. session: mega-corpus |
|
THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS Searching every Before — every HI16/LO16 object here is o32, and therefore angr/binaries at the merge baseAfter — the same five relocations in with this change |
cle's tests for R_MIPS_HI16 and R_MIPS_LO16 had one object to work from, tests/mips/mips-hilo.o, which is o32 and therefore SHT_REL. Nothing here covered the SHT_RELA spelling of the same pair, so the tests that wanted it were rewriting mips-hilo.o's section headers in memory. Three objects assembled from tests_src/relocs/mips/mips-hilo-rela.s, one per ABI, so the same code appears as Elf64_Rela, Elf32_Rela and Elf32_Rel: tests/mips64/mips64-hilo-rela.o ELFCLASS64, n64, SHT_RELA tests/mips64/mipsn32-hilo-rela.o ELFCLASS32, n32, SHT_RELA tests/mips/mips-hilo-unpaired.o ELFCLASS32, o32, SHT_REL Each holds two matched %hi/%lo pairs and a trailing %hi whose %lo never follows it, the arrangement a consumer that insists on pairing cannot handle. One pair points 0x8000 past its section symbol, so the low half of the address is negative once sign-extended and the high half has to compensate. Built with GNU as 2.46 from nixpkgs pkgsCross.mips64el-linux-gnuabin32; tests_src/relocs/mips/mips-hilo-generate.sh has the exact invocations and reproduces all three byte for byte.
9b2b033 to
1d6e87b
Compare
THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS
Problem
MIPS
R_MIPS_HI16/R_MIPS_LO16reach a loader in two spellings, and only one is represented here. The only HI16/LO16 object in the repository,tests/mips/mips-hilo.o, is o32 and thereforeSHT_REL, where the addend is read out of the instruction. Searching every MIPS object undertests/:So the
SHT_RELApath — where the addend is in the relocation entry and the pairing rule is different — has no input at all, and neither does the case of a%hiwhose%lonever follows it.Root cause
n64 and n32 assemble to
SHT_RELAand o32 toSHT_REL; every MIPS fixture here is o32, so the RELA form never appeared.Fix
Add three objects built from one assembly source, so the same five relocations reach a loader as
Elf64_Rela,Elf32_RelaandElf32_Rel:plus
tests/mips/mips-hilo-unpaired.o, the o32SHT_RELbuild of the same source. Each holds two matched%hi/%lopairs and a trailing%hiwith no%loafter it, which is the arrangement a consumer that insists on pairing cannot handle. Source and generate script are intests_src/relocs/mips.Testing
The generate script, run with GNU as 2.46 from nixpkgs, reproduces all three objects byte for byte, so the recipe and the artifacts agree. Section types,
e_flagsand the relocation lists were read back with pyelftools. All three raiseStopIterationon cle master today and load with the expected bytes on the consumer branch; that comparison and the digests are in the validation record.Validation: #210 (comment)
sync: angr/cle#722
session: sharpen