This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]