This is the mail archive of the gcc@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]

Re: v8.S dwarf2 eh frame issues again :(



On Sat, 20 Apr 2002 09:08:39 +0200, Jakub Jelinek wrote:
> On Fri, Apr 19, 2002 at 07:23:57PM -0700, David S. Miller wrote:
> >
> > Dwarf2 unwinds from libjava/testsuite/libjava.lang/invokethrow.java
> > fail to work unless I make the change at the end of thie email to the
> > .eh_frame information added recently to libffi/src/sparc/v8.S

I've been tracking down a similar problems with C++ exceptions over the
last few days.  With any luck it's the same problem.

> > I don't understand the .eh_frame format at all, basically what I did
> > was compile a dummy "extern int bar(void); int foo(void) { bar(); }"
> > with -g -fexceptions and copied the .eh_frame section code into v8.S
> > and then the test started working.
>
> Please use -fexceptions -fpic -dA to generate eh_frame. Does it work
> then?
>
> > Either it is a bug in binutils eh frame optimizations, the .eh_frame
> > specification currently in v8.S, or the runtime unwinder itself has an
> > .eh_frame decoding bug of some sort.

If it's the same as what I've been seeing then it is a bug in bfd in the
binutils.  The problem is occuring when a CIE is found to be the same as
the previous one and is removed (in _bfd_elf_discard_section_eh_frame in
bfd/elf-eh-frame.c).  What appears to be happening is that a CIE from one
object file is dropped and it's FDEs set to point at the previous object
file's FDE.  The FDEs contain relocations into the .text section of the
object file (the initial_location field in the FDE), and the CIEs contain
relocations into the .data section to find a pointer to
__gxx_personality_v0 (or presumably __gcj_personality_v0 in the case of
Java).

Then _bfd_final_link_relocate is called to merge handle relocations which
does pcrel relocations based on the original size of .eh_frame section
(before the CIE was dropped).  Finally, we write out the .eh_frame section
using _bfd_elf_write_section_eh_frame which is supposed to adjust the
relocations to compensate for any CIEs that have been removed.
Unfortunately, _bfd_elf_write_section_eh_frame only adjusts the relocation
from the FDE to the .text sec and not the CIE personality one.

The patch below (to the 2.12 release) fixes the problem on my machine
(i386) for the test case that I've been playing with.  I've not checked
that the patch doesn't break anything else, and I don't know whether the
personality can be encoded in any other ways that need fixing up similarly
-- a brief grep of gcc's config/* headers suggest that only
DW_EH_PE_absptr, DW_EH_PE_indirect | DW_EH_PE_pcrel and DW_EH_PE_indirect
| DW_EH_PE_datarel are ever used, but I could be wrong.


--- binutils-2.12-clean/bfd/elf-eh-frame.c	Sat Apr 20 15:59:42 2002
+++ binutils-2.12/bfd/elf-eh-frame.c	Sat Apr 20 16:02:13 2002
@@ -946,7 +946,7 @@ _bfd_elf_write_section_eh_frame (abfd, s
 	{
 	  /* CIE */
 	  cie_offset = sec_info->entry[i].new_offset;
-	  if (sec_info->entry[i].make_relative
+	  if (1 || sec_info->entry[i].make_relative
 	      || sec_info->entry[i].make_lsda_relative)
 	    {
 	      unsigned char *aug;
@@ -956,7 +956,8 @@ _bfd_elf_write_section_eh_frame (abfd, s
 	      /* Need to find 'R' or 'L' augmentation's argument and
modify
 		 DW_EH_PE_* value.  */
 	      action = (sec_info->entry[i].make_relative ? 1 : 0)
-		       | (sec_info->entry[i].make_lsda_relative ? 2 : 0);
+		       | (sec_info->entry[i].make_lsda_relative ? 2 : 0)
+		       | 4;
 	      buf = contents + sec_info->entry[i].offset;
 	      /* Skip length, id and version.  */
 	      buf += 9;
@@ -992,6 +993,20 @@ _bfd_elf_write_section_eh_frame (abfd, s
 		      buf = (contents
 			     + ((buf - contents + per_width - 1)
 				& ~((bfd_size_type) per_width - 1)));
+
+		    if ((per_encoding & 0x70) == DW_EH_PE_pcrel)
+		      {
+			bfd_vma value;
+
+			value = read_value( abfd, buf, per_width );
+			value += (sec_info->entry[i].offset
+ 				  - sec_info->entry[i].new_offset);
+
+			write_value( abfd, buf, value, per_width );
+		      }
+
+		    action &= ~4;
+
 		    buf += per_width;
 		    break;
 		  case 'R':


While I was working out this patch, I noticed that when comparing a CIE to
the previous one as a candiate for removal, it essentially checks that the
two CIEs are binary identical.  If however, the personality is stored as a
DW_EH_PE_pcrel | DW_EH_PE_indirect (as it will be if you compile with
-fPIC on an i386), this means that two CIEs in different object files can
quite possibly have the same value of cie->personality (which is just an
offset into the .data section of the separate object files) but actually
be pointing to different things.  This will only matter when object files
with different personalities are being linked together, and so probably
doesn't affect many people.

Hope this helps.

--
Richard Smith



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