This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
PATCH: Avoid use of CFI unless gas creates read-only 64-bit .eh_frame sections on Solaris/x86
- From: Rainer Orth <ro at CeBiTec dot Uni-Bielefeld dot DE>
- To: gcc-patches at gcc dot gnu dot org
- Date: Tue, 26 Jan 2010 11:42:17 +0100
- Subject: PATCH: Avoid use of CFI unless gas creates read-only 64-bit .eh_frame sections on Solaris/x86
When I recently tested mainline on Solaris 11/x86 with the bundled gas
2.19 (/usr/sfw/bin/gas), I noticed that all 64-bit C++ EH tests were
failing. It turned out that this happens because unwind-dw2-fde.c
(__register_frame_info_bases) registers empty (zero-terminator only)
.eh_frame sections. Further investigation reveals that the affected
objects (both executables and shared libraries) have *two* .eh_frame
sections: one read-only consisting only of the zero-terminator, and a
regular read-write one. Since the Sun ld doesn't merge them, both end
up in executables and the empty one happens to be registered.
It turns out that the empty ones are from crtbegin.o/crtend.o
(crtstuff.c), which also heeds EH_TABLES_CAN_BE_READ_ONLY in
config/i386/sol2.h. The `real' ones are created by gas, which supports
.cfi* directives in this and later versions. Unfortunately, GCC and gas
disagree about whether the .eh_frame sections are read-only or
read-write in the 64-bit case: GCC has
/* The Solaris linker will not merge a read-only .eh_frame section
with a read-write .eh_frame section. None of the encodings used
with non-PIC code require runtime relocations. In 64-bit mode,
since there is no backwards compatibility issue, we use a read-only
section for .eh_frame. In 32-bit mode, we use a writable .eh_frame
section in order to be compatible with G++ for Solaris x86. */
#undef EH_TABLES_CAN_BE_READ_ONLY
#define EH_TABLES_CAN_BE_READ_ONLY (TARGET_64BIT)
while gas 2.19 and above have (gas/config/te-solaris.h)
/* The Sun linker doesn't merge read-only and read-write sections into
a single read-write section so we must force all EH frame sections
to be read-write. */
#define DWARF2_EH_FRAME_READ_ONLY 0
There are several possible ways to fix this:
* Make gas and GCC agree about .eh_frame section permissions. I've
implemented this and it will be in both binutils 2.20.1 and 2.21:
http://sourceware.org/ml/binutils/2010-01/msg00401.html
* Fix the Sun linker to allow ro/rw sections mixing. I'm in contact
with the Sun linker maintainers about this, but they state that
section permissions are fundamental to the way Sun ld decides which
input sections end up in which output section. They might be
persuaded to relax the requirement for .eh_frame sections, since the
linker knows their semantics, but that might take some time if it
happens at all.
* Even so, gcc must guard against the current situation to avoid broken
EH, which is what the current patch does. It disables use of .cfi*
directives if 64-bit Solaris/x86 .eh_frame sections are made
read-write by the assembler (i.e. an unfixed version of gas is in
use), so GCC emits the directly itself, and fortunately is consistent
internally :-)
What astonished me at first was that Solaris 10/x86 wasn't affected.
With the bundled gas 2.15 (/usr/sfw/bin/gas), there is of course no
issue since it doesn't support .cfi* at all. But even with gas 2.19 and
above, all 64-bit EH C++ tests work. I could trace this to the fact
that the Solaris 10 ld doesn't support zero-terminator .eh_frame
sections, thus crt{begin, end}.o are built *without*
-fno-asynchronous-unwind-tables and end up with both the manually
generated .eh_frame sections from crtstuff.c *and* the
assembler-generated ones from the .cfi* directives. gas merges those
and creates a single read-write .eh_frame section, so they all end up
read-write and everything works fine.
The patch below avoids the problem and was tested as follows:
* Bootstrap on i386-pc-solaris2.1[01] with gas 2.19.
* Bootstrap on i386-pc-solaris2.1[01] with gas 2.20.51 (i.e. with my
fixes).
The Solaris 10 bootstraps finished without regressions, the Solaris 11
ones are still running. In all cases, CFI was disabled with gas 2.19
and enabled with gas 2.20.51. The Solaris 11 case had already been
checked with the fixed gas and the EH testcases found to be ok.
Ok for mainline?
Rainer
--
-----------------------------------------------------------------------------
Rainer Orth, Center for Biotechnology, Bielefeld University
2010-01-25 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
* configure.ac (gcc_cv_as_cfi_directive) [i?86-*-solaris*]:
Disable cfi directives unless GCC and gas agree on using read-only
.eh_frame sections for 64-bit.
* configure: Regenerate.
diff -r 639f1353c2b9 gcc/configure.ac
--- a/gcc/configure.ac Mon Jan 25 10:22:04 2010 +0000
+++ b/gcc/configure.ac Tue Jan 26 11:09:20 2010 +0100
@@ -2276,7 +2276,23 @@
sed -e /.eh_frame/!d -e N | grep READONLY > /dev/null; then
gcc_cv_as_cfi_directive=no
else
- gcc_cv_as_cfi_directive=yes
+ case "$target" in
+ i?86-*-solaris*)
+ # On Solaris/x86, make sure that GCC and gas agree on using
+ # read-only .eh_frame sections for 64-bit.
+ if $gcc_cv_as --64 -o conftest.o conftest.s > /dev/null 2>&1 && \
+ $gcc_cv_objdump -h conftest.o 2>/dev/null | \
+ sed -e /.eh_frame/!d -e N | \
+ grep READONLY > /dev/null; then
+ gcc_cv_as_cfi_directive=yes
+ else
+ gcc_cv_as_cfi_directive=no
+ fi
+ ;;
+ *)
+ gcc_cv_as_cfi_directive=yes
+ ;;
+ esac
fi
else
# no objdump, err on the side of caution