Linux
2019-05-09
NAME
elf - format of Executable and Linking Format (ELF) files
SYNOPSIS
#include <elf.h>
DESCRIPTION
The header file <elf.h> defines the format of ELF executable binary files. Amongst these files are normal executable files, relocatable object files, core files, and shared objects.
An executable file using the ELF file format consists of an ELF header, followed by a program header table or a section header table, or both. The ELF header is always at offset zero of the file. The program header table and the section header table’s offset in the file are defined in the ELF header. The two tables describe the rest of the particularities of the file.
This header file describes the above mentioned headers as C structures and also includes structures for dynamic sections, relocation sections and symbol tables.
Basic types
The following types are used for N-bit architectures (N=32,64, ElfN stands for Elf32 or Elf64, uintN_t stands for uint32_t or uint64_t):
ElfN_Addr Unsigned program address, uintN_t ElfN_Off Unsigned file offset, uintN_t ElfN_Section Unsigned section index, uint16_t ElfN_Versym Unsigned version symbol information, uint16_t Elf_Byte unsigned char ElfN_Half uint16_t ElfN_Sword int32_t ElfN_Word uint32_t ElfN_Sxword int64_t ElfN_Xword uint64_t
(Note: the *BSD terminology is a bit different. There, Elf64_Half is twice as large as Elf32_Half, and Elf64Quarter is used for uint16_t. In order to avoid confusion these types are replaced by explicit ones in the below.)
All data structures that the file format defines follow the "natural" size and alignment guidelines for the relevant class. If necessary, data structures contain explicit padding to ensure 4-byte alignment for 4-byte objects, to force structure sizes to a multiple of 4, and so on.
ELF header (Ehdr)
The ELF header is described by the type Elf32_Ehdr or Elf64_Ehdr:
#define EI_NIDENT 16
typedef struct {
unsigned char e_ident[EI_NIDENT];
uint16_t e_type;
uint16_t e_machine;
uint32_t e_version;
ElfN_Addr e_entry;
ElfN_Off e_phoff;
ElfN_Off e_shoff;
uint32_t e_flags;
uint16_t e_ehsize;
uint16_t e_phentsize;
uint16_t e_phnum;
uint16_t e_shentsize;
uint16_t e_shnum;
uint16_t e_shstrndx; } ElfN_Ehdr;
unsigned char e_ident[EI_NIDENT];
uint16_t e_type;
uint16_t e_machine;
uint32_t e_version;
ElfN_Addr e_entry;
ElfN_Off e_phoff;
ElfN_Off e_shoff;
uint32_t e_flags;
uint16_t e_ehsize;
uint16_t e_phentsize;
uint16_t e_phnum;
uint16_t e_shentsize;
uint16_t e_shnum;
uint16_t e_shstrndx; } ElfN_Ehdr;
The fields have the following meanings:
e_ident | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
This array of bytes specifies how to interpret the file, independent of the processor or the file’s remaining contents. Within this array everything is named by macros, which start with the prefix EI_ and may contain values which start with the prefix ELF. The following macros are defined:
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
e_type | This member of the structure identifies the object file type:
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
e_machine | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
This member specifies the required architecture for an individual file. For example: |
Program header (Phdr)
An executable or shared object file’s program header table is an array of structures, each describing a segment or other information the system needs to prepare the program for execution. An object file segment contains one or more sections. Program headers are meaningful only for executable and shared object files. A file specifies its own program header size with the ELF header’s e_phentsize and e_phnum members. The ELF program header is described by the type Elf32_Phdr or Elf64_Phdr depending on the architecture:
typedef struct {
uint32_t p_type;
Elf32_Off p_offset;
Elf32_Addr p_vaddr;
Elf32_Addr p_paddr;
uint32_t p_filesz;
uint32_t p_memsz;
uint32_t p_flags;
uint32_t p_align; } Elf32_Phdr;
uint32_t p_type;
Elf32_Off p_offset;
Elf32_Addr p_vaddr;
Elf32_Addr p_paddr;
uint32_t p_filesz;
uint32_t p_memsz;
uint32_t p_flags;
uint32_t p_align; } Elf32_Phdr;
typedef struct {
uint32_t p_type;
uint32_t p_flags;
Elf64_Off p_offset;
Elf64_Addr p_vaddr;
Elf64_Addr p_paddr;
uint64_t p_filesz;
uint64_t p_memsz;
uint64_t p_align; } Elf64_Phdr;
uint32_t p_type;
uint32_t p_flags;
Elf64_Off p_offset;
Elf64_Addr p_vaddr;
Elf64_Addr p_paddr;
uint64_t p_filesz;
uint64_t p_memsz;
uint64_t p_align; } Elf64_Phdr;
The main difference between the 32-bit and the 64-bit program header lies in the location of the p_flags member in the total struct.
p_type | This member of the structure indicates what kind of segment this array element describes or how to interpret the array element’s information.
|
||||||||||||||||||||
p_offset | This member holds the offset from the beginning of the file at which the first byte of the segment resides. | ||||||||||||||||||||
p_vaddr | This member holds the virtual address at which the first byte of the segment resides in memory. | ||||||||||||||||||||
p_paddr | On systems for which physical addressing is relevant, this member is reserved for the segment’s physical address. Under BSD this member is not used and must be zero. | ||||||||||||||||||||
p_filesz | This member holds the number of bytes in the file image of the segment. It may be zero. | ||||||||||||||||||||
p_memsz | This member holds the number of bytes in the memory image of the segment. It may be zero. | ||||||||||||||||||||
p_flags | This member holds a bit mask of flags relevant to the segment: |
Section header (Shdr)
A file’s section header table lets one locate all the file’s sections. The section header table is an array of Elf32_Shdr or Elf64_Shdr structures. The ELF header’s e_shoff member gives the byte offset from the beginning of the file to the section header table. e_shnum holds the number of entries the section header table contains. e_shentsize holds the size in bytes of each entry.
A section header table index is a subscript into this array. Some section header table indices are reserved: the initial entry and the indices between SHN_LORESERVE and SHN_HIRESERVE. The initial entry is used in ELF extensions for e_phnum, e_shnum and e_shstrndx; in other cases, each field in the initial entry is set to zero. An object file does not have sections for these special indices:
SHN_UNDEF | |
This value marks an undefined, missing, irrelevant, or otherwise meaningless section reference. | |
SHN_LORESERVE | |
This value specifies the lower bound of the range of reserved indices. | |
SHN_LOPROC, SHN_HIPROC | |
Values greater in the inclusive range [SHN_LOPROC, SHN_HIPROC] are reserved for processor-specific semantics. | |
SHN_ABS | |
This value specifies the absolute value for the corresponding reference. For example, a symbol defined relative to section number SHN_ABS has an absolute value and is not affected by relocation. | |
SHN_COMMON | |
Symbols defined relative to this section are common symbols, such as FORTRAN COMMON or unallocated C external variables. | |
SHN_HIRESERVE | |
This value specifies the upper bound of the range of reserved indices. The system reserves indices between SHN_LORESERVE and SHN_HIRESERVE, inclusive. The section header table does not contain entries for the reserved indices. | |
The section header has the following structure: | |
typedef struct { uint32_t sh_name; uint32_t sh_type; uint32_t sh_flags; Elf32_Addr sh_addr; Elf32_Off sh_offset; uint32_t sh_size; uint32_t sh_link; uint32_t sh_info; uint32_t sh_addralign; uint32_t sh_entsize; } Elf32_Shdr; |
|
typedef struct { uint32_t sh_name; uint32_t sh_type; uint64_t sh_flags; Elf64_Addr sh_addr; Elf64_Off sh_offset; uint64_t sh_size; uint32_t sh_link; uint32_t sh_info; uint64_t sh_addralign; uint64_t sh_entsize; } Elf64_Shdr; |
|
No real differences exist between the 32-bit and 64-bit section headers. | |
sh_name | |
This member specifies the name of the section. Its value is an index into the section header string table section, giving the location of a null-terminated string. | |
sh_type | |
This member categorizes the section’s contents and semantics. |
String and symbol tables
String table sections hold null-terminated character sequences, commonly called strings. The object file uses these strings to represent symbol and section names. One references a string as an index into the string table section. The first byte, which is index zero, is defined to hold a null byte (\(aq\0\(aq). Similarly, a string table’s last byte is defined to hold a null byte, ensuring null termination for all strings.
An object file’s symbol table holds information needed to locate and relocate a program’s symbolic definitions and references. A symbol table index is a subscript into this array.
typedef struct {
uint32_t st_name;
Elf32_Addr st_value;
uint32_t st_size;
unsigned char st_info;
unsigned char st_other;
uint16_t st_shndx; } Elf32_Sym;
uint32_t st_name;
Elf32_Addr st_value;
uint32_t st_size;
unsigned char st_info;
unsigned char st_other;
uint16_t st_shndx; } Elf32_Sym;
typedef struct {
uint32_t st_name;
unsigned char st_info;
unsigned char st_other;
uint16_t st_shndx;
Elf64_Addr st_value;
uint64_t st_size; } Elf64_Sym;
uint32_t st_name;
unsigned char st_info;
unsigned char st_other;
uint16_t st_shndx;
Elf64_Addr st_value;
uint64_t st_size; } Elf64_Sym;
The 32-bit and 64-bit versions have the same members, just in a different order.
st_name | |
This member holds an index into the object file’s symbol string table, which holds character representations of the symbol names. If the value is nonzero, it represents a string table index that gives the symbol name. Otherwise, the symbol has no name. | |
st_value | |
This member gives the value of the associated symbol. | |
st_size | |
Many symbols have associated sizes. This member holds zero if the symbol has no size or an unknown size. | |
st_info | |
This member specifies the symbol’s type and binding attributes: |
Relocation entries (Rel & Rela)
Relocation is the process of connecting symbolic references with symbolic definitions. Relocatable files must have information that describes how to modify their section contents, thus allowing executable and shared object files to hold the right information for a process’s program image. Relocation entries are these data.
Relocation structures that do not need an addend:
typedef struct {
Elf32_Addr r_offset;
uint32_t r_info; } Elf32_Rel;
Elf32_Addr r_offset;
uint32_t r_info; } Elf32_Rel;
typedef struct {
Elf64_Addr r_offset;
uint64_t r_info; } Elf64_Rel;
Elf64_Addr r_offset;
uint64_t r_info; } Elf64_Rel;
Relocation structures that need an addend:
typedef struct {
Elf32_Addr r_offset;
uint32_t r_info;
int32_t r_addend; } Elf32_Rela;
Elf32_Addr r_offset;
uint32_t r_info;
int32_t r_addend; } Elf32_Rela;
typedef struct {
Elf64_Addr r_offset;
uint64_t r_info;
int64_t r_addend; } Elf64_Rela;
Elf64_Addr r_offset;
uint64_t r_info;
int64_t r_addend; } Elf64_Rela;
r_offset | |
This member gives the location at which to apply the relocation action. For a relocatable file, the value is the byte offset from the beginning of the section to the storage unit affected by the relocation. For an executable file or shared object, the value is the virtual address of the storage unit affected by the relocation. | |
r_info | This member gives both the symbol table index with respect to which the relocation must be made and the type of relocation to apply. Relocation types are processor-specific. When the text refers to a relocation entry’s relocation type or symbol table index, it means the result of applying ELF[32|64]_R_TYPE or ELF[32|64]_R_SYM, respectively, to the entry’s r_info member. |
r_addend | |
This member specifies a constant addend used to compute the value to be stored into the relocatable field. |
Dynamic tags (Dyn)
The .dynamic section contains a series of structures that hold relevant dynamic linking information. The d_tag member controls the interpretation of d_un.
typedef struct {
Elf32_Sword d_tag;
union {
Elf32_Word d_val;
Elf32_Addr d_ptr;
} d_un; } Elf32_Dyn; extern Elf32_Dyn _DYNAMIC[];
Elf32_Sword d_tag;
union {
Elf32_Word d_val;
Elf32_Addr d_ptr;
} d_un; } Elf32_Dyn; extern Elf32_Dyn _DYNAMIC[];
typedef struct {
Elf64_Sxword d_tag;
union {
Elf64_Xword d_val;
Elf64_Addr d_ptr;
} d_un; } Elf64_Dyn; extern Elf64_Dyn _DYNAMIC[];
Elf64_Sxword d_tag;
union {
Elf64_Xword d_val;
Elf64_Addr d_ptr;
} d_un; } Elf64_Dyn; extern Elf64_Dyn _DYNAMIC[];
d_tag | This member may have any of the following values: |
Notes (Nhdr)
ELF notes allow for appending arbitrary information for the system to use. They are largely used by core files (e_type of ET_CORE), but many projects define their own set of extensions. For example, the GNU tool chain uses ELF notes to pass information from the linker to the C library.
Note sections contain a series of notes (see the struct definitions below). Each note is followed by the name field (whose length is defined in n_namesz) and then by the descriptor field (whose length is defined in n_descsz) and whose starting address has a 4 byte alignment. Neither field is defined in the note struct due to their arbitrary lengths.
An example for parsing out two consecutive notes should clarify their layout in memory:
void *memory, *name, *desc; Elf64_Nhdr *note, *next_note;
/* The buffer is pointing to the start of the section/segment */ note = memory;
/* If the name is defined, it follows the note */ name = note->n_namesz == 0 ? NULL : memory + sizeof(*note);
/* If the descriptor is defined, it follows the name
(with alignment) */
(with alignment) */
desc = note->n_descsz == 0 ? NULL :
memory + sizeof(*note) + ALIGN_UP(note->n_namesz, 4);
memory + sizeof(*note) + ALIGN_UP(note->n_namesz, 4);
/* The next note follows both (with alignment) */ next_note = memory + sizeof(*note) +
ALIGN_UP(note->n_namesz, 4) +
ALIGN_UP(note->n_descsz, 4);
ALIGN_UP(note->n_namesz, 4) +
ALIGN_UP(note->n_descsz, 4);
Keep in mind that the interpretation of n_type depends on the namespace defined by the n_namesz field. If the n_namesz field is not set (e.g., is 0), then there are two sets of notes: one for core files and one for all other ELF types. If the namespace is unknown, then tools will usually fallback to these sets of notes as well.
typedef struct {
Elf32_Word n_namesz;
Elf32_Word n_descsz;
Elf32_Word n_type; } Elf32_Nhdr;
Elf32_Word n_namesz;
Elf32_Word n_descsz;
Elf32_Word n_type; } Elf32_Nhdr;
typedef struct {
Elf64_Word n_namesz;
Elf64_Word n_descsz;
Elf64_Word n_type; } Elf64_Nhdr;
Elf64_Word n_namesz;
Elf64_Word n_descsz;
Elf64_Word n_type; } Elf64_Nhdr;
n_namesz | |
The length of the name field in bytes. The contents will immediately follow this note in memory. The name is null terminated. For example, if the name is "GNU", then n_namesz will be set to 4. | |
n_descsz | |
The length of the descriptor field in bytes. The contents will immediately follow the name field in memory. | |
n_type | Depending on the value of the name field, this member may have any of the following values: |
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ELF32_ST_VISIBILITY(other) or ELF64_ST_VISIBILITY(other)
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
NOTES
ELF first appeared in System V. The ELF format is an adopted standard.
The extensions for e_phnum, e_shnum and e_shstrndx respectively are Linux extensions. Sun, BSD and AMD64 also support them; for further information, look under SEE ALSO.
SEE ALSO
as(1), elfedit(1), gdb(1), ld(1), nm(1), objdump(1), patchelf(1), readelf(1), size(1), strings(1), strip(1), execve(2), dl_iterate_phdr(3), core(5), ld.so(8)
Hewlett-Packard, Elf-64 Object File Format.
Santa Cruz Operation, System V Application Binary Interface.
UNIX System Laboratories, "Object Files", Executable and Linking Format (ELF).
Sun Microsystems, Linker and Libraries Guide.
AMD64 ABI Draft, System V Application Binary Interface AMD64 Architecture Processor Supplement.