<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之间有如下关系: