<aside> 💡
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.
</aside>
// linux-4.19/include/uapi/linux/elf.h
struct elf64_phdr {
Elf64_Word p_type; // 4
Elf64_Word p_flags; // 4
Elf64_Off p_offset; // 8
Elf64_Addr p_vaddr; // 8
Elf64_Addr p_paddr; // 8
Elf64_Xword p_filesz; // 8
Elf64_Xword p_memsz; // 8
Elf64_Xword p_align; // 8
}
(gdb) p/d (Elf64_Xword *)0 + 1
$35 = 8
// Size of program headers: 56 (bytes)
(gdb) p/d (Elf64_Phdr *)0 + 1
$4 = 56
// linux-4.19/include/uapi/linux/elf.h
/* These constants are for the segment types stored in the image headers */
#define PT_NULL 0
#define PT_LOAD 1
#define PT_DYNAMIC 2
#define PT_INTERP 3
#define PT_NOTE 4
#define PT_SHLIB 5
#define PT_PHDR 6
#define PT_TLS 7 /* Thread local storage segment */
#define PT_LOOS 0x60000000 /* OS-specific */
#define PT_HIOS 0x6fffffff /* OS-specific */
#define PT_LOPROC 0x70000000
#define PT_HIPROC 0x7fffffff
#define PT_GNU_EH_FRAME 0x6474e550
#define PT_GNU_STACK (PT_LOOS + 0x474e551)
/* These constants define the permissions on sections in the program
header, p_flags. */
#define PF_R 0x4
#define PF_W 0x2
#define PF_X 0x1
$ readelf -h /bin/echo
ELF Header:
...
Start of program headers: 64 (bytes into file)
...
Size of program headers: 56 (bytes)
Number of program headers: 13
// 根据ELF file header:
// program headers 位于文件的:64 ~ 792(64+56*13 0x318)共 0x2d8 bytes
----------------------------------------------------------------------------------
hd /bin/echo -s 64 -n 56
00000040 06 00 00 00 04 00 00 00 40 00 00 00 00 00 00 00 |........@.......|
00000050 40 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 |@.......@.......|
00000060 d8 02 00 00 00 00 00 00 d8 02 00 00 00 00 00 00 |................|
00000070 08 00 00 00 00 00 00 00 |........|
p_type = 0x06 -> PT_PHDR
p_flags = 0x04 -> PF_R
p_offset = 0x40
p_vaddr = 0x40
p_paddr = 0x40
p_filesz = 0x02d8
p_memsz = 0x02d8
p_align = 0x8
(base) ➜ tmp hd /bin/echo -s 120 -n 56
00000078 03 00 00 00 04 00 00 00 18 03 00 00 00 00 00 00 |................|
00000088 18 03 00 00 00 00 00 00 18 03 00 00 00 00 00 00 |................|
00000098 1c 00 00 00 00 00 00 00 1c 00 00 00 00 00 00 00 |................|
000000a8 01 00 00 00 00 00 00 00 |........|
p_type = 0x03 -> PT_INTERP
p_flags = 0x04 -> PF_R
p_offset = 0x0318
p_vaddr = 0x0318
p_paddr = 0x0318
p_filesz = 0x1c
p_memsz = 0x1c
p_align = 0x1
...
(base) ➜ tmp hd /bin/echo -s 736 -n 56
000002e0 52 e5 74 64 04 00 00 00 10 8c 00 00 00 00 00 00 |R.td............|
000002f0 10 9c 00 00 00 00 00 00 10 9c 00 00 00 00 00 00 |................|
00000300 f0 03 00 00 00 00 00 00 f0 03 00 00 00 00 00 00 |................|
00000310 01 00 00 00 00 00 00 00 |........|
00000318
p_type = 0x6474e552 -> GNU_RELRO
p_flags = 0x04 -> PF_R
p_offset = 0x108c
p_vaddr = 0x109c
p_paddr = 0x109c
p_filesz = 0x03f0
p_memsz = 0x03f0
p_align = 0x01
---------------------------------------------------------------------------------
readelf -l /bin/echo
...
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x0000000000000040 0x0000000000000040
0x00000000000002d8 0x00000000000002d8 R 0x8
INTERP 0x0000000000000318 0x0000000000000318 0x0000000000000318
0x000000000000001c 0x000000000000001c R 0x1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
...
GNU_RELRO 0x0000000000008c10 0x0000000000009c10 0x0000000000009c10
0x00000000000003f0 0x00000000000003f0 R 0x1
...
Section to Segment mapping:
Segment Sections...
00
01 .interp
02 .interp .note.gnu.property .note.gnu.build-id .note.ABI-tag .gnu.hash .dynsym .dynstr .gnu.version .gnu.ver
03 .init .plt .plt.got .plt.sec .text .fini
04 .rodata .eh_frame_hdr .eh_frame
05 .init_array .fini_array .data.rel.ro .dynamic .got .data .bss
06 .dynamic
07 .note.gnu.property
08 .note.gnu.build-id .note.ABI-tag
09 .note.gnu.property
10 .eh_frame_hdr
11
12 .init_array .fini_array .data.rel.ro .dynamic .got
segments和sections之间有如下关系: