I'm experimenting with the concept of pure-static-linked PIE executables on Linux, but running into the problem that the GNU binutils linker insists on adding a PT_INTERP header to the output binary when -pie
is used, even when also given -static
. Is there any way to inhibit this behavior? That is, is there a way to tell GNU ld specifically not to write certain headers to the output file? Perhaps with a linker script?
(Please don't answer with claims that it won't work; I'm well aware that the program still needs relocation processing - load-address-relative relocations only due to my use of -Bsymbolic
- and I have special startup code in place of the standard Scrt1.o
to handle this. But I can't get it to be invoked without the dynamic linker already kicking in and doing the work unless hexedit the PT_INTERP
header out of the binary.)
I think I might have found a solution: simply using -shared
instead of -pie
to make pie binaries. You need a few extra linker options to patch up the behavior, but it seems to avoid the need for a custom linker script. Or in other words, the -shared
linker script is already essentially correct for linking static pie binaries.
If I get it working with this, I'll update the answer with the exact command line I'm using.
Update: It works! Here's the command line:
gcc -shared -static-libgcc -Wl,-static -Wl,-Bsymbolic \
-nostartfiles -fPIE Zcrt1.s Zcrt2.c /usr/lib/crti.o hello.c /usr/lib/crtn.o
where Zcrt1.s is a modified version of Scrt1.s that calls a function in Zcrt2.c before doing its normal work, and the code in Zcrt2.c processes the aux vector just past the argv and environment arrays to find the DYNAMIC section, then loops over the relocation tables and applies all the relative-type relocations (the only ones that should exist).
Now all of this can (with a little work) be wrapped up into a script or gcc specfile...