I learned a useful trick today for embedding arbitrary data in an ELF executable. This is an easy way bundle RAM disks and other resources when you’re running on bare hardware.

The first step is to turn our binary data into an ELF object file:

echo yahyahyah > yah
objcopy -I binary -O elf32-i386 -B i386 \
    --rename-section .data=.yah yah yah.o

The -I and -O mean we are converting from raw binary to our target format elf32-i386. The -B option sets the architecture field of the output file: this is required by ld. By default the binary data is placed in the .data section; --rename-section changes this to a name we can refer to in our linker script. You can omit this flag if you don’t care about the layout of your executable.

nick@pickle:~$ objdump -x yah.o 
 
yah.o:     file format elf32-i386
yah.o
architecture: i386, flags 0x00000010:
HAS_SYMS
start address 0x00000000
 
Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .yah          0000000a  00000000  00000000  00000034  2**0
                  CONTENTS, ALLOC, LOAD, DATA
SYMBOL TABLE:
00000000 l    d  .yah   00000000 .yah
00000000 g       .yah   00000000 _binary_yah_start
0000000a g       .yah   00000000 _binary_yah_end
0000000a g       *ABS*  00000000 _binary_yah_size

You can see objcopy has created three symbols which we can use to access the data at runtime like so:

extern void _binary_yah_start, _binary_yah_end;
extern void _binary_yah_size;
 
void *yah = &_binary_yah_start;
size_t yah_size = (size_t)&_binary_yah_size;

By renaming the output section we can place the data wherever we like using a linker script like this:

.yah : AT(some_address)
{
    *(.yah)
    . = ALIGN(4096);   /* Optional */
}

What fun! Hopefully someone will find it useful.