Turn libc.so into an ld script
Jeremie Le Hen
jlh at FreeBSD.org
Sat May 25 08:06:41 UTC 2013
Hi,
There has been quite a while since the SSP glue has been committed in
the tree. Yet there has always been a gloomy corner case since then
that was reported from time to time, mainly by port maintainers, which
has been hard to reproduce. This is the main showstopper to enable SSP
for ports by default.
On i386 for PIC objects, gcc uses the __stack_chk_fail_local hidden
symbol instead of calling __stack_chk_fail directly [1]. This happen
not only with our gcc-4.2.1 but also with the latest gcc-4.8. If you
want the very nasty details, see [2].
OTOH the problem doesn't exist on other architectures. It also doesn't
exist with Clang as the latter will somehow manage to create the
function in the object file at compile time (contrary to only
referencing it through a symbol that will be brought in at link time).
In a perfect world, when an object file is compiled with
-fstack-protector, it will be linked into a binary or a DSO with this
same flag as well, so GCC will add libssp_nonshared.a to the linker
command-line. Unfortunately, we don't control softwares in ports and we
may have such broken DSO. This is the whole point of this patch.
I wrote a specific test that exhibits the error:
http://people.freebsd.org/~jlh/twisted_ssp_linktime_fail.shar
If you run "make main" on i386, it will fail. More details at [3].
So the attached patch turns libc.so into an ld script which will
automatically _propose_ libssp_nonshared.a along with the real libc DSO
to the linker. It is important to understand that the object file
contained in this library will be pulled in the resulting binary
_only if_ the linker notices one of its symbols is needed (i.e. one of
the SSP symbol is missing). Otherwise nothing is changed, except a
slight theorical overhead that I wasn't able to measure on my Core 2
developement machine with -j 4:
x current
+ current_libc_ldscript
+------------------------------------------------------------------------------+
| ++ x+ xx + x|
|||_____________M__M_______A____A___________________|__________| |
+------------------------------------------------------------------------------+
N Min Max Median Avg Stddev
x 4 9130 9227 9136 9157 46.740418
+ 4 9126 9207 9132 9148 39.420807
Any objection to the patch?
Thanks for reading,
[1] See comment here if you wonder why:
sed -n 19460,+3p src/contrib/gcc/config/i386/i386.c
[2] When compiling a source file to an object file, if you use something
which is external to the compilation unit, GCC doesn't know yet if
this symbol will be inside or outside the DSO. So it expects the
worst case and routes the symbol through the GOT, which means
additional space and extra relocation for rtld(1).
Declaring a symbol has hidden tells GCC to use the optimal route (no
GOT), but on the other hand this means the symbol has to be provided
in the same DSO (namely libssp_nonshared.a).
On i386, GCC actually uses an hidden symbol for SSP in PIC objects
to save PIC register setup, as said in [1].
[3] As abstractly explained in [2], the problem shows up as long as you
compile a PIC (or PIE) object but you don't link it directly with
libssp_nonshared.a.
So in the test I gave, you can also trigger the problem by setting
"BIN_CFLAGS= -fstack-protector-all -fPIE" and leaving BIN_LDFLAGS
blank, whatever you did with LIB_{CFLAGS,LDFLAGS}.
This won't happen without -fPIE here, because a non-hidden symbol
will be emitted in that case.
--
Jeremie Le Hen
Scientists say the world is made up of Protons, Neutrons and Electrons.
They forgot to mention Morons.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: libc_ldscript.diff
Type: text/x-diff
Size: 775 bytes
Desc: not available
URL: <http://lists.freebsd.org/pipermail/freebsd-hackers/attachments/20130525/7d81b45a/attachment.diff>
More information about the freebsd-hackers
mailing list