This is the mail archive of the binutils@sources.redhat.com mailing list for the binutils project.


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

relaxation segv


The attached test case will segfault on i386.

The direct cause for the segv is that when local symbols are
finalized, their fragment is nulled.

The deeper reason is that the section containing the .uleb128
was relaxed before the section containing the labels.  Which
meant that the .uleb128 got incorrect values for the symbols,
since their fr_address were all still zero.  Also, when
cvt_frag_to_fill ran for the leb128, it finalized the symbols,
which resulted in them being fixed to incorrect values.  And
also happens to cause a segv here:

relax_frag (segment=0x8108940, fragP=0x810eab8, stretch=11)
    at ../../../src/gas/write.c:2062
2062          target += S_GET_VALUE (symbolP) + sym_frag->fr_address;

Now, what I'm most concerned about is how this ever worked.
My guess is "by accident".  It's currently dependant on what
order the sections exist in the bfd.

If a relaxation expresion involves differences between symbols
in a different section, then we need to relax the sections in
the proper order.  Moreover, there can be loops in the dependancy
graph that require us to re-run relaxation on a section.

However, this is somewhat difficult, and is not aided by the
fact that it currently doesn't work to re-run relax_section
(you'll get aborts in cvt_frag_to_fill for unknown reasons).

Something that does work for this test case is to relax all the
code sections before all the data sections.  I have a feeling
this catches the bulk of the interesting cases, as happens with
EH data and Dwarf2 frame data.  Thus the attached patch.

Anyone got any better ideas?


r~
	.section	.gcc_except_table,"aw",@progbits

	.section	.gnu.linkonce.t.blah,"ax",@progbits
	.p2align 4,,7
.LFB4:
	jmp	.L774
	.p2align 4,,7
	nop
	.p2align 4,,7
.L774:
	movl	%edx, %esi

	.section	.gcc_except_table,"aw",@progbits
	.uleb128 .L774-.LFB4
	* write.c (relax_seg, size_seg): Split from relax_and_size_seg.
	(write_object_file): Relax code then data, then size sections.

	* config/tc-i386.c (md_convert_frag): Don't die on local symbols
	that have been finalized.

Index: write.c
===================================================================
RCS file: /cvs/src/src/gas/write.c,v
retrieving revision 1.27
diff -c -p -d -r1.27 write.c
*** write.c	2001/03/08 23:24:22	1.27
--- write.c	2001/03/11 08:22:55
*************** static fragS *chain_frchains_together_1 
*** 122,128 ****
  #ifdef BFD_ASSEMBLER
  static void chain_frchains_together PARAMS ((bfd *, segT, PTR));
  static void cvt_frag_to_fill PARAMS ((segT, fragS *));
! static void relax_and_size_seg PARAMS ((bfd *, asection *, PTR));
  static void adjust_reloc_syms PARAMS ((bfd *, asection *, PTR));
  static void write_relocs PARAMS ((bfd *, asection *, PTR));
  static void write_contents PARAMS ((bfd *, asection *, PTR));
--- 122,130 ----
  #ifdef BFD_ASSEMBLER
  static void chain_frchains_together PARAMS ((bfd *, segT, PTR));
  static void cvt_frag_to_fill PARAMS ((segT, fragS *));
! static void relax_seg PARAMS ((bfd *, asection *, PTR));
! static void relax_seg PARAMS ((bfd *, asection *, PTR));
! static void size_seg PARAMS ((bfd *, asection *, PTR));
  static void adjust_reloc_syms PARAMS ((bfd *, asection *, PTR));
  static void write_relocs PARAMS ((bfd *, asection *, PTR));
  static void write_contents PARAMS ((bfd *, asection *, PTR));
*************** cvt_frag_to_fill (headersP, sec, fragP)
*** 594,602 ****
  
  #ifdef BFD_ASSEMBLER
  static void
! relax_and_size_seg (abfd, sec, xxx)
       bfd *abfd;
       asection *sec;
       PTR xxx ATTRIBUTE_UNUSED;
  {
    flagword flags;
--- 596,618 ----
  
  #ifdef BFD_ASSEMBLER
  static void
! relax_seg (abfd, sec, do_code)
       bfd *abfd;
       asection *sec;
+      PTR do_code;
+ {
+   flagword flags = bfd_get_section_flags (abfd, sec);
+   segment_info_type *seginfo = seg_info (sec);
+ 
+   if (!(flags & SEC_CODE) == !do_code
+       && seginfo && seginfo->frchainP)
+     relax_segment (seginfo->frchainP->frch_root, sec);
+ }
+ 
+ static void
+ size_seg (abfd, sec, xxx)
+      bfd *abfd;
+      asection *sec;
       PTR xxx ATTRIBUTE_UNUSED;
  {
    flagword flags;
*************** relax_and_size_seg (abfd, sec, xxx)
*** 607,618 ****
  
    subseg_change (sec, 0);
  
-   flags = bfd_get_section_flags (abfd, sec);
- 
    seginfo = seg_info (sec);
    if (seginfo && seginfo->frchainP)
      {
-       relax_segment (seginfo->frchainP->frch_root, sec);
        for (fragp = seginfo->frchainP->frch_root; fragp; fragp = fragp->fr_next)
  	cvt_frag_to_fill (sec, fragp);
        for (fragp = seginfo->frchainP->frch_root;
--- 623,631 ----
*************** relax_and_size_seg (abfd, sec, xxx)
*** 625,630 ****
--- 638,645 ----
    else
      size = 0;
  
+   flags = bfd_get_section_flags (abfd, sec);
+ 
    if (size > 0 && ! seginfo->bss)
      flags |= SEC_HAS_CONTENTS;
  
*************** write_object_file ()
*** 1515,1521 ****
  #endif
  
  #ifdef BFD_ASSEMBLER
!   bfd_map_over_sections (stdoutput, relax_and_size_seg, (char *) 0);
  #else
    relax_and_size_all_segments ();
  #endif /* BFD_ASSEMBLER  */
--- 1530,1538 ----
  #endif
  
  #ifdef BFD_ASSEMBLER
!   bfd_map_over_sections (stdoutput, relax_seg, (char *) 1);
!   bfd_map_over_sections (stdoutput, relax_seg, (char *) 0);
!   bfd_map_over_sections (stdoutput, size_seg, (char *) 0);
  #else
    relax_and_size_all_segments ();
  #endif /* BFD_ASSEMBLER  */
Index: config/tc-i386.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-i386.c,v
retrieving revision 1.89
diff -c -p -d -r1.89 tc-i386.c
*** tc-i386.c	2001/03/08 23:24:23	1.89
--- tc-i386.c	2001/03/11 08:22:56
*************** md_convert_frag (abfd, sec, fragP)
*** 4041,4047 ****
    target_address = S_GET_VALUE (fragP->fr_symbol) + fragP->fr_offset;
  #ifdef BFD_ASSEMBLER
    /* Not needed otherwise?  */
!   target_address += symbol_get_frag (fragP->fr_symbol)->fr_address;
  #endif
  
    /* Address opcode resides at in file space.  */
--- 4041,4052 ----
    target_address = S_GET_VALUE (fragP->fr_symbol) + fragP->fr_offset;
  #ifdef BFD_ASSEMBLER
    /* Not needed otherwise?  */
!   {
!     /* Local symbols which have already been resolved have a NULL frags.  */
!     fragS *sym_frag = symbol_get_frag (fragP->fr_symbol);
!     if (sym_frag)
!       target_address += sym_frag->fr_address;
!   }
  #endif
  
    /* Address opcode resides at in file space.  */

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