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]
Other format: [Raw text]

Re: i386 and "R_386_16 relocation against SEC_MERGE section"


On Tue, May 07, 2002 at 11:00:36AM +0200, Etienne Lorrain wrote:
> ld: main.o(.text.menu+0x887): R_386_16 relocation against SEC_MERGE section

This goes a bit overboard and fixes pcrel relocs to SEC_MERGE sections
as well.  We're hardly going to branch in a SEC_MERGE section, but I
figured that if I'm supporting more than R_386_32 I might as well do
them all.  The overflow checking is quite possibly wrong;  If
somebody wants to analyse and correct, please go ahead!

bfd/ChangeLog
	* elf32-i386.c (elf_howto_table): Comments.
	(elf_i386_relocate_section): Handle more relocs for relocatable
	linking and against SEC_MERGE sections.

gas/ChangeLog
	* config/tc-i386.c (md_estimate_size_before_relax) Don't lose
	reloc when no_cond_jump_promotion.

Index: bfd/elf32-i386.c
===================================================================
RCS file: /cvs/src/src/bfd/elf32-i386.c,v
retrieving revision 1.67
diff -c -p -r1.67 elf32-i386.c
*** bfd/elf32-i386.c	4 Apr 2002 19:53:36 -0000	1.67
--- bfd/elf32-i386.c	8 May 2002 04:56:59 -0000
*************** static reloc_howto_type elf_howto_table[
*** 154,160 ****
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
  	 0,			/* dst_mask */
! 	 false),
  
  /* GNU extension to record C++ vtable member usage.  */
    HOWTO (R_386_GNU_VTENTRY,	/* type */
--- 154,160 ----
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
  	 0,			/* dst_mask */
! 	 false),		/* pcrel_offset */
  
  /* GNU extension to record C++ vtable member usage.  */
    HOWTO (R_386_GNU_VTENTRY,	/* type */
*************** static reloc_howto_type elf_howto_table[
*** 169,175 ****
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
  	 0,			/* dst_mask */
! 	 false)
  
  #define R_386_vt ((unsigned int) R_386_GNU_VTENTRY + 1 - R_386_vt_offset)
  
--- 169,175 ----
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
  	 0,			/* dst_mask */
! 	 false)			/* pcrel_offset */
  
  #define R_386_vt ((unsigned int) R_386_GNU_VTENTRY + 1 - R_386_vt_offset)
  
