Skip to content
Advertisement

libelf corrupts ARM elf binaries

I’m trying to manipulate ARM elf binaries on linux using the libelf library without success. Even a minimal test-case corrupts my binaries, and I don’t know why.

Here is my minimal test-code which reads an elf-file and then simply writes it back:

#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h> 
#include <unistd.h>  
#include <libelf.h>
#include <assert.h>

void main (void)
{
    if (elf_version(EV_CURRENT) == EV_NONE)
       return;

    int fd = open ("HelloWorld.elf", O_RDWR);
    assert (fd);

    Elf *e = elf_begin(fd, ELF_C_RDWR, (Elf *) 0);
    assert (e);

    if (elf_update(e, ELF_C_WRITE) == -1)
        return;

    elf_end (e);
    close (fd);

    printf ("okn");
    return;
}

If I run this code on a ELF 64-bit x86-64 executable I get a bit-exact copy of the elf-file back. That’s what I expected.

If however I pass in an ARM 32-bit executable the file gets corrupted. It’s still an elf-file and I can parse it just fine, but the section offsets have been modified and worse: The section to Segment mapping gets corrupted:

Before running my code the mapping looks like this:

 Section to Segment mapping:
  Segment Sections...
   00     .ARM.exidx 
   01     .text .ARM.exidx 
   02     .data .bss 

And after running my code it becomes:

 Section to Segment mapping:
  Segment Sections...
   00     
   01     .ARM.exidx .heap .stack_dummy .ARM.attributes .comment .svc_table 
   02     .bss 

If I convert the modified elf binary to a flash image using objcopy I only get garbage out.

So is there anything I should do to make the libelf library work with arm binaries?

Background:

I’m writing a little utility to calculate some checksums and insert them into the elf binary. That’s required my microcontroller and unfortunately gnu LD can’t do it on it’s own. I thought using a high-level ELF manipulation library would be the best and most robust way to get this working.

Advertisement

Answer

Found it myself.

After opening the elf-file a call to:

elf_flagelf (e, ELF_C_SET, ELF_F_LAYOUT);

will tell libelf to not touch the segment and section layout. This prevents libelf from rewriting the executable and we’ll get an unmodified file as exepcted.

After any modifications to the section data a call to elf_flagdata is required like this:

 Elf_Data *data = elf_getdata ( ...

 // do modification to data here..

 elf_flagdata (data, ELF_C_SET, ELF_F_DIRTY);

is required to let libelf know that the data has been changed and that the elf checksum has to be recalculated.

Advertisement