object icon indicating copy to clipboard operation
object copied to clipboard

Elf Builder fails with non-homogenous PT_LOAD alignments

Open JaciBrunning opened this issue 3 months ago • 2 comments

When calling object::build::elf::Builder::read32(...) on an ELF file that contains different alignments in its load sections (e.g. the below), the following error is raised: "Unsupported alignments for PT_LOAD segments"

From objdump -x myelf:

Program Header:
    LOAD off    0x00000114 vaddr 0x08000000 paddr 0x08000000 align 2**2
         filesz 0x0000020d memsz 0x0000020d flags r--
    LOAD off    0x00000324 vaddr 0x08000250 paddr 0x08000250 align 2**2
         filesz 0x00004260 memsz 0x00004260 flags r-x
    LOAD off    0x00004584 vaddr 0x080044b0 paddr 0x080044b0 align 2**2
         filesz 0x000003fc memsz 0x000003fc flags r--
    LOAD off    0x00004980 vaddr 0x20000100 paddr 0x20000100 align 2**3
         filesz 0x00000000 memsz 0x00001070 flags rw-
   STACK off    0x00000000 vaddr 0x00000000 paddr 0x00000000 align 2**0
         filesz 0x00000000 memsz 0x00000000 flags rw-
private flags = 0x5000400: [Version5 EABI] [hard-float ABI]

I may be missing something, but I don't see a reason for this restriction, and causes the elf builder to fail to load a subset of files that are valid. In my case, this prevents us from being able to read ELF files that perform floating point trigonometric methods on a 32-bit platform with hard-float support.

The issue seems to originate in src/build/elf.rs:146 and onwards, where the alignment of the first section with PT_LOAD is latched through builder.load_align.

            if segment.p_type(endian) == elf::PT_LOAD {
                let p_align = segment.p_align(endian).into();
                if builder.load_align != 0 && builder.load_align != p_align {
                    return Err(Error::new("Unsupported alignments for PT_LOAD segments"));
                }
                builder.load_align = p_align;
            }

The alignments are stored per-segment in the lines following, so it seems odd to be storing it at the builder level when I can only find references to builder.load_align in the rewrite crate.

            builder.segments.push(Segment {
                id,
                delete: false,
                p_type: segment.p_type(endian),
                p_flags: segment.p_flags(endian),
                p_offset: segment.p_offset(endian).into(),
                p_vaddr: segment.p_vaddr(endian).into(),
                p_paddr: segment.p_paddr(endian).into(),
                p_filesz: segment.p_filesz(endian).into(),
                p_memsz: segment.p_memsz(endian).into(),
                p_align: segment.p_align(endian).into(),
                sections: Vec::new(),
                marker: PhantomData,
            });

Is there a reason that I'm missing for the PT_LOAD segments to be homogenous in alignment as a requirement? If not, I'm happy to open a PR to fix this issue.

Thanks!

JaciBrunning avatar Mar 30 '24 05:03 JaciBrunning