https://chacker.pl/
Tabela nagłówków programu zapewnia widok segmentu pliku binarnego, w przeciwieństwie do widoku sekcji zapewnianego przez tabelę nagłówków sekcji. Widok sekcji pliku binarnego ELF, który omówiłem wcześniej, jest przeznaczony wyłącznie do celów łączenia statycznego. Natomiast widok segmentu, który omówię później, jest używany przez system operacyjny i dynamiczny linker podczas ładowania pliku ELF do procesu w celu wykonania, aby zlokalizować odpowiedni kod i dane oraz zdecydować, co załadować do pamięci wirtualnej. Segment ELF obejmuje zero lub więcej sekcji, zasadniczo łącząc je w jeden fragment. Ponieważ segmenty zapewniają widok wykonania, są potrzebne tylko w przypadku wykonywalnych plików ELF, a nie w przypadku plików niewykonywalnych, takich jak obiekty relokowalne. Tabela nagłówków programu koduje widok segmentu przy użyciu nagłówków programu typu struct Elf64_Phdr. Każdy nagłówek programu zawiera pola pokazane w Listingu 2-11.
Listing 2-11: Definition of Elf64_Phdr in /usr/include/elf.h
typedef struct {
uint32_t p_type; /* Segment type */
uint32_t p_flags; /* Segment flags */
uint64_t p_offset; /* Segment file offset */
uint64_t p_vaddr; /* Segment virtual address */
uint64_t p_paddr; /* Segment physical address */
uint64_t p_filesz; /* Segment size in file */
uint64_t p_memsz; /* Segment size in memory */
uint64_t p_align; /* Segment alignment */
} Elf64_Phdr;
Opiszę każde z tych pól w kilku następnych sekcjach. Listing 2-12 pokazuje tabelę nagłówków programu dla przykładowego pliku binarnego, wyświetlaną przez readelf.
Listing 2-12: A typical program header as shown by readelf
$ readelf –wide –segments a.out
Elf file type is EXEC (Executable file)
Entry point 0x400430
There are 9 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000040 0x0000000000400040 0x0000000000400040 0x0001f8 0x0001f8 R E 0x8
INTERP 0x000238 0x0000000000400238 0x0000000000400238 0x00001c 0x00001c R 0x1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
LOAD 0x000000 0x0000000000400000 0x0000000000400000 0x00070c 0x00070c R E 0x200000
LOAD 0x000e10 0x0000000000600e10 0x0000000000600e10 0x000228 0x000230 RW 0x200000
DYNAMIC 0x000e28 0x0000000000600e28 0x0000000000600e28 0x0001d0 0x0001d0 RW 0x8
NOTE 0x000254 0x0000000000400254 0x0000000000400254 0x000044 0x000044 R 0x4
GNU_EH_FRAME 0x0005e4 0x00000000004005e4 0x00000000004005e4 0x000034 0x000034 R 0x4
GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x10
GNU_RELRO 0x000e10 0x0000000000600e10 0x0000000000600e10 0x0001f0 0x0001f0 R 0x1
(1) Section to Segment mapping:
Segment Sections…
00
01 .interp
02 .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version
.gnu.version_r .rela.dyn .rela.plt .init .plt .plt.got .text .fini .rodata
.eh_frame_hdr .eh_frame
03 .init_array .fini_array .jcr .dynamic .got .got.plt .data .bss
04 .dynamic
05 .note.ABI-tag .note.gnu.build-id
06 .eh_frame_hdr
07
08 .init_array .fini_array .jcr .dynamic .got
Zwróć uwagę na mapowanie sekcji na segment na dole wyjścia readelf, które wyraźnie pokazuje, że segmenty to po prostu zbiór sekcji połączonych razem (1). To konkretne mapowanie sekcji na segment jest typowe dla większości plików binarnych ELF, z którymi się spotkasz.