RFC: Padding segments to eliminate gaps

Nick Clifton nickc@redhat.com
Tue Jan 21 16:38:46 GMT 2025


Hi Guys,

  We have an interesting situation here at RedHat.  For various
  reasons(1) we want to ensure that there are no gaps between loadable
  segments in a binary.  But we do not want to increase the size of
  binaries unnecessarily.

  Originally I tried increasing the p_memsz and p_filesz of loadable
  segments to eliminate the gaps.  Without actually adding in any extra
  sections.  (As far as I can tell the ELF standard does not require
  that segments be completely filled with sections).  But this proved to
  be a bust as tools like objcopy/strip could not handle the empty parts
  of the segments.  (This is a potential bug in the BFD library, but I
  chose not to investigate as I felt that fixing it might break lots of
  things).

  Instead I have gone with a second method - adding a new option to
  objcopy that inserts padding sections that fill up segments so that
  they end at the start of the next segments.  The new sections are
  SHT_NOBITS so that they do not take up any extra space in the file
  (well apart from their section headers), and using objcopy means that
  the transformation can be performed post-link, possibly after
  stripping or other kinds of file munging.

  I am not sure if this feature is really suitable for submission to the
  upstream sources.  It feels a bit hackish to me.  But maybe someone
  will be interested in it, which is why I am posting the patch here.

  As for what the results look like, here is a short example:

   $ gcc hello.c
   $ objcopy --add-segment-padding-sections a.out a.new
   $ ls -l a.out a.new
     -rwxr-xr-x. 1 nickc nickc 17832 Jan 21 14:27 a.out*
     -rwxr-xr-x. 1 nickc nickc 18064 Jan 21 14:29 a.new*

   (a small increase in file size)
   
   $ readelf -lW a.out
     [...]
     Type           Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
     [...]
     LOAD           0x000000 0x0000000000400000 0x0000000000400000 0x00039c 0x00039c R   0x1000
     LOAD           0x001000 0x0000000000401000 0x0000000000401000 0x000155 0x000155 R E 0x1000
     LOAD           0x002000 0x0000000000402000 0x0000000000402000 0x00024c 0x00024c R   0x1000
     LOAD           0x002df8 0x0000000000403df8 0x0000000000403df8 0x000228 0x000230 RW  0x1000

  $ readelf -lW a.new

     LOAD           0x000000 0x0000000000400000 0x0000000000400000 0x00039c 0x001000 R   0x1000
     LOAD           0x001000 0x0000000000401000 0x0000000000401000 0x000155 0x001000 R E 0x1000
     LOAD           0x002000 0x0000000000402000 0x0000000000402000 0x00024c 0x001000 R   0x1000
     LOAD           0x002df8 0x0000000000403df8 0x0000000000403df8 0x000228 0x000230 RW  0x1000

  (note the change in MemSiz)

     Section to Segment mapping:
       Segment Sections...
       02     .note.gnu.property .note.gnu.build-id .note.ABI-tag .segment.pad.2 
       03     .init .plt .text .fini .segment.pad.3 
       04     .interp .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .rodata .eh_frame_hdr .eh_frame .segment.pad.4 
  (the .segment.pad.N sections are the newly inserted padding sections)

  If you have any comments or questions please feel free to let me know.

Cheers
  Nick

(1) The presence of gaps between loadable segments leads to the
possibility that something else might be inserted in between them.
Typically only if the common page size and maximum page size for the
given architecture are different.  But theoretically it could happen for
any architecture.  This load of unexpected code/data might then pose a
security risk, if a buffer overflow attack or similar is able to reach
it.

-------------- next part --------------
A non-text attachment was scrubbed...
Name: binutils-segment-gap.patch
Type: text/x-patch
Size: 9204 bytes
Desc: not available
URL: <https://sourceware.org/pipermail/binutils/attachments/20250121/43ac4454/attachment.bin>


More information about the Binutils mailing list