0x03 - The Program Header
This is the final part of the ELF: Diving Deep Inside series.
In this article, we’ll explore the Program Header Table, its fields and view of an PHT of a real ELF binary.
Table of Content
Section titled “Table of Content”- Introduction
- p_type field
- p_flags
- p_offset, p_vaddr, p_paddr, p_filesz, and p_memsz
- p_align
- Viewing the Program Header Table
- Conclusion
Introduction
Section titled “Introduction”Program Header table provides the segment view of the binary as opposed to section header table which provide the section view of the binary.
Segements are used by the operating system and dynamic linkers to load the data and code in virtual memory and make the process run.
Each Segment can consist of one or more section.
The segment (defined in the Program Header Table) is what decides:
-
Which sections go together
-
What virtual address they get mapped to
-
What memory permissions (R, W, X) they will have
Typedef of Program Header Table in /usr/include/elf.h
Now let’s dicuss about each of the field one by one.
p_type field
Section titled “p_type field”- As the name implies this field denotes the type of the segment.
- Size : 4 Bytes
- Values : PT_LOAD (Sections covered in this type of segment should be loaded in memory), PT_DYNAMIC (This include the .dynamic section which tells how to parse and prepare for execution), PT_PHDR (Includes the program header table) and PT_INTERP (include .interp section which denotes the interpreter to be used for loading)
p_flags
Section titled “p_flags”- Flags are used to define the access permission of segment in memory.
- Size : 4 Bytes
- Values : PF_X, PF_W, PF_R - for execute, write, read respectively.
p_offset, p_vaddr, p_paddr, p_filesz, and p_memsz
Section titled “p_offset, p_vaddr, p_paddr, p_filesz, and p_memsz”- p_offset
- This denotes the posiiton of the segement in the binary
- Size : 8 Bytes
- Value : Not the address but the offset (value that need to be added to the start address of segment)
- p_vaddr
- This denotes the virtual address where the segment will be loaded.
- Size : 8 Bytes
- p_filesz
- Size of the segment when stored in disk.
- Size (of field in struct) : 8 Bytes
- p_memsz
- Size of the segment in memory.
- Size (of field in struct) : 8 Bytes
p_filesz and p_memsz can be different for a single segment because when storing file on disk data block with null bytes are not actually stored with all null bytes but when loaded in memory all null bytes are stored
- p_paddr
- Physical address where the segement will be loaded. (NOTE: This is no more used in modern OS)
- Size : 8 Bytes
p_align
Section titled “p_align”- This defines the alignment requirement for the segment.
- Size : 8 Bytes
- Value : Should be power of 2 , Value 0 and 1 means no alignment required.
Viewing the program header table
Section titled “Viewing the program header table”To view the program header table for a ELF binary use -
readelf --segments --wide <binary>
The Section to Segment mapping clearly defines which segment consists exactly which sections.
Conclusion
Section titled “Conclusion”The Program Header Table defines how an ELF binary is loaded into memory, grouping sections into segments with proper addresses and permissions. With this, we wrap up the ELF deep dive series—you now have the essentials to understand and explore ELF internals further.