goblin
goblin copied to clipboard
Failing to parse section headers of MIPS LE 32-bit ELF correctly on 64-bit PPC BE host
Hello, I seem to have stumbled upon some endian-awareness issues, unless you think I'm somehow misusing the library.
I have this goblin program (simplified from my actual usecase for ease of troubleshooting)
use std::fs;
use goblin::elf32::{header::Header, section_header::SectionHeader, section_header::SHT_REL};
fn main() {
let elf_bytes = fs::read("psp-cube-example").unwrap();
let header = Header::parse(&elf_bytes).unwrap();
let section_headers = SectionHeader::from_bytes(
&elf_bytes[header.e_shoff as usize..],
header.e_shnum as usize,
);
let reloc_count = section_headers.iter().filter(|sh| sh.sh_type == SHT_REL).count();
println!("reloc_count: {}", reloc_count);
println!("section_headers: {:?}", section_headers);
}
and I have this 32-bit MIPS2 LE ELF file (uploaded as zip because github is dumb) psp-cube-example.zip
When I run this program on x86_64 Little Endian - I get the correct result. goblin_repro_x86_64.txt
When I run this program on 64-bit PowerPC - I do not. goblin_repro_ppc64.txt
I am using the default endian_fd feature of goblin.
Here is the output of readelf -S
paul@ps3:~/goblin-repro$ readelf -S psp-cube-example
There are 34 section headers, starting at offset 0x46d44:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 00000000 000120 00af20 00 AX 0 0 16
[ 2] .sceStub.text PROGBITS 0000af20 00b040 0000b8 00 A 0 0 4
[ 3] .lib.stub.top PROGBITS 0000afd8 00b0f8 000004 00 A 0 0 4
[ 4] .lib.stub PROGBITS 0000afdc 00b0fc 000078 00 A 0 0 4
[ 5] .lib.stub.btm PROGBITS 0000b054 00b174 000004 00 A 0 0 4
[ 6] .lib.ent.top PROGBITS 0000b058 00b178 000004 00 A 0 0 4
[ 7] .lib.ent PROGBITS 0000b05c 00b17c 000010 00 A 0 0 1
[ 8] .lib.ent.btm PROGBITS 0000b06c 00b18c 000004 00 A 0 0 4
[ 9] .eh_frame_hdr PROGBITS 0000b070 00b190 0005cc 00 A 0 0 4
[10] .eh_frame PROGBITS 0000b63c 00b75c 0014d4 00 A 0 0 4
[11] .rodata.sceR[...] PROGBITS 0000cb10 00cc30 000074 00 A 0 0 4
[12] .rodata.sceM[...] PROGBITS 0000cb90 00ccb0 000040 00 A 0 0 16
[13] .rodata.sceNid PROGBITS 0000cbd0 00ccf0 00005c 00 A 0 0 4
[14] .rodata PROGBITS 0000cc30 00cd50 011e22 00 AMS 0 0 16
[15] .data PROGBITS 0001ea54 01eb74 000068 00 WA 0 0 4
[16] .got PROGBITS 0001eac0 01ebe0 000008 00 WAp 0 0 16
[17] .gcc_except_table PROGBITS 0001eac8 01ebe8 000dd8 00 A 0 0 4
[18] .bss NOBITS 0001f8a0 01f9c0 1030a4 00 WA 0 0 16
[19] .mdebug.abi32 PROGBITS 00000000 01f9c0 000000 00 0 0 1
[20] .rel.text REL 00000000 01f9c0 002f68 08 I 31 1 4
[21] .pdr PROGBITS 00000000 022928 0151a0 00 0 0 4
[22] .rel.pdr REL 00000000 037ac8 005468 08 I 31 21 4
[23] .rel.rodata REL 00000000 03cf30 000f78 08 I 31 14 4
[24] .rel.rodata.[...] REL 00000000 03dea8 000028 08 I 31 12 4
[25] .rel.lib.ent REL 00000000 03ded0 000008 08 I 31 7 4
[26] .rel.rodata.[...] REL 00000000 03ded8 000010 08 I 31 11 4
[27] .rel.data REL 00000000 03dee8 000048 08 I 31 15 4
[28] .comment PROGBITS 00000000 03df30 0000bf 01 MS 0 0 1
[29] .rel.lib.stub REL 00000000 03dff0 000090 08 I 31 4 4
[30] .rel.sceStub.text REL 00000000 03e080 000170 08 I 31 2 4
[31] .symtab SYMTAB 00000000 03e1f0 002c20 10 33 504 4
[32] .shstrtab STRTAB 00000000 040e10 000197 00 0 0 1
[33] .strtab STRTAB 00000000 040fa7 005d9b 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
D (mbind), p (processor specific)
Let me know if there's any other details you need, I hope you may be able to reproduce using qemu-system-ppc64, but I have not explored it myself.
For extra background on what I'm actually doing, because it's kind of fun :smile: I'm trying to use rust-psp to compile a psp homebrew app on a ps3 running linux. And I hit this assertion in our psp executable repacker: https://github.com/overdrivenpotato/rust-psp/blob/bfaa487ea4881395cc64fdd82158745885222a29/cargo-psp/src/bin/prxgen.rs#L98
It looks like I should be using from_fd instead of from_bytes
Reopening, from_fd doesn't work either.
use std::{fs::File, io::{Seek, SeekFrom}};
use goblin::elf32::{header::Header, section_header::SectionHeader, section_header::SHT_REL};
fn main() {
let mut fd = File::open("psp-cube-example").unwrap();
let header = Header::from_fd(&mut fd).unwrap();
println!("header: {:?}" , header);
//fd.rewind().unwrap();
let section_headers = SectionHeader::from_fd(
&mut fd,
header.e_shoff.into(),
header.e_shnum.into(),
).unwrap();
let reloc_count = section_headers.iter().filter(|sh| sh.sh_type == SHT_REL).count();
println!("reloc_count: {}", reloc_count);
println!("section_headers: {:?}", section_headers);
}
Running `target/debug/goblin-repro`
header: Header { e_ident: [127, 69, 76, 70, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0], e_type: "UNKNOWN_ET", e_machine: 0x800, e_version: 0x1000000, e_entry: 0x10040000, e_phoff: 0x34000000, e_shoff: 0x446d0400, e_flags: 5100010, e_ehsize: 13312, e_phentsize: 8192, e_phnum: 1792, e_shentsize: 10240, e_shnum: 8704, e_shstrndx: 8192 }
thread 'main' panicked at src/main.rs:16:7:
called `Result::unwrap()` on an `Err` value: IO(Error { kind: UnexpectedEof, message: "failed to fill whole buffer" })
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Actual values:
[0x00000410]> iH
0x00000000 ELF MAGIC 0x464c457f
0x00000010 Type 0x0002
0x00000012 Machine 0x0008
0x00000014 Version 0x00000001
0x00000018 Entrypoint 0x00000410
0x0000001c PhOff 0x00000034
0x00000020 ShOff 0x00046d44
0x00000024 Flags 0x10001005
0x00000028 EhSize 52
0x0000002a PhentSize 32
0x0000002c PhNum 7
0x0000002e ShentSize 40
0x00000030 ShNum 34
0x00000032 ShrStrndx 32