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>