This is the mail archive of the
binutils@sourceware.cygnus.com
mailing list for the binutils project.
reloc overflows
- To: ian at zembu dot com
- Subject: reloc overflows
- From: Alan Modra <alan at SPRI dot Levels dot UniSA dot Edu dot Au>
- Date: Sat, 11 Mar 2000 13:02:04 +1030 (CST)
- cc: binutils at sourceware dot cygnus dot com
I've just been looking at ways to fix the 16-bit reloc overflow problem
discussed in the thread starting at
http://sourceware.cygnus.com/ml/binutils/2000-02/msg00198.html My
conclusion is that it's not easy to fix without either massive hacks or a
fairly simple change in bitfield overflow handling.
Actually, the problem isn't limited to 16-bit relocs. It also shows up in
32-bit relocs when compiling bfd with --enable-64-bit-bfd (or with some
target requiring BFD64). Using an x86 example
$ cat jmp.s
.extern foo
jmp foo
$ gas/gas/as-new -o jmp.o jmp.s
$ gas/ld/ld-new -Ttext 0x80000000 -e 0x80000000 -defsym foo=0 jmp.o
jmp.o(.text+0x1): relocation truncated to fit: R_386_PC32 foo
$
This testcase doesn't fail when using a 32-bit bfd because Ian put in a
hack
/* We explicitly permit wrap around if this relocation
covers the high bit of an address. The Linux kernel
relies on it, and it is the only way to write assembler
code which can run when loaded at a location 0x80000000
away from the location at which it is linked. */
if (howto->bitsize + rightshift
== bfd_arch_bits_per_address (input_bfd))
break;
to circumvent some of the checks in _bfd_relocate_contents (case
complain_overflow_bitfield), but this isn't sufficient when compiling with
64-bit bfd. Moving the hack up a little will cure the problem by
effectively saying that if bits_per_address == 32 then a 32-bit bitfield
reloc can't overflow (which is what you get when compiling with a 32-bit
bfd). I don't particularly like this solution though as we might as well
remove all the bitfield overflow checking.
My alternative solution, which also fixes the 16-bit reloc problem, is to
say that a bitfield reloc of n bits can represent numbers in the range
-(2**n) to 2**n-1. The current range allowed is -(2**(n-1)) to 2**n-1,
ie. overlap of n bit signed and unsigned numbers.
What do you all think of this?