public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* Fix ld/418
@ 2004-09-30 14:37 Alan Modra
  2004-09-30 14:51 ` Jakub Jelinek
  2004-10-08 12:58 ` Richard Sandiford
  0 siblings, 2 replies; 9+ messages in thread
From: Alan Modra @ 2004-09-30 14:37 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: binutils, mendell

Hi Jakub,
  I'd like your opinion on the following patch to fix
http://sources.redhat.com/bugzilla/show_bug.cgi?id=418.  xlc apparently
uses a LSDA that isn't a pointer, thus making it pc-relative doesn't
really make much sense.  The changelog below should make it clear
what I'm doing.

	* elf-bfd.h (struct eh_cie_fde): Add need_relative and
	need_lsda_relative.
	* elf-eh-frame.c (_bfd_elf_eh_frame_section_offset): Set
	need_relative or need_lsda_relative if we are processing an
	offset for a reloc on a FDE initial loc or LSDA field
	respectively.
	(_bfd_elf_write_section_eh_frame): Test need_relative and
	need_lsda_relative in place of corresponding make_* field
	when deciding to use pc-relative encodings.

BTW, I haven't tested this very well yet, just binutils testsuite runs
and checking that this cures the testcase.  I intend to build gcc and
glibc overnight, and verify that it doesn't cause regressions before
committing.

An alternative hack that works in this particular case is to not
translate lsda to pcrel if lsda is too small to be a pointer.

Index: bfd/elf-bfd.h
===================================================================
RCS file: /cvs/src/src/bfd/elf-bfd.h,v
retrieving revision 1.158
diff -u -p -r1.158 elf-bfd.h
--- bfd/elf-bfd.h	17 Sep 2004 07:14:25 -0000	1.158
+++ bfd/elf-bfd.h	30 Sep 2004 14:00:31 -0000
@@ -296,7 +296,9 @@ struct eh_cie_fde
   unsigned int cie : 1;
   unsigned int removed : 1;
   unsigned int make_relative : 1;
+  unsigned int need_relative : 1;
   unsigned int make_lsda_relative : 1;
+  unsigned int need_lsda_relative : 1;
   unsigned int per_encoding_relative : 1;
 };
 
Index: bfd/elf-eh-frame.c
===================================================================
RCS file: /cvs/src/src/bfd/elf-eh-frame.c,v
retrieving revision 1.31
diff -u -p -r1.31 elf-eh-frame.c
--- bfd/elf-eh-frame.c	24 Jun 2004 04:46:17 -0000	1.31
+++ bfd/elf-eh-frame.c	30 Sep 2004 13:59:52 -0000
@@ -775,7 +775,10 @@ _bfd_elf_eh_frame_section_offset (bfd *o
   if (sec_info->entry[mid].make_relative
       && ! sec_info->entry[mid].cie
       && offset == sec_info->entry[mid].offset + 8)
-    return (bfd_vma) -2;
+    {
+      sec_info->entry[mid].need_relative = 1;
+      return (bfd_vma) -2;
+    }
 
   /* If converting LSDA pointers to DW_EH_PE_pcrel, there will be no need
      for run-time relocation against LSDA field.  */
@@ -783,7 +786,10 @@ _bfd_elf_eh_frame_section_offset (bfd *o
       && ! sec_info->entry[mid].cie
       && (offset == (sec_info->entry[mid].offset + 8
 		     + sec_info->entry[mid].lsda_offset)))
-    return (bfd_vma) -2;
+    {
+      sec_info->entry[mid].need_lsda_relative = 1;
+      return (bfd_vma) -2;
+    }
 
   return (offset + sec_info->entry[mid].new_offset
 	  - sec_info->entry[mid].offset);
@@ -850,8 +856,8 @@ _bfd_elf_write_section_eh_frame (bfd *ab
 	{
 	  /* CIE */
 	  cie_offset = sec_info->entry[i].new_offset;
-	  if (sec_info->entry[i].make_relative
-	      || sec_info->entry[i].make_lsda_relative
+	  if (sec_info->entry[i].need_relative
+	      || sec_info->entry[i].need_lsda_relative
 	      || sec_info->entry[i].per_encoding_relative)
 	    {
 	      unsigned char *aug;
@@ -860,8 +866,8 @@ _bfd_elf_write_section_eh_frame (bfd *ab
 
 	      /* 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)
+	      action = (sec_info->entry[i].need_relative ? 1 : 0)
+		       | (sec_info->entry[i].need_lsda_relative ? 2 : 0)
 		       | (sec_info->entry[i].per_encoding_relative ? 4 : 0);
 	      buf = contents + sec_info->entry[i].offset;
 	      /* Skip length, id and version.  */
@@ -968,7 +974,7 @@ _bfd_elf_write_section_eh_frame (bfd *ab
 			      + sec_info->entry[i].offset + 8);
 		  break;
 		}
-	      if (sec_info->entry[i].make_relative)
+	      if (sec_info->entry[i].need_relative)
 		value -= (sec->output_section->vma + sec->output_offset
 			  + sec_info->entry[i].new_offset + 8);
 	      write_value (abfd, buf, value, width);
@@ -983,7 +989,7 @@ _bfd_elf_write_section_eh_frame (bfd *ab
 	    }
 
 	  if ((sec_info->entry[i].lsda_encoding & 0xf0) == DW_EH_PE_pcrel
-	      || sec_info->entry[i].make_lsda_relative)
+	      || sec_info->entry[i].need_lsda_relative)
 	    {
 	      buf += sec_info->entry[i].lsda_offset;
 	      width = get_DW_EH_PE_width (sec_info->entry[i].lsda_encoding,
@@ -997,7 +1003,7 @@ _bfd_elf_write_section_eh_frame (bfd *ab
 		      == DW_EH_PE_pcrel)
 		    value += (sec_info->entry[i].offset
 			      - sec_info->entry[i].new_offset);
-		  else if (sec_info->entry[i].make_lsda_relative)
+		  else if (sec_info->entry[i].need_lsda_relative)
 		    value -= (sec->output_section->vma + sec->output_offset
 			      + sec_info->entry[i].new_offset + 8
 			      + sec_info->entry[i].lsda_offset);

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Fix ld/418
  2004-09-30 14:37 Fix ld/418 Alan Modra
@ 2004-09-30 14:51 ` Jakub Jelinek
  2004-10-08 12:58 ` Richard Sandiford
  1 sibling, 0 replies; 9+ messages in thread
From: Jakub Jelinek @ 2004-09-30 14:51 UTC (permalink / raw)
  To: binutils, mendell

On Fri, Oct 01, 2004 at 12:06:57AM +0930, Alan Modra wrote:
> Hi Jakub,
>   I'd like your opinion on the following patch to fix
> http://sources.redhat.com/bugzilla/show_bug.cgi?id=418.  xlc apparently
> uses a LSDA that isn't a pointer, thus making it pc-relative doesn't
> really make much sense.  The changelog below should make it clear
> what I'm doing.
> 
> 	* elf-bfd.h (struct eh_cie_fde): Add need_relative and
> 	need_lsda_relative.
> 	* elf-eh-frame.c (_bfd_elf_eh_frame_section_offset): Set
> 	need_relative or need_lsda_relative if we are processing an
> 	offset for a reloc on a FDE initial loc or LSDA field
> 	respectively.
> 	(_bfd_elf_write_section_eh_frame): Test need_relative and
> 	need_lsda_relative in place of corresponding make_* field
> 	when deciding to use pc-relative encodings.

Looks good.

	Jakub

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Fix ld/418
  2004-09-30 14:37 Fix ld/418 Alan Modra
  2004-09-30 14:51 ` Jakub Jelinek
@ 2004-10-08 12:58 ` Richard Sandiford
  2004-10-08 14:09   ` Alan Modra
  1 sibling, 1 reply; 9+ messages in thread
From: Richard Sandiford @ 2004-10-08 12:58 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: binutils, mendell

[-- Attachment #1: Type: text/plain, Size: 2525 bytes --]

Hi Alan,

Alan Modra <amodra@bigpond.net.au> writes:
> 	* elf-bfd.h (struct eh_cie_fde): Add need_relative and
> 	need_lsda_relative.
> 	* elf-eh-frame.c (_bfd_elf_eh_frame_section_offset): Set
> 	need_relative or need_lsda_relative if we are processing an
> 	offset for a reloc on a FDE initial loc or LSDA field
> 	respectively.
> 	(_bfd_elf_write_section_eh_frame): Test need_relative and
> 	need_lsda_relative in place of corresponding make_* field
> 	when deciding to use pc-relative encodings.
>
> BTW, I haven't tested this very well yet, just binutils testsuite runs
> and checking that this cures the testcase.  I intend to build gcc and
> glibc overnight, and verify that it doesn't cause regressions before
> committing.

Sorry if I'm duplicating another report, but this patch breaks the frame
info on MIPS targets such as mips-sgi-irix6.5.  need_lsda_relative is only
set for FDEs:

  /* If converting LSDA pointers to DW_EH_PE_pcrel, there will be no need
     for run-time relocation against LSDA field.  */
  if (sec_info->entry[mid].make_lsda_relative
      && ! sec_info->entry[mid].cie
      && (offset == (sec_info->entry[mid].offset + 8
		     + sec_info->entry[mid].lsda_offset)))
    {
      sec_info->entry[mid].need_lsda_relative = 1;
      return (bfd_vma) -2;
    }

and never for CIEs.  We'll therefore not update the CIE LSDA encoding
to match the new pc-relative LSDA fields.

You can duplicate this by configuring for mips-sgi-irix6.5 and doing:

    ./gas/as-new foo.s -o foo.o
    ./ld/ld-new foo.o -o foo.so -shared
    ./binutils/readelf -wf foo.so

00000000 00000018 00000000 CIE
  Version:               1
  Augmentation:          "zPL"
  Code alignment factor: 1
  Data alignment factor: 4
  Return address column: 31
  Augmentation data:     00 00 00 00 00 00
                                        ^^
                       DW_EH_absptr, should be DW_EH_pcrel

  DW_CFA_def_cfa: r29 ofs 0
  DW_CFA_nop
  DW_CFA_nop

0000001c 00000028 00000020 FDE cie=00000000 pc=5ffe04f0..5ffe05cc
  Augmentation data:     00 00 00 1b
                         ^^^^^^^^^^^
                         now PC-relative

  DW_CFA_advance_loc: 4 to 5ffe04f4
  DW_CFA_def_cfa_offset: 64
  DW_CFA_advance_loc: 16 to 5ffe0504
  DW_CFA_offset_extended_sf: r16 at cfa-32
  DW_CFA_offset_extended_sf: r28 at cfa-24
  DW_CFA_offset_extended_sf: r30 at cfa-16
  DW_CFA_offset_extended_sf: r31 at cfa-8
  DW_CFA_advance_loc: 4 to 5ffe0508
  DW_CFA_def_cfa: r30 ofs 64
  DW_CFA_nop
  DW_CFA_nop
  DW_CFA_nop

Richard


[-- Attachment #2: foo.s --]
[-- Type: application/octet-stream, Size: 2646 bytes --]

	.file	1 "foo.C"
	.abicalls
	.text
	.align	2
	.globl	_Z3barv
.LFB2:
	.ent	_Z3barv
_Z3barv:
	.frame	$fp,64,$31		# vars= 32, regs= 4/0, args= 0, gp= 0
	.mask	0xd0010000,-8
	.fmask	0x00000000,0
	.set	noreorder
	.set	nomacro
	
	addiu	$sp,$sp,-64
.LCFI0:
	sd	$31,56($sp)
.LCFI1:
	sd	$fp,48($sp)
.LCFI2:
	sd	$28,40($sp)
.LCFI3:
	sd	$16,32($sp)
.LCFI4:
	move	$fp,$sp
.LCFI5:
	lui	$28,%hi(%neg(%gp_rel(_Z3barv)))
	addu	$28,$28,$25
	addiu	$28,$28,%lo(%neg(%gp_rel(_Z3barv)))
	lw	$25,%call16(_Z3foov)($28)
.LEHB0:
	jal	$25
	nop

.LEHE0:
	b	.L6
	nop

.L9:
	sw	$4,16($fp)
	move	$3,$5
	li	$2,1			# 0x1
	beq	$3,$2,.L3
	nop

	lw	$4,16($fp)
	lw	$25,%call16(_Unwind_Resume)($28)
.LEHB1:
	jal	$25
	nop

.LEHE1:
.L3:
	lw	$4,16($fp)
	lw	$25,%call16(__cxa_begin_catch)($28)
	jal	$25
	nop

	lw	$2,0($2)
	sw	$2,0($fp)
	lw	$25,%call16(_Z3foov)($28)
.LEHB2:
	jal	$25
	nop

.LEHE2:
	b	.L4
	nop

.L8:
	sw	$4,16($fp)
.L5:
	lw	$16,16($fp)
	lw	$25,%call16(__cxa_end_catch)($28)
	jal	$25
	nop

	sw	$16,16($fp)
	lw	$4,16($fp)
	lw	$25,%call16(_Unwind_Resume)($28)
.LEHB3:
	jal	$25
	nop

.LEHE3:
.L4:
	lw	$25,%call16(__cxa_end_catch)($28)
	jal	$25
	nop

.L6:
	move	$sp,$fp
	ld	$31,56($sp)
	ld	$fp,48($sp)
	ld	$28,40($sp)
	ld	$16,32($sp)
	addiu	$sp,$sp,64
	j	$31
	nop

	.set	macro
	.set	reorder
	.end	_Z3barv
.LFE2:
	.size	_Z3barv, .-_Z3barv
	.section	.gcc_except_table,"aw",@progbits
	.align	2
.LLSDA2:
	.byte	0xff
	.byte	0x0
	.uleb128 .LLSDATT2-.LLSDATTD2
.LLSDATTD2:
	.byte	0x1
	.uleb128 .LLSDACSE2-.LLSDACSB2
.LLSDACSB2:
	.uleb128 .LEHB0-.LFB2
	.uleb128 .LEHE0-.LEHB0
	.uleb128 .L9-.LFB2
	.uleb128 0x1
	.uleb128 .LEHB1-.LFB2
	.uleb128 .LEHE1-.LEHB1
	.uleb128 0x0
	.uleb128 0x0
	.uleb128 .LEHB2-.LFB2
	.uleb128 .LEHE2-.LEHB2
	.uleb128 .L8-.LFB2
	.uleb128 0x0
	.uleb128 .LEHB3-.LFB2
	.uleb128 .LEHE3-.LEHB3
	.uleb128 0x0
	.uleb128 0x0
.LLSDACSE2:
	.byte	0x1
	.byte	0x0
	.align	2
	.word	_ZTIi
.LLSDATT2:
	.text
	.section	.eh_frame,"aw",@progbits
.Lframe1:
	.4byte	.LECIE1-.LSCIE1
.LSCIE1:
	.4byte	0x0
	.byte	0x1
	.ascii	"zPL\000"
	.uleb128 0x1
	.sleb128 4
	.byte	0x1f
	.uleb128 0x6
	.byte	0x0
	.4byte	__gxx_personality_v0
	.byte	0x0
	.byte	0xc
	.uleb128 0x1d
	.uleb128 0x0
	.align	2
.LECIE1:
.LSFDE1:
	.4byte	.LEFDE1-.LASFDE1
.LASFDE1:
	.4byte	.LASFDE1-.Lframe1
	.4byte	.LFB2
	.4byte	.LFE2-.LFB2
	.uleb128 0x4
	.4byte	.LLSDA2
	.byte	0x4
	.4byte	.LCFI0-.LFB2
	.byte	0xe
	.uleb128 0x40
	.byte	0x4
	.4byte	.LCFI4-.LCFI0
	.byte	0x11
	.uleb128 0x10
	.sleb128 -8
	.byte	0x11
	.uleb128 0x1c
	.sleb128 -6
	.byte	0x11
	.uleb128 0x1e
	.sleb128 -4
	.byte	0x11
	.uleb128 0x1f
	.sleb128 -2
	.byte	0x4
	.4byte	.LCFI5-.LCFI4
	.byte	0xc
	.uleb128 0x1e
	.uleb128 0x40
	.align	2
.LEFDE1:
	.align	0

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Fix ld/418
  2004-10-08 12:58 ` Richard Sandiford
@ 2004-10-08 14:09   ` Alan Modra
  2004-10-08 14:34     ` Alan Modra
  0 siblings, 1 reply; 9+ messages in thread
From: Alan Modra @ 2004-10-08 14:09 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: Jakub Jelinek, binutils, mendell

On Fri, Oct 08, 2004 at 01:58:03PM +0100, Richard Sandiford wrote:
> need_lsda_relative is only set for FDEs and never for CIEs.

Blagh.  I was just about to go to bed.  Silly mistake on my part, but
will require more than just a one-liner to fix.  I'll need to write
some code that trundles through the struct eh_cie_fde info and ties
together fdes and cies.  Tomorrow.

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Fix ld/418
  2004-10-08 14:09   ` Alan Modra
@ 2004-10-08 14:34     ` Alan Modra
  2004-10-10  7:54       ` Alan Modra
  0 siblings, 1 reply; 9+ messages in thread
From: Alan Modra @ 2004-10-08 14:34 UTC (permalink / raw)
  To: Richard Sandiford, Jakub Jelinek, binutils, mendell

On Fri, Oct 08, 2004 at 11:39:53PM +0930, Alan Modra wrote:
> On Fri, Oct 08, 2004 at 01:58:03PM +0100, Richard Sandiford wrote:
> > need_lsda_relative is only set for FDEs and never for CIEs.
> 
> Blagh.  I was just about to go to bed.  Silly mistake on my part, but
> will require more than just a one-liner to fix.  I'll need to write
> some code that trundles through the struct eh_cie_fde info and ties
> together fdes and cies.  Tomorrow.

Like this.  Untested.  I'll commit tomorrow after some testing.

Index: bfd/elf-eh-frame.c
===================================================================
RCS file: /cvs/src/src/bfd/elf-eh-frame.c,v
retrieving revision 1.32
diff -u -p -r1.32 elf-eh-frame.c
--- bfd/elf-eh-frame.c	1 Oct 2004 00:51:37 -0000	1.32
+++ bfd/elf-eh-frame.c	8 Oct 2004 14:31:41 -0000
@@ -812,6 +812,7 @@ _bfd_elf_write_section_eh_frame (bfd *ab
   unsigned int leb128_tmp;
   unsigned int cie_offset = 0;
   unsigned int ptr_size;
+  unsigned int last_cie_ndx;
 
   ptr_size = (elf_elfheader (sec->owner)->e_ident[EI_CLASS]
 	      == ELFCLASS64) ? 8 : 4;
@@ -828,6 +829,41 @@ _bfd_elf_write_section_eh_frame (bfd *ab
   if (hdr_info->array == NULL)
     hdr_info = NULL;
 
+  /* Copy FDE's need_* flags to CIE.  */
+  last_cie_ndx = (unsigned) -1;
+  for (i = 0; i < sec_info->count; ++i)
+    {
+      if (sec_info->entry[i].removed)
+	continue;
+      if (sec_info->entry[i].cie)
+	last_cie_ndx = i;
+      else if (sec_info->entry[i].size > 4)
+	{
+	  BFD_ASSERT (last_cie_ndx != (unsigned) -1);
+	  sec_info->entry[last_cie_ndx].need_relative
+	    |= sec_info->entry[i].need_relative;
+	  sec_info->entry[last_cie_ndx].need_lsda_relative
+	    |= sec_info->entry[i].need_lsda_relative;
+	}
+    }
+  /* And now from CIE to FDEs.  */
+  last_cie_ndx = (unsigned) -1;
+  for (i = 0; i < sec_info->count; ++i)
+    {
+      if (sec_info->entry[i].removed)
+	continue;
+      if (sec_info->entry[i].cie)
+	last_cie_ndx = i;
+      else if (sec_info->entry[i].size > 4)
+	{
+	  BFD_ASSERT (last_cie_ndx != (unsigned) -1);
+	  sec_info->entry[i].need_relative
+	    |= sec_info->entry[last_cie_ndx].need_relative;
+	  sec_info->entry[i].need_lsda_relative
+	    |= sec_info->entry[last_cie_ndx].need_lsda_relative;
+	}
+    }
+
   p = contents;
   for (i = 0; i < sec_info->count; ++i)
     {

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Fix ld/418
  2004-10-08 14:34     ` Alan Modra
@ 2004-10-10  7:54       ` Alan Modra
  2004-10-10 13:01         ` Alan Modra
  2004-10-13 21:48         ` Richard Sandiford
  0 siblings, 2 replies; 9+ messages in thread
From: Alan Modra @ 2004-10-10  7:54 UTC (permalink / raw)
  To: Richard Sandiford, Jakub Jelinek, binutils, mendell

On Sat, Oct 09, 2004 at 12:03:57AM +0930, Alan Modra wrote:
> Like this.  Untested.  I'll commit tomorrow after some testing.

Testing showed an embarrassing number of problems with that idea.  The
following patch is a proper fix (I think!).  Key changes from the
current code are:

a) Add a pointer in info kept for FDEs to the info for the actual CIE
   used.
b) Use output section offsets in _bfd_elf_write_section_eh_frame

These two changes allow rather a lot of simplification too, since we
get access to CIE info from other sections, and don't need to track
input sections.  Overall, a net reduction of approx 50 lines of code,
and no increase in data.  With a little more work, it would be possible
to optimize CIEs more aggressively, ie. look at more than just the last
CIE when merging.

Those who peruse this patch may notice a FIXME.  I'll attack that later,
probably by iterating over input sections using link_orders in
bfd_elf_discard_info.  This code might fail if someone writes a linker
script that deliberately reorders eh_frame sections, or uses HJ's new
--sort-section linker options.

	* elf-bfd.h (struct eh_cie_fde): Add cie_inf, remove sec.
	(struct eh_frame_hdr_info): Add last_cie_inf, remove last_cie_offset.
	* elf-eh-frame.c (_bfd_elf_discard_section_eh_frame): Delete code
	setting offsets for removed CIEs.  Don't set "sec", instead set
	cie_inf for FDEs.  Keep a pointer to last struct eh_cie_fde for a
	CIE in hdr_info.  Only set make_relative and make_lsda_relative
	for CIEs.  Use pointers rather than array indices.
	(_bfd_elf_eh_frame_section_offset): Test/set make_relative,
	make_lsda_relative, need_* on cie_inf for FDEs.
	(_bfd_elf_write_section_eh_frame): Adjust offset and new_offset for
	section output_offset.  Delete cie_offset, instead use cie_inf
	pointer to CIE entry.  Use need_relative and need_lsda_relative on
	CIE entry for FDEs.  Use pointers rather than array indices.

Index: bfd/elf-bfd.h
===================================================================
RCS file: /cvs/src/src/bfd/elf-bfd.h,v
retrieving revision 1.159
diff -u -p -r1.159 elf-bfd.h
--- bfd/elf-bfd.h	1 Oct 2004 00:51:37 -0000	1.159
+++ bfd/elf-bfd.h	10 Oct 2004 06:05:25 -0000
@@ -286,9 +286,10 @@ struct cie
 
 struct eh_cie_fde
 {
-  unsigned int offset;
+  /* For FDEs, this points to the CIE used.  */
+  struct eh_cie_fde *cie_inf;
   unsigned int size;
-  asection *sec;
+  unsigned int offset;
   unsigned int new_offset;
   unsigned char fde_encoding;
   unsigned char lsda_encoding;
@@ -319,8 +320,8 @@ struct eh_frame_hdr_info
 {
   struct cie last_cie;
   asection *last_cie_sec;
+  struct eh_cie_fde *last_cie_inf;
   asection *hdr_sec;
-  unsigned int last_cie_offset;
   unsigned int fde_count, array_count;
   struct eh_frame_array_ent *array;
   /* TRUE if .eh_frame_hdr should contain the sorted search table.
Index: bfd/elf-eh-frame.c
===================================================================
RCS file: /cvs/src/src/bfd/elf-eh-frame.c,v
retrieving revision 1.32
diff -u -p -r1.32 elf-eh-frame.c
--- bfd/elf-eh-frame.c	1 Oct 2004 00:51:37 -0000	1.32
+++ bfd/elf-eh-frame.c	10 Oct 2004 06:05:25 -0000
@@ -213,14 +213,14 @@ _bfd_elf_discard_section_eh_frame
 {
   bfd_byte *ehbuf = NULL, *buf;
   bfd_byte *last_cie, *last_fde;
+  struct eh_cie_fde *ent, *last_cie_inf, *this_inf;
   struct cie_header hdr;
   struct cie cie;
   struct elf_link_hash_table *htab;
   struct eh_frame_hdr_info *hdr_info;
   struct eh_frame_sec_info *sec_info = NULL;
   unsigned int leb128_tmp;
-  unsigned int cie_usage_count, last_cie_ndx, i, offset;
-  unsigned int make_relative, make_lsda_relative;
+  unsigned int cie_usage_count, offset;
   bfd_size_type new_size;
   unsigned int ptr_size;
 
@@ -264,12 +264,10 @@ _bfd_elf_discard_section_eh_frame
 	      == ELFCLASS64) ? 8 : 4;
   buf = ehbuf;
   last_cie = NULL;
-  last_cie_ndx = 0;
+  last_cie_inf = NULL;
   memset (&cie, 0, sizeof (cie));
   cie_usage_count = 0;
   new_size = sec->size;
-  make_relative = hdr_info->last_cie.make_relative;
-  make_lsda_relative = hdr_info->last_cie.make_lsda_relative;
   sec_info = bfd_zmalloc (sizeof (struct eh_frame_sec_info)
 			  + 99 * sizeof (struct eh_cie_fde));
   if (sec_info == NULL)
@@ -302,18 +300,25 @@ _bfd_elf_discard_section_eh_frame
 
       if (sec_info->count == sec_info->alloced)
 	{
+	  struct eh_cie_fde *old_entry = sec_info->entry;
 	  sec_info = bfd_realloc (sec_info,
 				  sizeof (struct eh_frame_sec_info)
-				  + (sec_info->alloced + 99)
-				     * sizeof (struct eh_cie_fde));
+				  + ((sec_info->alloced + 99)
+				     * sizeof (struct eh_cie_fde)));
 	  if (sec_info == NULL)
 	    goto free_no_table;
 
 	  memset (&sec_info->entry[sec_info->alloced], 0,
 		  100 * sizeof (struct eh_cie_fde));
 	  sec_info->alloced += 100;
+
+	  /* Now fix any pointers into the array.  */
+	  if (last_cie_inf >= old_entry
+	      && last_cie_inf < old_entry + sec_info->count)
+	    last_cie_inf = sec_info->entry + (last_cie_inf - old_entry);
 	}
 
+      this_inf = sec_info->entry + sec_info->count;
       last_fde = buf;
       /* If we are at the end of the section, we still need to decide
 	 on whether to output or discard last encountered CIE (if any).  */
@@ -334,8 +339,8 @@ _bfd_elf_discard_section_eh_frame
 	    /* CIE/FDE not contained fully in this .eh_frame input section.  */
 	    goto free_no_table;
 
-	  sec_info->entry[sec_info->count].offset = last_fde - ehbuf;
-	  sec_info->entry[sec_info->count].size = 4 + hdr.length;
+	  this_inf->offset = last_fde - ehbuf;
+	  this_inf->size = 4 + hdr.length;
 
 	  if (hdr.length == 0)
 	    {
@@ -376,21 +381,15 @@ _bfd_elf_discard_section_eh_frame
 		  || cie_usage_count == 0)
 		{
 		  new_size -= cie.hdr.length + 4;
-		  sec_info->entry[last_cie_ndx].removed = 1;
-		  sec_info->entry[last_cie_ndx].sec = hdr_info->last_cie_sec;
-		  sec_info->entry[last_cie_ndx].new_offset
-		    = hdr_info->last_cie_offset;
+		  last_cie_inf->removed = 1;
 		}
 	      else
 		{
 		  hdr_info->last_cie = cie;
 		  hdr_info->last_cie_sec = sec;
-		  hdr_info->last_cie_offset = last_cie - ehbuf;
-		  sec_info->entry[last_cie_ndx].make_relative
-		    = cie.make_relative;
-		  sec_info->entry[last_cie_ndx].make_lsda_relative
-		    = cie.make_lsda_relative;
-		  sec_info->entry[last_cie_ndx].per_encoding_relative
+		  last_cie_inf->make_relative = cie.make_relative;
+		  last_cie_inf->make_lsda_relative = cie.make_lsda_relative;
+		  last_cie_inf->per_encoding_relative
 		    = (cie.per_encoding & 0x70) == DW_EH_PE_pcrel;
 		}
 	    }
@@ -398,8 +397,8 @@ _bfd_elf_discard_section_eh_frame
 	  if (hdr.id == (unsigned int) -1)
 	    break;
 
-	  last_cie_ndx = sec_info->count;
-	  sec_info->entry[sec_info->count].cie = 1;
+	  last_cie_inf = this_inf;
+	  this_inf->cie = 1;
 
 	  cie_usage_count = 0;
 	  memset (&cie, 0, sizeof (cie));
@@ -552,12 +551,13 @@ _bfd_elf_discard_section_eh_frame
 	  if (GET_RELOC (buf) == NULL)
 	    /* This should not happen.  */
 	    goto free_no_table;
+
 	  if ((*reloc_symbol_deleted_p) (buf - ehbuf, cookie))
 	    {
 	      /* This is a FDE against a discarded section.  It should
 		 be deleted.  */
 	      new_size -= hdr.length + 4;
-	      sec_info->entry[sec_info->count].removed = 1;
+	      this_inf->removed = 1;
 	    }
 	  else
 	    {
@@ -585,14 +585,14 @@ _bfd_elf_discard_section_eh_frame
 		read_uleb128 (dummy, buf);
 	      /* If some new augmentation data is added before LSDA
 		 in FDE augmentation area, this need to be adjusted.  */
-	      sec_info->entry[sec_info->count].lsda_offset = (buf - aug);
+	      this_inf->lsda_offset = (buf - aug);
 	    }
 	  buf = last_fde + 4 + hdr.length;
 	  SKIP_RELOCS (buf);
 	}
 
-      sec_info->entry[sec_info->count].fde_encoding = cie.fde_encoding;
-      sec_info->entry[sec_info->count].lsda_encoding = cie.lsda_encoding;
+      this_inf->fde_encoding = cie.fde_encoding;
+      this_inf->lsda_encoding = cie.lsda_encoding;
       sec_info->count++;
     }
 
@@ -601,41 +601,18 @@ _bfd_elf_discard_section_eh_frame
 
   /* Ok, now we can assign new offsets.  */
   offset = 0;
-  last_cie_ndx = 0;
-  for (i = 0; i < sec_info->count; i++)
-    {
-      if (! sec_info->entry[i].removed)
-	{
-	  sec_info->entry[i].new_offset = offset;
-	  offset += sec_info->entry[i].size;
-	  if (sec_info->entry[i].cie)
-	    {
-	      last_cie_ndx = i;
-	      make_relative = sec_info->entry[i].make_relative;
-	      make_lsda_relative = sec_info->entry[i].make_lsda_relative;
-	    }
-	  else
-	    {
-	      sec_info->entry[i].make_relative = make_relative;
-	      sec_info->entry[i].make_lsda_relative = make_lsda_relative;
-	      sec_info->entry[i].per_encoding_relative = 0;
-	    }
-	}
-      else if (sec_info->entry[i].cie && sec_info->entry[i].sec == sec)
-	{
-	  /* Need to adjust new_offset too.  */
-	  BFD_ASSERT (sec_info->entry[last_cie_ndx].offset
-		      == sec_info->entry[i].new_offset);
-	  sec_info->entry[i].new_offset
-	    = sec_info->entry[last_cie_ndx].new_offset;
-	}
-    }
-  if (hdr_info->last_cie_sec == sec)
-    {
-      BFD_ASSERT (sec_info->entry[last_cie_ndx].offset
-		  == hdr_info->last_cie_offset);
-      hdr_info->last_cie_offset = sec_info->entry[last_cie_ndx].new_offset;
-    }
+  last_cie_inf = hdr_info->last_cie_inf;
+  for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent)
+    if (!ent->removed)
+      {
+	ent->new_offset = offset;
+	offset += ent->size;
+	if (ent->cie)
+	  last_cie_inf = ent;
+	else
+	  ent->cie_inf = last_cie_inf;
+      }
+  hdr_info->last_cie_inf = last_cie_inf;
 
   /* Shrink the sec as needed.  */
   sec->rawsize = sec->size;
@@ -772,22 +749,22 @@ _bfd_elf_eh_frame_section_offset (bfd *o
 
   /* If converting to DW_EH_PE_pcrel, there will be no need for run-time
      relocation against FDE's initial_location field.  */
-  if (sec_info->entry[mid].make_relative
-      && ! sec_info->entry[mid].cie
+  if (!sec_info->entry[mid].cie
+      && sec_info->entry[mid].cie_inf->make_relative
       && offset == sec_info->entry[mid].offset + 8)
     {
-      sec_info->entry[mid].need_relative = 1;
+      sec_info->entry[mid].cie_inf->need_relative = 1;
       return (bfd_vma) -2;
     }
 
   /* If converting LSDA pointers to DW_EH_PE_pcrel, there will be no need
      for run-time relocation against LSDA field.  */
-  if (sec_info->entry[mid].make_lsda_relative
-      && ! sec_info->entry[mid].cie
+  if (!sec_info->entry[mid].cie
+      && sec_info->entry[mid].cie_inf->make_lsda_relative
       && (offset == (sec_info->entry[mid].offset + 8
 		     + sec_info->entry[mid].lsda_offset)))
     {
-      sec_info->entry[mid].need_lsda_relative = 1;
+      sec_info->entry[mid].cie_inf->need_lsda_relative = 1;
       return (bfd_vma) -2;
     }
 
@@ -807,11 +784,10 @@ _bfd_elf_write_section_eh_frame (bfd *ab
   struct eh_frame_sec_info *sec_info;
   struct elf_link_hash_table *htab;
   struct eh_frame_hdr_info *hdr_info;
-  unsigned int i;
   bfd_byte *p, *buf;
   unsigned int leb128_tmp;
-  unsigned int cie_offset = 0;
   unsigned int ptr_size;
+  struct eh_cie_fde *ent;
 
   ptr_size = (elf_elfheader (sec->owner)->e_ident[EI_CLASS]
 	      == ELFCLASS64) ? 8 : 4;
@@ -829,36 +805,27 @@ _bfd_elf_write_section_eh_frame (bfd *ab
     hdr_info = NULL;
 
   p = contents;
-  for (i = 0; i < sec_info->count; ++i)
+  for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent)
     {
-      if (sec_info->entry[i].removed)
-	{
-	  if (sec_info->entry[i].cie)
-	    {
-	      /* If CIE is removed due to no remaining FDEs referencing it
-		 and there were no CIEs kept before it, sec_info->entry[i].sec
-		 will be zero.  */
-	      if (sec_info->entry[i].sec == NULL)
-		cie_offset = 0;
-	      else
-		{
-		  cie_offset = sec_info->entry[i].new_offset;
-		  cie_offset += (sec_info->entry[i].sec->output_section->vma
-				 + sec_info->entry[i].sec->output_offset
-				 - sec->output_section->vma
-				 - sec->output_offset);
-		}
-	    }
-	  continue;
-	}
+      if (ent->removed)
+	continue;
+
+      /* First convert all offsets to output section offsets, so that a
+	 CIE offset is valid if the CIE is used by a FDE from some other
+	 section.  This can happen when duplicate CIEs are deleted in
+	 _bfd_elf_discard_section_eh_frame.
+	 FIXME: This assumes that _bfd_elf_discard_section_eh_frame is
+	 called on sections in the same order as this function, which
+	 isn't necessarily so.  */
+      ent->offset += sec->output_offset;
+      ent->new_offset += sec->output_offset;
 
-      if (sec_info->entry[i].cie)
+      if (ent->cie)
 	{
 	  /* CIE */
-	  cie_offset = sec_info->entry[i].new_offset;
-	  if (sec_info->entry[i].need_relative
-	      || sec_info->entry[i].need_lsda_relative
-	      || sec_info->entry[i].per_encoding_relative)
+	  if (ent->need_relative
+	      || ent->need_lsda_relative
+	      || ent->per_encoding_relative)
 	    {
 	      unsigned char *aug;
 	      unsigned int action;
@@ -866,10 +833,10 @@ _bfd_elf_write_section_eh_frame (bfd *ab
 
 	      /* Need to find 'R' or 'L' augmentation's argument and modify
 		 DW_EH_PE_* value.  */
-	      action = (sec_info->entry[i].need_relative ? 1 : 0)
-		       | (sec_info->entry[i].need_lsda_relative ? 2 : 0)
-		       | (sec_info->entry[i].per_encoding_relative ? 4 : 0);
-	      buf = contents + sec_info->entry[i].offset;
+	      action = ((ent->need_relative ? 1 : 0)
+			| (ent->need_lsda_relative ? 2 : 0)
+			| (ent->per_encoding_relative ? 4 : 0));
+	      buf = contents + ent->offset - sec->output_offset;
 	      /* Skip length, id and version.  */
 	      buf += 9;
 	      aug = buf;
@@ -889,7 +856,7 @@ _bfd_elf_write_section_eh_frame (bfd *ab
 		  case 'L':
 		    if (action & 2)
 		      {
-			BFD_ASSERT (*buf == sec_info->entry[i].lsda_encoding);
+			BFD_ASSERT (*buf == ent->lsda_encoding);
 			*buf |= DW_EH_PE_pcrel;
 			action &= ~2;
 		      }
@@ -897,25 +864,22 @@ _bfd_elf_write_section_eh_frame (bfd *ab
 		    break;
 		  case 'P':
 		    per_encoding = *buf++;
-                    per_width = get_DW_EH_PE_width (per_encoding,
-						    ptr_size);
+                    per_width = get_DW_EH_PE_width (per_encoding, ptr_size);
 		    BFD_ASSERT (per_width != 0);
 		    BFD_ASSERT (((per_encoding & 0x70) == DW_EH_PE_pcrel)
-				== sec_info->entry[i].per_encoding_relative);
+				== ent->per_encoding_relative);
 		    if ((per_encoding & 0xf0) == DW_EH_PE_aligned)
 		      buf = (contents
 			     + ((buf - contents + per_width - 1)
 				& ~((bfd_size_type) per_width - 1)));
 		    if (action & 4)
 		      {
-			bfd_vma value;
+			bfd_vma val;
 
-			value = read_value (abfd, buf, per_width,
-					    get_DW_EH_PE_signed
-					    (per_encoding));
-			value += (sec_info->entry[i].offset
-				  - sec_info->entry[i].new_offset);
-			write_value (abfd, buf, value, per_width);
+			val = read_value (abfd, buf, per_width,
+					  get_DW_EH_PE_signed (per_encoding));
+			val += ent->offset - ent->new_offset;
+			write_value (abfd, buf, val, per_width);
 			action &= ~4;
 		      }
 		    buf += per_width;
@@ -923,7 +887,7 @@ _bfd_elf_write_section_eh_frame (bfd *ab
 		  case 'R':
 		    if (action & 1)
 		      {
-			BFD_ASSERT (*buf == sec_info->entry[i].fde_encoding);
+			BFD_ASSERT (*buf == ent->fde_encoding);
 			*buf |= DW_EH_PE_pcrel;
 			action &= ~1;
 		      }
@@ -934,26 +898,25 @@ _bfd_elf_write_section_eh_frame (bfd *ab
 		  }
 	    }
 	}
-      else if (sec_info->entry[i].size > 4)
+      else if (ent->size > 4)
 	{
 	  /* FDE */
-	  bfd_vma value = 0, address;
+	  bfd_vma value, address;
 	  unsigned int width;
 
-	  buf = contents + sec_info->entry[i].offset;
+	  buf = contents + ent->offset - sec->output_offset;
 	  /* Skip length.  */
 	  buf += 4;
-	  bfd_put_32 (abfd,
-		      sec_info->entry[i].new_offset + 4 - cie_offset, buf);
+	  value = ent->new_offset + 4 - ent->cie_inf->new_offset;
+	  bfd_put_32 (abfd, value, buf);
 	  buf += 4;
-	  width = get_DW_EH_PE_width (sec_info->entry[i].fde_encoding,
-				      ptr_size);
-	  address = value = read_value (abfd, buf, width,
-					get_DW_EH_PE_signed
-					(sec_info->entry[i].fde_encoding));
+	  width = get_DW_EH_PE_width (ent->fde_encoding, ptr_size);
+	  value = read_value (abfd, buf, width,
+			      get_DW_EH_PE_signed (ent->fde_encoding));
+	  address = value;
 	  if (value)
 	    {
-	      switch (sec_info->entry[i].fde_encoding & 0xf0)
+	      switch (ent->fde_encoding & 0xf0)
 		{
 		case DW_EH_PE_indirect:
 		case DW_EH_PE_textrel:
@@ -968,15 +931,12 @@ _bfd_elf_write_section_eh_frame (bfd *ab
 		  }
 		  break;
 		case DW_EH_PE_pcrel:
-		  value += (sec_info->entry[i].offset
-			    - sec_info->entry[i].new_offset);
-		  address += (sec->output_section->vma + sec->output_offset
-			      + sec_info->entry[i].offset + 8);
+		  value += ent->offset - ent->new_offset;
+		  address += sec->output_section->vma + ent->offset + 8;
 		  break;
 		}
-	      if (sec_info->entry[i].need_relative)
-		value -= (sec->output_section->vma + sec->output_offset
-			  + sec_info->entry[i].new_offset + 8);
+	      if (ent->cie_inf->need_relative)
+		value -= sec->output_section->vma + ent->new_offset + 8;
 	      write_value (abfd, buf, value, width);
 	    }
 
@@ -984,41 +944,34 @@ _bfd_elf_write_section_eh_frame (bfd *ab
 	    {
 	      hdr_info->array[hdr_info->array_count].initial_loc = address;
 	      hdr_info->array[hdr_info->array_count++].fde
-		= (sec->output_section->vma + sec->output_offset
-		   + sec_info->entry[i].new_offset);
+		= sec->output_section->vma + ent->new_offset;
 	    }
 
-	  if ((sec_info->entry[i].lsda_encoding & 0xf0) == DW_EH_PE_pcrel
-	      || sec_info->entry[i].need_lsda_relative)
+	  if ((ent->lsda_encoding & 0xf0) == DW_EH_PE_pcrel
+	      || ent->cie_inf->need_lsda_relative)
 	    {
-	      buf += sec_info->entry[i].lsda_offset;
-	      width = get_DW_EH_PE_width (sec_info->entry[i].lsda_encoding,
-					  ptr_size);
+	      buf += ent->lsda_offset;
+	      width = get_DW_EH_PE_width (ent->lsda_encoding, ptr_size);
 	      value = read_value (abfd, buf, width,
-				  get_DW_EH_PE_signed
-				  (sec_info->entry[i].lsda_encoding));
+				  get_DW_EH_PE_signed (ent->lsda_encoding));
 	      if (value)
 		{
-		  if ((sec_info->entry[i].lsda_encoding & 0xf0)
-		      == DW_EH_PE_pcrel)
-		    value += (sec_info->entry[i].offset
-			      - sec_info->entry[i].new_offset);
-		  else if (sec_info->entry[i].need_lsda_relative)
-		    value -= (sec->output_section->vma + sec->output_offset
-			      + sec_info->entry[i].new_offset + 8
-			      + sec_info->entry[i].lsda_offset);
+		  if ((ent->lsda_encoding & 0xf0) == DW_EH_PE_pcrel)
+		    value += ent->offset - ent->new_offset;
+		  else if (ent->cie_inf->need_lsda_relative)
+		    value -= (sec->output_section->vma + ent->new_offset + 8
+			      + ent->lsda_offset);
 		  write_value (abfd, buf, value, width);
 		}
 	    }
 	}
       else
 	/* Terminating FDE must be at the end of .eh_frame section only.  */
-	BFD_ASSERT (i == sec_info->count - 1);
+	BFD_ASSERT (ent == sec_info->entry + sec_info->count - 1);
 
-      BFD_ASSERT (p == contents + sec_info->entry[i].new_offset);
-      memmove (p, contents + sec_info->entry[i].offset,
-	       sec_info->entry[i].size);
-      p += sec_info->entry[i].size;
+      BFD_ASSERT (p == contents + ent->new_offset - sec->output_offset);
+      memmove (p, contents + ent->offset - sec->output_offset, ent->size);
+      p += ent->size;
     }
 
     {
@@ -1032,22 +985,22 @@ _bfd_elf_write_section_eh_frame (bfd *ab
 	      <= sec->output_section->size))
 	{
 	  /* Find the last CIE/FDE.  */
-	  for (i = sec_info->count - 1; i > 0; i--)
-	    if (! sec_info->entry[i].removed)
+	  ent = sec_info->entry + sec_info->count;
+	  while (--ent != sec_info->entry)
+	    if (!ent->removed)
 	      break;
 
 	  /* The size of the last CIE/FDE must be at least 4.  */
-	  if (sec_info->entry[i].removed
-	      || sec_info->entry[i].size < 4)
+	  if (ent->removed || ent->size < 4)
 	    abort ();
 
 	  pad = alignment - pad;
 
-	  buf = contents + sec_info->entry[i].new_offset;
+	  buf = contents + ent->new_offset - sec->output_offset;
 
 	  /* Update length.  */
-	  sec_info->entry[i].size += pad;
-	  bfd_put_32 (abfd, sec_info->entry[i].size - 4, buf);
+	  ent->size += pad;
+	  bfd_put_32 (abfd, ent->size - 4, buf);
 
 	  /* Pad it with DW_CFA_nop  */
 	  memset (p, 0, pad);


-- 
Alan Modra
IBM OzLabs - Linux Technology Centre

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Fix ld/418
  2004-10-10  7:54       ` Alan Modra
@ 2004-10-10 13:01         ` Alan Modra
  2004-10-13 21:48         ` Richard Sandiford
  1 sibling, 0 replies; 9+ messages in thread
From: Alan Modra @ 2004-10-10 13:01 UTC (permalink / raw)
  To: Richard Sandiford, Jakub Jelinek, binutils, mendell

On Sun, Oct 10, 2004 at 05:24:38PM +0930, Alan Modra wrote:
> Those who peruse this patch may notice a FIXME.  I'll attack that later,
> probably by iterating over input sections using link_orders in
> bfd_elf_discard_info.  This code might fail if someone writes a linker
> script that deliberately reorders eh_frame sections, or uses HJ's new
> --sort-section linker options.

Hmm, link_orders aren't set up when bfd_elf_discard_info is called.  I
toyed with writing a linker function to traverse the script and call a
function on each input section mapped to a particular output section,
then decided it wasn't worth the bother.

	* elf-bfd.h (struct eh_frame_hdr_info): Add offsets_adjusted.
	* elf-eh-frame.c (_bfd_elf_write_section_eh_frame): Adjust
	offsets stored in struct eh_cie_fde entries before doing other
	work.

Index: bfd/elf-bfd.h
===================================================================
RCS file: /cvs/src/src/bfd/elf-bfd.h,v
retrieving revision 1.160
diff -u -p -r1.160 elf-bfd.h
--- bfd/elf-bfd.h	10 Oct 2004 07:58:07 -0000	1.160
+++ bfd/elf-bfd.h	10 Oct 2004 12:47:40 -0000
@@ -328,6 +328,7 @@ struct eh_frame_hdr_info
      We build it if we successfully read all .eh_frame input sections
      and recognize them.  */
   bfd_boolean table;
+  bfd_boolean offsets_adjusted;
 };
 
 /* ELF linker hash table.  */
Index: bfd/elf-eh-frame.c
===================================================================
RCS file: /cvs/src/src/bfd/elf-eh-frame.c,v
retrieving revision 1.33
diff -u -p -r1.33 elf-eh-frame.c
--- bfd/elf-eh-frame.c	10 Oct 2004 07:58:07 -0000	1.33
+++ bfd/elf-eh-frame.c	10 Oct 2004 12:47:40 -0000
@@ -798,6 +798,39 @@ _bfd_elf_write_section_eh_frame (bfd *ab
   sec_info = elf_section_data (sec)->sec_info;
   htab = elf_hash_table (info);
   hdr_info = &htab->eh_info;
+
+  /* First convert all offsets to output section offsets, so that a
+     CIE offset is valid if the CIE is used by a FDE from some other
+     section.  This can happen when duplicate CIEs are deleted in
+     _bfd_elf_discard_section_eh_frame.  We do all sections here because
+     this function might not be called on sections in the same order as
+     _bfd_elf_discard_section_eh_frame.  */
+  if (!hdr_info->offsets_adjusted)
+    {
+      bfd *ibfd;
+      asection *eh;
+      struct eh_frame_sec_info *eh_inf;
+
+      for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+	{
+	  if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
+	      || (ibfd->flags & DYNAMIC) != 0)
+	    continue;
+
+	  eh = bfd_get_section_by_name (ibfd, ".eh_frame");
+	  if (eh == NULL || eh->sec_info_type != ELF_INFO_TYPE_EH_FRAME)
+	    continue;
+
+	  eh_inf = elf_section_data (eh)->sec_info;
+	  for (ent = eh_inf->entry; ent < eh_inf->entry + eh_inf->count; ++ent)
+	    {
+	      ent->offset += eh->output_offset;
+	      ent->new_offset += eh->output_offset;
+	    }
+	}
+      hdr_info->offsets_adjusted = TRUE;
+    }
+
   if (hdr_info->table && hdr_info->array == NULL)
     hdr_info->array
       = bfd_malloc (hdr_info->fde_count * sizeof(*hdr_info->array));
@@ -810,16 +843,6 @@ _bfd_elf_write_section_eh_frame (bfd *ab
       if (ent->removed)
 	continue;
 
-      /* First convert all offsets to output section offsets, so that a
-	 CIE offset is valid if the CIE is used by a FDE from some other
-	 section.  This can happen when duplicate CIEs are deleted in
-	 _bfd_elf_discard_section_eh_frame.
-	 FIXME: This assumes that _bfd_elf_discard_section_eh_frame is
-	 called on sections in the same order as this function, which
-	 isn't necessarily so.  */
-      ent->offset += sec->output_offset;
-      ent->new_offset += sec->output_offset;
-
       if (ent->cie)
 	{
 	  /* CIE */

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Fix ld/418
  2004-10-10  7:54       ` Alan Modra
  2004-10-10 13:01         ` Alan Modra
@ 2004-10-13 21:48         ` Richard Sandiford
  2004-10-14 23:36           ` Alan Modra
  1 sibling, 1 reply; 9+ messages in thread
From: Richard Sandiford @ 2004-10-13 21:48 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: binutils, mendell

[-- Attachment #1: Type: text/plain, Size: 1630 bytes --]

Hi Alan,

You're going to hate me for this ;)

I've just had chance to try out the revised version of your patch.
It's causing problems on MIPS in situations where you link:

   ld first.o second.o -o foo.so -shared

and:

   - both first.o and second.o have .eh_frames

   - second.o's .eh_frame needs a dynamic relocation
     (such as for the personality routine)

   - the backend uses _bfd_elf_section_offset (and thus
     _bfd_elf_eh_frame_section_offset) when creating
     the dynamic relocation.

Before the patch, the input-section-to-output-section calculation
was local to _bfd_elf_write_section_eh_frame:

		  cie_offset = sec_info->entry[i].new_offset;
		  cie_offset += (sec_info->entry[i].sec->output_section->vma
				 + sec_info->entry[i].sec->output_offset
				 - sec->output_section->vma
				 - sec->output_offset);

so the sec_info offset fields were still relative to the
input section when the backend called _bfd_elf_section_offset.
They're now relative to the output section instead.

Should _bfd_elf_eh_frame_section_offset be modified to cope with
the adjusted offsets or should _bfd_elf_write_section_eh_frame
record the adjustments in a less destructive way?

FWIW, you can see the problem with the attached testcase.
Command lines:

      ./gas/as-new -KPIC test.s -o test.o
      ./ld/ld-new test.o test.o -o foo.so -shared

It fails on mips64-linux-gnu with:

./ld/ld-new: BFD 2.15.93 20041013 assertion fail .../bfd/elf-eh-frame.c:744
./ld/ld-new: BFD 2.15.93 20041013 assertion fail .../bfd/elf-eh-frame.c:744
./ld/ld-new: BFD 2.15.93 20041013 assertion fail .../bfd/elf-eh-frame.c:744

Richard


[-- Attachment #2: test.s --]
[-- Type: text/plain, Size: 509 bytes --]

	.text
dummy:
	nop
end:
	.section .eh_frame,"aw",@progbits
.Lcie:
	.4byte	.LEcie - .LBcie
.LBcie:
	.4byte	0	# CIE Identifier Tag
	.byte	1	# CIE Version
	.string	"zP"	# CIE Augmentation
	.uleb128 1	# CIE Code Alignment Factor
	.sleb128 4	# CIE Data Alignment Factor
	.byte	31	# CIE RA Column
	.uleb128 5	# Augmentation size
	.byte	0	# Personality (absolute)
	.4byte	foo	# Personality routine
.LEcie:
.Lfde1:
	.4byte	.LEfde1 - .LBfde1
.LBfde1:
	.4byte	.LBfde1 - .Lcie
	.4byte	dummy
	.4byte	end - dummy
.LEfde1:

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Fix ld/418
  2004-10-13 21:48         ` Richard Sandiford
@ 2004-10-14 23:36           ` Alan Modra
  0 siblings, 0 replies; 9+ messages in thread
From: Alan Modra @ 2004-10-14 23:36 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: Jakub Jelinek, binutils, mendell

On Wed, Oct 13, 2004 at 10:48:01PM +0100, Richard Sandiford wrote:
> Should _bfd_elf_eh_frame_section_offset be modified to cope with
> the adjusted offsets

Yes, that would be easiest I think.  I didn't consider that this
function might be called after writing eh_frame sections, which
means some extra checks are needed too.

Richard, this is the same as the patch I sent you privately yesterday.

	* elf-eh-frame.c (_bfd_elf_eh_frame_section_offset): Add "info"
	parameter.  If called after _bfd_elf_write_section_eh_frame,
	don't allow a -2 return unless need_* bit is already set, and
	handle offsets adjusted for output_offset.
	* elf-bfd.h (_bfd_elf_eh_frame_section_offset): Update prototype.
	* elf.c (_bfd_elf_section_offset): Update call.

Index: bfd/elf-bfd.h
===================================================================
RCS file: /cvs/src/src/bfd/elf-bfd.h,v
retrieving revision 1.161
diff -u -p -r1.161 elf-bfd.h
--- bfd/elf-bfd.h	10 Oct 2004 13:02:00 -0000	1.161
+++ bfd/elf-bfd.h	14 Oct 2004 13:58:14 -0000
@@ -1532,7 +1532,7 @@ extern bfd_boolean _bfd_elf_discard_sect
 extern bfd_boolean _bfd_elf_discard_section_eh_frame_hdr
   (bfd *, struct bfd_link_info *);
 extern bfd_vma _bfd_elf_eh_frame_section_offset
-  (bfd *, asection *, bfd_vma);
+  (bfd *, struct bfd_link_info *, asection *, bfd_vma);
 extern bfd_boolean _bfd_elf_write_section_eh_frame
   (bfd *, struct bfd_link_info *, asection *, bfd_byte *);
 extern bfd_boolean _bfd_elf_write_section_eh_frame_hdr
Index: bfd/elf-eh-frame.c
===================================================================
RCS file: /cvs/src/src/bfd/elf-eh-frame.c,v
retrieving revision 1.34
diff -u -p -r1.34 elf-eh-frame.c
--- bfd/elf-eh-frame.c	10 Oct 2004 13:02:01 -0000	1.34
+++ bfd/elf-eh-frame.c	14 Oct 2004 13:58:15 -0000
@@ -713,10 +713,13 @@ _bfd_elf_maybe_strip_eh_frame_hdr (struc
 
 bfd_vma
 _bfd_elf_eh_frame_section_offset (bfd *output_bfd ATTRIBUTE_UNUSED,
+				  struct bfd_link_info *info,
 				  asection *sec,
 				  bfd_vma offset)
 {
   struct eh_frame_sec_info *sec_info;
+  struct elf_link_hash_table *htab;
+  struct eh_frame_hdr_info *hdr_info;
   unsigned int lo, hi, mid;
 
   if (sec->sec_info_type != ELF_INFO_TYPE_EH_FRAME)
@@ -726,6 +729,11 @@ _bfd_elf_eh_frame_section_offset (bfd *o
   if (offset >= sec->rawsize)
     return offset - sec->rawsize + sec->size;
 
+  htab = elf_hash_table (info);
+  hdr_info = &htab->eh_info;
+  if (hdr_info->offsets_adjusted)
+    offset += sec->output_offset;
+
   lo = 0;
   hi = sec_info->count;
   mid = 0;
@@ -751,7 +759,9 @@ _bfd_elf_eh_frame_section_offset (bfd *o
      relocation against FDE's initial_location field.  */
   if (!sec_info->entry[mid].cie
       && sec_info->entry[mid].cie_inf->make_relative
-      && offset == sec_info->entry[mid].offset + 8)
+      && offset == sec_info->entry[mid].offset + 8
+      && (sec_info->entry[mid].cie_inf->need_relative
+	  || !hdr_info->offsets_adjusted))
     {
       sec_info->entry[mid].cie_inf->need_relative = 1;
       return (bfd_vma) -2;
@@ -762,12 +772,16 @@ _bfd_elf_eh_frame_section_offset (bfd *o
   if (!sec_info->entry[mid].cie
       && sec_info->entry[mid].cie_inf->make_lsda_relative
       && (offset == (sec_info->entry[mid].offset + 8
-		     + sec_info->entry[mid].lsda_offset)))
+		     + sec_info->entry[mid].lsda_offset))
+      && (sec_info->entry[mid].cie_inf->need_lsda_relative
+	  || !hdr_info->offsets_adjusted))
     {
       sec_info->entry[mid].cie_inf->need_lsda_relative = 1;
       return (bfd_vma) -2;
     }
 
+  if (hdr_info->offsets_adjusted)
+    offset -= sec->output_offset;
   return (offset + sec_info->entry[mid].new_offset
 	  - sec_info->entry[mid].offset);
 }
Index: bfd/elf.c
===================================================================
RCS file: /cvs/src/src/bfd/elf.c,v
retrieving revision 1.250
diff -u -p -r1.250 elf.c
--- bfd/elf.c	11 Oct 2004 13:48:36 -0000	1.250
+++ bfd/elf.c	14 Oct 2004 13:58:20 -0000
@@ -7746,7 +7746,7 @@ _bfd_elf_rel_local_sym (bfd *abfd,
 
 bfd_vma
 _bfd_elf_section_offset (bfd *abfd,
-			 struct bfd_link_info *info ATTRIBUTE_UNUSED,
+			 struct bfd_link_info *info,
 			 asection *sec,
 			 bfd_vma offset)
 {
@@ -7756,7 +7756,7 @@ _bfd_elf_section_offset (bfd *abfd,
       return _bfd_stab_section_offset (sec, elf_section_data (sec)->sec_info,
 				       offset);
     case ELF_INFO_TYPE_EH_FRAME:
-      return _bfd_elf_eh_frame_section_offset (abfd, sec, offset);
+      return _bfd_elf_eh_frame_section_offset (abfd, info, sec, offset);
     default:
       return offset;
     }

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2004-10-14 23:36 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-09-30 14:37 Fix ld/418 Alan Modra
2004-09-30 14:51 ` Jakub Jelinek
2004-10-08 12:58 ` Richard Sandiford
2004-10-08 14:09   ` Alan Modra
2004-10-08 14:34     ` Alan Modra
2004-10-10  7:54       ` Alan Modra
2004-10-10 13:01         ` Alan Modra
2004-10-13 21:48         ` Richard Sandiford
2004-10-14 23:36           ` Alan Modra

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).