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]

Fix pe-coff reloc overflow problems


Hi,
this patch fixes some problems with the way pe-coff reloc overflows
are treated. There were a couple of off-by-one errors.

A reloc overflow causes an initial reloc to be prepended containing
the real number of relocs. The header mentions 0xffff relocs and sets
an overflow bit.

We were not removing that first reloc correctly when reading back the
reloc table, but we would prepend a new reloc when writing the table
out. This caused objcopy to grow the reloc table by 1, and prepend
a sequence of bogus relocs.

A section with exactly 65535 relocs would lose the final reloc as
we'd not set the header overflow bit, but would prepend an overflow
reloc.

tested by targeting i386-pc-mingw32

nathan
--
Nathan Sidwell    ::   http://www.codesourcery.com   ::     CodeSourcery LLC
         The voices in my head said this was stupid too
nathan@codesourcery.com    ::     http://www.planetfall.pwp.blueyonder.co.uk

2003-09-19  Nathan Sidwell  <nathan@codesourcery.com>

	* coffcode.h (coff_set_alignment_hook): With PE_COFF reloc
	overflow, set reloc start position to after the count
	reloc. Subtract one from num relocs. Give error on 0xffff relocs
	and no overflow.
	* cofflink.c (_bfd_coff_final_link): Deal with PE_COFF reloc
	overflow.
	* peXXigen.c (_bfd_XXi_swap_scnhdr_out): Do overflow if >=
	0xffff.

Index: bfd/coffcode.h
===================================================================
RCS file: /cvs/src/src/bfd/coffcode.h,v
retrieving revision 1.95
diff -c -3 -p -r1.95 coffcode.h
*** bfd/coffcode.h	5 Aug 2003 08:25:17 -0000	1.95
--- bfd/coffcode.h	19 Sep 2003 14:05:44 -0000
*************** coff_set_alignment_hook (abfd, section, 
*** 1694,1708 ****
        struct external_reloc dst;
        struct internal_reloc n;
        file_ptr oldpos = bfd_tell (abfd);
        bfd_seek (abfd, (file_ptr) hdr->s_relptr, 0);
!       if (bfd_bread ((PTR) &dst, (bfd_size_type) bfd_coff_relsz (abfd), abfd)
! 	  != bfd_coff_relsz (abfd))
  	return;
  
        coff_swap_reloc_in (abfd, &dst, &n);
        bfd_seek (abfd, oldpos, 0);
!       section->reloc_count = hdr->s_nreloc = n.r_vaddr;
      }
  }
  #undef ALIGN_SET
  #undef ELIFALIGN_SET
--- 1694,1714 ----
        struct external_reloc dst;
        struct internal_reloc n;
        file_ptr oldpos = bfd_tell (abfd);
+       bfd_size_type relsz = bfd_coff_relsz (abfd);
+       
        bfd_seek (abfd, (file_ptr) hdr->s_relptr, 0);
!       if (bfd_bread ((PTR) &dst, relsz, abfd) != relsz)
  	return;
  
        coff_swap_reloc_in (abfd, &dst, &n);
        bfd_seek (abfd, oldpos, 0);
!       section->reloc_count = hdr->s_nreloc = n.r_vaddr - 1;
!       section->rel_filepos += relsz;
      }
+   else if (hdr->s_nreloc == 0xffff)
+     (*_bfd_error_handler)
+       ("%s: warning: claims to have 0xffff relocs, without overflow",
+        bfd_get_filename (abfd));
  }
  #undef ALIGN_SET
  #undef ELIFALIGN_SET
Index: bfd/cofflink.c
===================================================================
RCS file: /cvs/src/src/bfd/cofflink.c,v
retrieving revision 1.39
diff -c -3 -p -r1.39 cofflink.c
*** bfd/cofflink.c	3 Sep 2003 16:06:12 -0000	1.39
--- bfd/cofflink.c	19 Sep 2003 14:05:50 -0000
*************** _bfd_coff_final_link (bfd *abfd,
*** 1028,1037 ****
  	      bfd_coff_swap_reloc_out (abfd, irel, erel);
  	    }
  
! 	  if (bfd_seek (abfd, o->rel_filepos, SEEK_SET) != 0
! 	      || (bfd_bwrite (external_relocs,
! 			     (bfd_size_type) relsz * o->reloc_count, abfd)
! 		  != (bfd_size_type) relsz * o->reloc_count))
  	    goto error_return;
  	}
  
--- 1028,1054 ----
  	      bfd_coff_swap_reloc_out (abfd, irel, erel);
  	    }
  
! 	  if (bfd_seek (abfd, o->rel_filepos, SEEK_SET) != 0)
! 	    goto error_return;
! 	  if (obj_pe (abfd) && o->reloc_count >= 0xffff)
! 	    {
! 	      /* In PE COFF, write the count of relocs as the first
! 		 reloc.  The header overflow bit will be set
! 		 elsewhere. */
! 	      struct internal_reloc incount;
! 	      bfd_byte *excount = (bfd_byte *)bfd_malloc (relsz);
! 	      
! 	      memset (&incount, 0, sizeof (incount));
! 	      incount.r_vaddr = o->reloc_count + 1;
! 	      bfd_coff_swap_reloc_out (abfd, (PTR) &incount, (PTR) excount);
! 	      if (bfd_bwrite (excount, relsz, abfd) != relsz)
! 		/* We'll leak, but it's an error anyway. */
! 		goto error_return;
! 	      free (excount);
! 	    }
! 	  if (bfd_bwrite (external_relocs,
! 			  (bfd_size_type) relsz * o->reloc_count, abfd)
! 	      != (bfd_size_type) relsz * o->reloc_count)
  	    goto error_return;
  	}
  
Index: bfd/peXXigen.c
===================================================================
RCS file: /cvs/src/src/bfd/peXXigen.c,v
retrieving revision 1.15
diff -c -3 -p -r1.15 peXXigen.c
*** bfd/peXXigen.c	25 Jun 2003 06:40:23 -0000	1.15
--- bfd/peXXigen.c	19 Sep 2003 14:06:17 -0000
*************** _bfd_XXi_swap_scnhdr_out (abfd, in, out)
*** 990,996 ****
  	  ret = 0;
  	}
  
!       if (scnhdr_int->s_nreloc <= 0xffff)
  	H_PUT_16 (abfd, scnhdr_int->s_nreloc, scnhdr_ext->s_nreloc);
        else
  	{
--- 990,1000 ----
  	  ret = 0;
  	}
  
!       /* Although we could encode 0xffff relocs here, we do not, to be
!          consistent with other parts of bfd. Also it lets us warn, as
!          we should never see 0xffff here w/o having the overflow flag
!          set.  */
!       if (scnhdr_int->s_nreloc < 0xffff)
  	H_PUT_16 (abfd, scnhdr_int->s_nreloc, scnhdr_ext->s_nreloc);
        else
  	{

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