Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 25 May 2013 10:06:40 +0200
From:      Jeremie Le Hen <jlh@FreeBSD.org>
To:        freebsd-hackers@FreeBSD.org
Subject:   Turn libc.so into an ld script
Message-ID:  <20130525080639.GS71389@caravan.chchile.org>

next in thread | raw e-mail | index | archive | help

--FsscpQKzF/jJk6ya
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

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.

--FsscpQKzF/jJk6ya
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="libc_ldscript.diff"

Index: lib/libc/Makefile
===================================================================
--- lib/libc/Makefile	(revision 250307)
+++ lib/libc/Makefile	(working copy)
@@ -33,6 +33,12 @@
 INSTALL_PIC_ARCHIVE=
 PRECIOUSLIB=
 
+# Only use an ld script in place of the so file on i386, because of
+# the way -fstack-protector works on gcc.
+.if ${MACHINE_CPUARCH} == "i386"
+SHLIB_LDSCRIPT=libc.ldscript
+.endif
+
 .ifndef NO_THREAD_STACK_UNWIND
 CANCELPOINTS_CFLAGS=-fexceptions
 CFLAGS+=${CANCELPOINTS_CFLAGS}
Index: lib/libc/libc.ldscript
===================================================================
--- lib/libc/libc.ldscript	(revision 0)
+++ lib/libc/libc.ldscript	(working copy)
@@ -0,0 +1,2 @@
+/* $FreeBSD$ */
+GROUP ( @@SHLIB@@ @@LIBDIR@@/libssp_nonshared.a )

--FsscpQKzF/jJk6ya--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20130525080639.GS71389>