*************** elf_i386_relocate_section (output_bfd, i
*** 1724,1729 ****
--- 1724,1730 ----
        bfd_vma off;
        bfd_vma relocation;
        boolean unresolved_reloc;
+       boolean overflow;
        bfd_reloc_status_type r;
        unsigned int indx;
  
*************** elf_i386_relocate_section (output_bfd, i
*** 1745,1766 ****
  
        if (info->relocateable)
  	{
  	  /* This is a relocatable link.  We don't have to change
  	     anything, unless the reloc is against a section symbol,
  	     in which case we have to adjust according to where the
  	     section symbol winds up in the output section.  */
! 	  if (r_symndx < symtab_hdr->sh_info)
  	    {
! 	      sym = local_syms + r_symndx;
! 	      if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
  		{
! 		  bfd_vma val;
! 
! 		  sec = local_sections[r_symndx];
! 		  val = bfd_get_32 (input_bfd, contents + rel->r_offset);
! 		  val += sec->output_offset + sym->st_value;
! 		  bfd_put_32 (input_bfd, val, contents + rel->r_offset);
  		}
  	    }
  	  continue;
  	}
--- 1746,1811 ----
  
        if (info->relocateable)
  	{
+ 	  bfd_vma val;
+ 	  bfd_vma addend;
+ 	  bfd_byte *where;
+ 
  	  /* This is a relocatable link.  We don't have to change
  	     anything, unless the reloc is against a section symbol,
  	     in which case we have to adjust according to where the
  	     section symbol winds up in the output section.  */
! 	  if (r_symndx >= symtab_hdr->sh_info)
! 	    continue;
! 
! 	  sym = local_syms + r_symndx;
! 	  if (ELF_ST_TYPE (sym->st_info) != STT_SECTION)
! 	    continue;
! 
! 	  sec = local_sections[r_symndx];
! 	  val = sec->output_offset;
! 	  if (val == 0)
! 	    continue;
! 
! 	  where = contents + rel->r_offset;
! 	  switch (howto->size)
  	    {
! 	    case 0:
! 	      addend = bfd_get_8 (input_bfd, where);
! 	      if (howto->pc_relative)
! 		addend = (addend ^ 0x80) - 0x80;
! 	      val += addend;
! 	      bfd_put_8 (input_bfd, val, where);
! 	      if (howto->pc_relative)
! 		val += 0x80;
! 	      if (val > 0xff)
  		{
! 		  h = NULL;
! 		  r = bfd_reloc_overflow;
! 		  goto overflow_error;
! 		}
! 	      break;
! 	    case 1:
! 	      addend = bfd_get_16 (input_bfd, where);
! 	      if (howto->pc_relative)
! 		addend = (addend ^ 0x8000) - 0x8000;
! 	      val += addend;
! 	      bfd_put_16 (input_bfd, val, where);
! 	      if (howto->pc_relative)
! 		val += 0x8000;
! 	      if (output_bfd->arch_info->mach != bfd_mach_i386_i8086
! 		  && val > 0xffff)
! 		{
! 		  h = NULL;
! 		  r = bfd_reloc_overflow;
! 		  goto overflow_error;
  		}
+ 	      break;
+ 	    case 2:
+ 	      val += bfd_get_32 (input_bfd, where);
+ 	      bfd_put_32 (input_bfd, val, where);
+ 	      break;
+ 	    default:
+ 	      abort ();
  	    }
  	  continue;
  	}
*************** elf_i386_relocate_section (output_bfd, i
*** 1770,1775 ****
--- 1815,1821 ----
        sym = NULL;
        sec = NULL;
        unresolved_reloc = false;
+       overflow = false;
        if (r_symndx < symtab_hdr->sh_info)
  	{
  	  sym = local_syms + r_symndx;
*************** elf_i386_relocate_section (output_bfd, i
*** 1782,1805 ****
  	    {
  	      asection *msec;
  	      bfd_vma addend;
  
! 	      if (howto->src_mask != 0xffffffff)
  		{
! 		  (*_bfd_error_handler)
! 		    (_("%s(%s+0x%lx): %s relocation against SEC_MERGE section"),
! 		     bfd_archive_filename (input_bfd),
! 		     bfd_get_section_name (input_bfd, input_section),
! 		     (long) rel->r_offset, howto->name);
! 		  return false;
  		}
  
- 	      addend = bfd_get_32 (input_bfd, contents + rel->r_offset);
  	      msec = sec;
! 	      addend =
! 		_bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend)
! 		- relocation;
  	      addend += msec->output_section->vma + msec->output_offset;
! 	      bfd_put_32 (input_bfd, addend, contents + rel->r_offset);
  	    }
  	}
        else
--- 1828,1895 ----
  	    {
  	      asection *msec;
  	      bfd_vma addend;
+ 	      bfd_byte *where = contents + rel->r_offset;
  
! 	      switch (howto->size)
  		{
! 		case 0:
! 		  addend = bfd_get_8 (input_bfd, where);
! 		  if (howto->pc_relative)
! 		    {
! 		      addend = (addend ^ 0x80) - 0x80;
! 		      addend += 1;
! 		    }
! 		  break;
! 		case 1:
! 		  addend = bfd_get_16 (input_bfd, where);
! 		  if (howto->pc_relative)
! 		    {
! 		      addend = (addend ^ 0x8000) - 0x8000;
! 		      addend += 2;
! 		    }
! 		  break;
! 		case 2:
! 		  addend = bfd_get_32 (input_bfd, where);
! 		  if (howto->pc_relative)
! 		    {
! 		      addend = (addend ^ 0x80000000) - 0x80000000;
! 		      addend += 4;
! 		    }
! 		  break;
! 		default:
! 		  abort ();
  		}
  
  	      msec = sec;
! 	      addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend);
! 	      addend -= relocation;
  	      addend += msec->output_section->vma + msec->output_offset;
! 
! 	      switch (howto->size)
! 		{
! 		case 0:
! 		  if (howto->pc_relative)
! 		    addend -= 1;
! 		  bfd_put_8 (input_bfd, addend, where);
! 		  if (howto->pc_relative)
! 		    addend += 0x80;
! 		  overflow = addend > 0xff;
! 		  break;
! 		case 1:
! 		  if (howto->pc_relative)
! 		    addend -= 2;
! 		  bfd_put_16 (input_bfd, addend, where);
! 		  if (howto->pc_relative)
! 		    addend += 0x8000;
! 		  if (output_bfd->arch_info->mach != bfd_mach_i386_i8086)
! 		    overflow = addend > 0xffff;
! 		  break;
! 		case 2:
! 		  if (howto->pc_relative)
! 		    addend -= 4;
! 		  bfd_put_32 (input_bfd, addend, where);
! 		  break;
! 		}
  	    }
  	}
        else
*************** elf_i386_relocate_section (output_bfd, i
*** 2082,2088 ****
--- 2172,2181 ----
        r = _bfd_final_link_relocate (howto, input_bfd, input_section,
  				    contents, rel->r_offset,
  				    relocation, (bfd_vma) 0);
+       if (overflow && r == bfd_reloc_ok)
+ 	r = bfd_reloc_overflow;
  
+     overflow_error:
        if (r != bfd_reloc_ok)
  	{
  	  const char *name;
*************** elf_i386_relocate_section (output_bfd, i
*** 2102,2108 ****
  
  	  if (r == bfd_reloc_overflow)
  	    {
- 
  	      if (! ((*info->callbacks->reloc_overflow)
  		     (info, name, howto->name, (bfd_vma) 0,
  		      input_bfd, input_section, rel->r_offset)))
--- 2195,2200 ----
Index: gas/config/tc-i386.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-i386.c,v
retrieving revision 1.118
diff -u -p -r1.118 tc-i386.c
--- gas/config/tc-i386.c	1 May 2002 00:53:55 -0000	1.118
+++ gas/config/tc-i386.c	9 May 2002 04:59:27 -0000
@@ -4235,10 +4235,8 @@ md_estimate_size_before_relax (fragP, se
 	  break;
 
 	case COND_JUMP86:
-	  if (no_cond_jump_promotion)
-	    goto relax_guess;
-
-	  if (size == 2)
+	  if (size == 2
+	      && (!no_cond_jump_promotion || fragP->fr_var != NO_RELOC))
 	    {
 	      /* Negate the condition, and branch past an
 		 unconditional jump.  */
@@ -4258,8 +4256,15 @@ md_estimate_size_before_relax (fragP, se
 	  /* Fall through.  */
 
 	case COND_JUMP:
-	  if (no_cond_jump_promotion)
-	    goto relax_guess;
+	  if (no_cond_jump_promotion && fragP->fr_var == NO_RELOC)
+	    {
+	      fragP->fr_fix += 1;
+	      fix_new (fragP, old_fr_fix, 1,
+		       fragP->fr_symbol,
+		       fragP->fr_offset, 1,
+		       BFD_RELOC_8_PCREL);
+	      break;
+	    }
 
 	  /* This changes the byte-displacement jump 0x7N
 	     to the (d)word-displacement jump 0x0f,0x8N.  */
@@ -4281,7 +4286,6 @@ md_estimate_size_before_relax (fragP, se
       return fragP->fr_fix - old_fr_fix;
     }
 
- relax_guess:
   /* Guess size depending on current relax state.  Initially the relax
      state will correspond to a short jump and we return 1, because
      the variable part of the frag (the branch offset) is one byte

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre


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