This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
Fix pe-coff reloc overflow problems
- From: Nathan Sidwell <nathan at codesourcery dot com>
- To: binutils at sources dot redhat dot com
- Date: Fri, 19 Sep 2003 15:43:42 +0100
- Subject: Fix pe-coff reloc overflow problems
- Organization: Codesourcery LLC
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
{