Search code examples
elf

What exactly is the point of the p_align field in the program headers of an ELF file


What exactly is the purpose of the p_align field? Every source online has only said something vague about it saying the "required alignment" of segment or only that its a value so that p_vaddr = p_offset mod p_allign. Using readelf, I can see that LOAD segments have p_align of 4KB. The modulo statement with p_align being 4KB mathematically guarantees its possible to mmap file pages to memory pages to correctly load the segment. This is the only utility I see for p_align. But it is anyways required for p_align of LOAD segments to be page-sized, so is there no purpose?


Solution

  • What exactly is the purpose of the p_align field?

    To make it possible to use mmap to bring LOAD segments into memory.

    I can see that LOAD segments have p_align of 4KB. The modulo statement with p_align being 4KB mathematically guarantees its possible to mmap file pages to memory pages to correctly load the segment.

    Some architectures have a different page size. For example powerpc64 page size is 64KB, and binaries linked for it will have p_align == 0x10000.

    Further, x86_64 supports multiple page sizes, and if you want to be able to use e.g. 2MB pages for your binary, then you need to set alignment appropriately:

    echo "int main() { return 0; }" | gcc -xc - -Wl,-z,max-page-size=0x200000
    
    readelf -Wl ./a.out
    
    Elf file type is EXEC (Executable file)
    Entry point 0x600020
    There are 13 program headers, starting at offset 64
    
    Program Headers:
      Type           Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
      PHDR           0x000040 0x0000000000400040 0x0000000000400040 0x0002d8 0x0002d8 R   0x8
      INTERP         0x000318 0x0000000000400318 0x0000000000400318 0x00001c 0x00001c R   0x1
          [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
      LOAD           0x000000 0x0000000000400000 0x0000000000400000 0x0004b8 0x0004b8 R   0x200000
      LOAD           0x200000 0x0000000000600000 0x0000000000600000 0x000121 0x000121 R E 0x200000
      LOAD           0x400000 0x0000000000800000 0x0000000000800000 0x00009c 0x00009c R   0x200000
      LOAD           0x5ffe38 0x0000000000bffe38 0x0000000000bffe38 0x0001cc 0x0001d0 RW  0x200000
      DYNAMIC        0x5ffe48 0x0000000000bffe48 0x0000000000bffe48 0x000190 0x000190 RW  0x8
    ...
    

    Indeed, 2MB pages used to be the default on x86_64, precisely because someone might decide to use 2MB (aka huge) pages, until the default was changed to 4KB in this commit.