elf

Segments do not respect their own alignment


I noticed that ELF binaries often do not respect their Alignment value for LOAD segments.

The alignment is specified in the program header and man pages describe the p_align value like this:

       p_align
              This member holds the value to which the segments are
              aligned in memory and in the file.  Loadable process
              segments must have congruent values for p_vaddr and
              p_offset, modulo the page size.  Values of zero and one
              mean no alignment is required.  Otherwise, p_align should
              be a positive, integral power of two, and p_vaddr should
              equal p_offset, modulo p_align.

So it seems to be clear that the Segments in the file should be aligned to this value.

Why isn't this the case for the second LOAD segment in this example hello world binary?

Its supposed to be aligned to 0x10000 but it actually starts at offset 0x000db8.

Program Headers:
  Type           Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
  PHDR           0x000040 0x0000000000000040 0x0000000000000040 0x0001f8 0x0001f8 R   0x8
  INTERP         0x000238 0x0000000000000238 0x0000000000000238 0x00001b 0x00001b R   0x1
  LOAD           0x000000 0x0000000000000000 0x0000000000000000 0x000b6c 0x000b6c R E 0x10000
  LOAD           0x000db8 0x0000000000010db8 0x0000000000010db8 0x000280 0x000288 RW  0x10000
  DYNAMIC        0x000dc8 0x0000000000010dc8 0x0000000000010dc8 0x0001e0 0x0001e0 RW  0x8
  NOTE           0x000254 0x0000000000000254 0x0000000000000254 0x000044 0x000044 R   0x4
  GNU_EH_FRAME   0x00098c 0x000000000000098c 0x000000000000098c 0x00006c 0x00006c R   0x4
  GNU_STACK      0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW  0x10
  GNU_RELRO      0x000db8 0x0000000000010db8 0x0000000000010db8 0x000248 0x000248 R   0x1

Solution

  • p_vaddr should equal p_offset, modulo p_align

    You have:

      Type  Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
      LOAD  0x000db8 0x0000000000010db8 0x0000000000010db8 0x000280 0x000288 RW  0x10000
    

    p_vaddr % p_align == 0x10db8 % 0x10000 == 0xdb8, which is equal p_offset.

    The requirement is satisfied.

    So it seems to be clear that the Segments in the file should be aligned to this value.

    No, you are mis-interpreting what the requirement actually is.