E12 Program Header Table

The following is the program header table in an executable file (object files have no such table):

[email protected]> readelf -l test

Elf file type is EXEC (Executable file) Entry point 0x80482d0

There are 6 program headers, starting at offset 52

Program Headers:

Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align

PHDR 0x000034 0x08048034 0x08048034 0x000c0 0x000c0 R E 0x4

INTERP 0x0000f4 0x080480f4 0x080480f4 0x00013 0x00013 R 0x1

[Requesting program interpreter: /lib/ld-linux.so.2]

LOAD 0x000000 0x08048000 0x08048000 0x0046d 0x0046d R E 0x1000

LOAD 0x000470 0x08049470 0x08049470 0x00108 0x0010c RW 0x1000

DYNAMIC 0x000480 0x08049480 0x08049480 0x000c8 0x000c8 RW 0x4

NOTE 0x000108 0x08048108 0x08048108 0x00020 0x00020 R 0x4

Section to Segment mapping: Segment Sections...

01 .interp

02 .interp .note.ABI-tag .hash .dynsym .dynstr .gnu.version .gnu.version_r .rel.dyn .rel.plt .init .plt .text .fini .rodata

03 .data .eh_frame .dynamic .ctors .dtors .jcr .got .bss

04 .dynamic

05 .note.ABI-tag

Six sections are listed under Program Headers — these constitute the final program in memory. Information on size and position in virtual and physical address space,3 flags, access authorizations, and

2In particular, this means that relative branch addresses must be used instead of absolute addresses in assembly language code.

3 The physical address information is ignored because this information is allocated dynamically by the kernel depending on which physical page frames are mapped onto the corresponding positions in virtual address space. This information is of relevance only on systems that have no MMU and therefore no virtual memory — on small embedded processors, for instance.

alignment is provided for each section. A type is also specified to describe the section more precisely. The sample program includes five different types with the following meanings:

□ phdr holds the program header table in memory.

□ interp specifies which interpreter must be called once the program has been mapped from the executable file into memory. In this context, interpreter does not mean that the contents of the binary file must be interpreted by a further program, as is the case with Java byte code and with the Java Virtual Machine (JVM). It refers to a program that satisfies unresolved references by linking additional libraries.

Normally, /lib/ld-linux.so.2, /lib/ld-linux-ia-64.so.2 and so on, is used to insert the required dynamic libraries in virtual address space. The C standard library libc.so must be mapped for almost all programs, and various libraries are added to is, such as GTK, the mathematical library, libjpeg, and many more.

□ LOAD denotes a section that is mapped from the binary file into virtual address space. It holds constant data (such as strings), the object code of the program, and so on.

□ dynamic sections hold information used by the dynamic linker (i.e., by the interpreter specified in interp).

□ note holds proprietary information, which is not relevant to the current topic.

The various segments in virtual address space are filled with the data of specific sections in the ELF file. The second part of the readelf output therefore specifies which sections are loaded into which segment (Section to Segment Mapping).

These are not segments as used in IA32 processors to implement different isolated ranges of virtual address space but are simply address space areas.

Other platforms adopt basically the same approach, but different sections are mapped into the individual areas depending on the particular architecture, as the following IA-64 example shows:

[email protected]> readelf -l test_ia64 Elf file type is EXEC (Executable file) Entry point 0x40000000000004e0

There are 7 program headers, starting at offset 64

Program Headers: Type


Offset FileSiz

VirtAddr MemSiz

PhysAddr Flags Align

0x0000000000000040 0x4000000000000040 0x4000000000000040


0x0000000000000188 0x0000000000000188

0x00000000000001c8 0x40000000000001c8 0x40000000000001c8

0x0000000000000018 0x0000000000000018 R 1 [Requesting program interpreter: /lib/ld-linux-ia64.so.2]

LOAD 0x0000000000000000 0x4000000000000000 0x4000000000000000

0x00000000000009f0 0x00000000000009f0 R E 10000

LOAD 0x00000000000009f0 0x60000000000009f0 0x60000000000009f0

0x0000000000000270 0x0000000000000280 RW 10000

DYNAMiC 0x00000000000009f8 0x60000000000009f8 0x60000000000009f8



0x00000000000001a0 0x00000000000001a0 RW 8

0x00000000000001e0 0x40000000000001e0 0x40000000000001e0

0x0000000000000020 0x0000000000000020 R 4

0x00000000000009a8 0x40000000000009a8 0x40000000000009a8

0x0000000000000048 0x0000000000000048 R 8

Section to Segment mapping: Segment Sections...

01 .interp

02 .interp .note.ABI-tag .hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.IA_64.pltoff .init .plt .text .fini .rodata .opd .IA_64.unwind_info .IA_64.unwind

03 .data .dynamic .ctors .dtors .jcr .got .IA_64.pltoff .sdata .sbss .bss

04 .dynamic

05 .note.ABI-tag

06 .IA_64.unwind

Notwithstanding the fact that 64-bit addresses are used, it is also apparent that a further section of the ia_64_unwind type has been added. This section stores unwind information that is used to analyze stack frames (if, for example, a backtrace is to be generated) because, for architecture-specific reasons, this cannot be done on IA-64 systems by simply analyzing the stack contents.4 The exact meanings of the various sections are discussed next.

The segments can overlap, as the readelf output for IA-32 shows. Segment 02 of type load extends from 0x08048000 to 0x8048000 + 0x0046d = 0x0804846d. It contains the .note.ABI-tag segment. However, the same area in virtual address space is used to implement segment 06 (of the note type) that extends from 0x08048108 to 0x08048108 + 0x00020 = 0x08048128 and therefore lies within segment 02. This behavior is explicitly allowed by the standard.

Continue reading here: E13 Sections

Was this article helpful?

0 0