It's great idea when you store program data somewhere outside the binary.
It can be modified for changing program's behaivior or for rebranding.
But sometimes you want to keep some data immutable, hidden into executable binary.
This can be help sections. If you don't want to have smth like
void
usage (status)
int status;
{
fprintf (status ? stderr : stdout, "\
Usage: %s [-nV] [--quiet] [--silent] [--version] [-e script]\n\
[-f script-file] [--expression=script] [--file=script-file] [file...]\n",
myname);
exit (status);
}
and don't want this help section be stored in the separate file.You can simply embed binary data into your executable.
Consider you have data.txt:
$cat data.txt
data file
You have to convert it to elf.
I know two ways:
Both of these commands produce elf:
$readelf -a data.o
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: REL (Relocatable file)
Machine: Intel 80386
Version: 0x1
Entry point address: 0x0
Start of program headers: 0 (bytes into file)
Start of section headers: 96 (bytes into file)
Flags: 0x0
Size of this header: 52 (bytes)
Size of program headers: 0 (bytes)
Number of program headers: 0
Size of section headers: 40 (bytes)
Number of section headers: 5
Section header string table index: 2
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .data PROGBITS 00000000 000034 00000a 00 WA 0 0 1
[ 2] .shstrtab STRTAB 00000000 00003e 000021 00 0 0 1
[ 3] .symtab SYMTAB 00000000 000128 000050 10 4 2 4
[ 4] .strtab STRTAB 00000000 000178 000043 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings)
I (info), L (link order), G (group), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)
Symbol table '.symtab' contains 5 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000000 0 SECTION LOCAL DEFAULT 1
2: 00000000 0 NOTYPE GLOBAL DEFAULT 1 _binary_data_txt_start
3: 0000000a 0 NOTYPE GLOBAL DEFAULT 1 _binary_data_txt_end
4: 0000000a 0 NOTYPE GLOBAL DEFAULT ABS _binary_data_txt_size
_binary_data_txt_size and _binary_data_txt_end contain
Ok, you have data.o with your data in .data section and three symbols: _binary_data_txt_start, _binary_data_txt_end, _binary_data_txt_size
_binary_data_txt_end and _binary_data_txt_size have the same value here. So I'll use _binary_data_txt_size only.
Let's make a simple c program to use data from the object. It's a bit tricky.
#include <stdio.h>
extern int _binary_data_txt_start;
extern int _binary_data_txt_size;
int
main(int argc, char **argv)
{
int size = (int)&_binary_data_txt_size;
char *data = (char *)&_binary_data_txt_start;
printf("%d", size);
printf("%s", data);
return 0;
}
_binary_data_txt_start and _binary_data_txt_size contain values in their addresses. So &_binary_data_txt_size contains not an address of the symbol but actually value of the symbol that holds the size of the data and &_binary_data_txt_start contains address of the data.
To compile
gcc test.c data.o