Skip to content

elf: fix MIPS64 little-endian relocation parsing#519

Open
messense wants to merge 1 commit intom4b:masterfrom
messense:fix-mips64-reloc-parsing
Open

elf: fix MIPS64 little-endian relocation parsing#519
messense wants to merge 1 commit intom4b:masterfrom
messense:fix-mips64-reloc-parsing

Conversation

@messense
Copy link
Contributor

Summary

Fixes #274 — MIPS64 LE ELF binaries fail to parse with an out-of-bounds error because r_sym and r_type return garbage values from the non-standard MIPS64 relocation layout.

Background

MIPS64 ELF uses a non-standard relocation info (r_info) layout different from standard ELF64:

Standard ELF64 MIPS64
r_sym (32 bits) | r_type (32 bits) r_sym (32 bits) | r_ssym (8 bits) | r_type3 (8 bits) | r_type2 (8 bits) | r_type (8 bits)

On little-endian MIPS64, when this struct is read as a single u64, the byte order causes the fields to be scrambled. For example, an r_info with r_sym=0 and r_type=R_MIPS_REL32 gets read as 0x0312000000000000, causing:

  • r_sym to return 51,511,296 (instead of 0)
  • r_type to return 0 (instead of 3)

The bogus r_sym then causes the dynamic symbol table parsing to try to read millions of symbols, failing with an out-of-bounds error.

Approach

Based on the maintainer's feedback from #382pass down whether it's a MIPS binary at runtime rather than using #[cfg] compile-time conditionals:

  1. reloc64::mips64el_r_info() — Converts MIPS64 LE r_info to standard ELF64 format using the same byte transformation as LLVM and the object crate

  2. Reloc::fixup_mips64el() — Applies the transformation after parsing a relocation entry

  3. RelocSection / RelocIterator — Carry an is_mips64el flag and conditionally apply the fixup during get() and iteration

  4. Elf::parse_with_opts() — Detects MIPS64 LE from the ELF header (e_machine == EM_MIPS && 64-bit && little-endian) and passes it through via RelocSection::parse_inner()

Backward Compatibility

  • RelocSection::parse() signature is unchanged (defaults is_mips64el = false)
  • RelocCtx type alias is unchanged
  • r_sym() / r_type() / r_info() functions are unchanged
  • All existing tests pass

Tests

Added 5 new tests:

  • test_mips64el_r_info — validates the byte transformation with real data from MIPS64 parse error: "type is too big (1236271128) for 137416" #274
  • test_mips64el_r_info_with_sym — validates transformation when r_sym is non-zero
  • test_mips64el_r_info_zero — edge case: all-zero r_info
  • test_standard_r_sym_r_type_unchanged — ensures no regression for non-MIPS
  • test_mips64el_reloc_section_parse — integration test through the full RelocSection pipeline, verifying both broken (without fix) and correct (with fix) behavior

References

@messense messense force-pushed the fix-mips64-reloc-parsing branch from 0d7b9ab to 27b25a2 Compare February 28, 2026 07:31
Fix m4b#274: MIPS64 ELF uses a non-standard relocation info layout where
the r_info field contains r_sym (32 bits) | r_ssym (8 bits) | r_type3
(8 bits) | r_type2 (8 bits) | r_type (8 bits), instead of the standard
ELF64 format of (sym << 32) | type.

On little-endian MIPS64 systems, when this struct is read as a single
u64, the byte order causes the fields to be scrambled. This resulted in
r_sym returning garbage values (e.g., 51511296 instead of 0), which then
caused the dynamic symbol table parsing to try to read millions of
symbols, failing with an out-of-bounds error.

The fix applies a byte transformation (matching the approach used by
LLVM and the `object` crate) to rearrange the MIPS64 LE r_info bytes
into the standard ELF64 format before extracting r_sym and r_type.

Changes:
- Add `reloc64::mips64el_r_info()` to convert MIPS64 LE r_info to
  standard ELF64 format
- Add `Reloc::fixup_mips64el()` to apply the transformation after
  parsing
- Add `is_mips64el` flag to `RelocSection` and `RelocIterator` to
  conditionally apply the fixup during iteration/access
- Add `RelocSection::parse_inner()` that accepts the `is_mips64el` flag
- Detect MIPS64 LE in `Elf::parse_with_opts()` from the ELF header's
  e_machine and endianness
- Backward compatible: `RelocSection::parse()` still works unchanged
  (defaults to no MIPS64 fixup)
- Add comprehensive unit and integration tests
@messense messense force-pushed the fix-mips64-reloc-parsing branch from 27b25a2 to 9dfc91e Compare February 28, 2026 07:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MIPS64 parse error: "type is too big (1236271128) for 137416"

1 participant