You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Fix#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
/// On little-endian systems, when this struct is read as a single `u64`, the byte order
275
+
/// causes the fields to be scrambled compared to the standard `(sym << 32) | type` layout.
276
+
/// This function rearranges the bytes so that the standard [`r_sym`] and [`r_type`] functions
277
+
/// return correct values.
278
+
///
279
+
/// See the [MIPS64 ELF ABI](https://web.archive.org/web/20231012215433/https://techpubs.jurassic.nl/manuals/hdwr/developer/Mpro_n32_ABI/sgi_html/sgidoc/books/Mpro_n32_ABI/sgi_html/ch06.html)
280
+
/// and [LLVM's implementation](https://github.com/llvm/llvm-project/blob/119bf57ab6de49a3e61b9200c917a6d30ac6f0ad/llvm/include/llvm/Object/ELFTypes.h#L435-L444)
281
+
/// for reference.
282
+
#[inline(always)]
283
+
pubfnmips64el_r_info(info:u64) -> u64{
284
+
(info << 32)
285
+
| ((info >> 8)&0xff000000)
286
+
| ((info >> 24)&0x00ff0000)
287
+
| ((info >> 40)&0x0000ff00)
288
+
| ((info >> 56)&0x000000ff)
289
+
}
290
+
269
291
elf_rela_std_impl!(u64,i64);
270
292
}
271
293
@@ -298,6 +320,19 @@ if_alloc! {
298
320
use scroll::ctx::SizeWith;
299
321
Reloc::size_with(&(is_rela, ctx))
300
322
}
323
+
324
+
/// Fix up `r_sym` and `r_type` for MIPS64 little-endian binaries.
325
+
///
326
+
/// MIPS64 ELF uses a non-standard relocation info layout that causes
327
+
/// `r_sym` and `r_type` to be incorrectly extracted on little-endian systems.
328
+
/// This method reconstructs the original `r_info`, applies the MIPS64 LE
329
+
/// byte transformation, and re-extracts the correct values.
330
+
fn fixup_mips64el(&mutself){
331
+
let r_info = ((self.r_sym asu64) << 32) | (self.r_type asu64);
332
+
let fixed = reloc64::mips64el_r_info(r_info);
333
+
self.r_sym = reloc64::r_sym(fixed)asusize;
334
+
self.r_type = reloc64::r_type(fixed);
335
+
}
301
336
}
302
337
303
338
typeRelocCtx = (bool,Ctx);
@@ -394,6 +429,7 @@ if_alloc! {
394
429
ctx:RelocCtx,
395
430
start:usize,
396
431
end:usize,
432
+
is_mips64el:bool,
397
433
}
398
434
399
435
impl<'a> fmt::DebugforRelocSection<'a> {
@@ -412,6 +448,17 @@ if_alloc! {
412
448
#[cfg(feature = "endian_fd")]
413
449
/// Parse a REL or RELA section of size `filesz` from `offset`.
0 commit comments