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