Static PIE support in GCC

Rich Felker
Mon Jun 1 21:26:00 GMT 2015

A feature I've been interested in getting upstream in GCC for a while
now is support for producing static-linked PIE executables for Linux.
In the model I'm working with, static PIE executables are ET_DYN
format with no PT_INTERP, and are intended to contain only relative
type relocations (no symbol references). A custom crt1 start file
named rcrt1.o is responsible for processing these relative relocations
before passing execution to the libc entry point code. I have as part
of musl libc an implementation of rcrt1.o (for all targets musl
presently supports) that's working for this model. The way it works is
completely analogous to what OpenBSD has done in their fork of GCC
(see, but
aside from adopting the 'r' prefix for crt that they used, which I did
for some level of consistency, my work on static PIE has been
completely independent of the development of this feature in OpenBSD.

While OpenBSD's motivations for static PIE seem to be purely security
focused, I'm also interested in static PIE as a form of executable
that can be used on NOMMU targets. My motivation for doing the
relocations in the start file, rather than with an external program
interpreter, is both to reduce runtime cost on very small systems, and
to make deployment easier. For musl users, one of the main benefits of
static linking is that the resulting binary can be run on systems
without any additional runtime files installed.

Unfortunately, producing static PIE binaries with GCC is not as simple
as passing -static -pie when linking. The linker arguments I've been
using to test this so far have been:

	-shared -Wl,-Bstatic -Wl,-Bsymbolic

and adding the rcrt1.o to the beginning of the inputs. This looks like
something of a hack, and on the GCC command line I would say it is, at
least for -shared which is being used both to suppress the default
crt1 file and to produce ET_DYN output without PT_INTERP. On the other
hand,-Bstatic is just being used to suppress use of .so files to
satisfy -l dependencies, and -Bsymbolic to produce relative
relocations in the output instead of symbol references.

Thankfully this gets a lot less ugly if you put it in the specs. Just

#define LINK_PIE_SPEC "%{pie:-pie} "


#define LINK_PIE_SPEC "%{pie:%{static:-shared -Bsymbolic;:-pie}} "

causes -static -pie to invoke the linker in a manner which matches the
desired static PIE model. Aside from this, a per-target addition to
STARTFILE_SPEC is needed to make GCC choose rcrt1.o instead of Scrt1.o
when -static is used with -pie, and to change the logic for crtbegin
so that -pie's choice of crtbeginS.o overrides -static's crtbeginT.o,
and likewise for crtend.

Before proposing anything in the way of patches I'd like some feedback
on whether this approach is acceptable for upstreaming in GCC. The
obvious alternative to the LINK_PIE_SPEC change is making ld accept
-static -pie and do "the right thing" on its side, but the startfile
changes needed on the GCC side are the same either way.


More information about the Gcc mailing list