summaryrefslogtreecommitdiff
path: root/bfd/reloc.c
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2000-04-11 23:01:50 +0000
committerAlan Modra <amodra@gmail.com>2000-04-11 23:01:50 +0000
commit8a4ac87108a0ad21e0fa7890ee7bbdba5eb92ad5 (patch)
tree9722fc87ec9b4a6de04b99e49f1cd192b77a0662 /bfd/reloc.c
parent287e3058087929647df7eb001a99ed281d5d719d (diff)
downloadbinutils-gdb-8a4ac87108a0ad21e0fa7890ee7bbdba5eb92ad5.tar.gz
Allow address wrap for bitfields again.
Diffstat (limited to 'bfd/reloc.c')
-rw-r--r--bfd/reloc.c20
1 files changed, 11 insertions, 9 deletions
diff --git a/bfd/reloc.c b/bfd/reloc.c
index 8823c6ce53e..f312ffc5b72 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -1498,11 +1498,9 @@ _bfd_relocate_contents (howto, input_bfd, relocation, location)
trouble; we would need to verify that B is in range, as
we do for A above. */
signmask = ((~ howto->src_mask) >> 1) & howto->src_mask;
- if ((b & signmask) != 0)
- {
- /* Set all the bits above the sign bit. */
- b -= signmask << 1;
- }
+
+ /* Set all the bits above the sign bit. */
+ b = (b ^ signmask) - signmask;
b = (b & addrmask) >> bitpos;
@@ -1545,7 +1543,7 @@ _bfd_relocate_contents (howto, input_bfd, relocation, location)
case complain_overflow_bitfield:
/* Much like the signed check, but for a field one bit
- wider, and no trimming with addrmask. We allow a
+ wider, and no trimming inputs with addrmask. We allow a
bitfield to represent numbers in the range -2**n to
2**n-1, where n is the number of bits in the field.
Note that when bfd_vma is 32 bits, a 32-bit reloc can't
@@ -1558,15 +1556,19 @@ _bfd_relocate_contents (howto, input_bfd, relocation, location)
flag = bfd_reloc_overflow;
signmask = ((~ howto->src_mask) >> 1) & howto->src_mask;
- if ((b & signmask) != 0)
- b -= signmask << 1;
+ b = (b ^ signmask) - signmask;
b >>= bitpos;
sum = a + b;
+ /* We mask with addrmask here to explicitly allow an address
+ wrap-around. 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. */
signmask = fieldmask + 1;
- if (((~ (a ^ b)) & (a ^ sum)) & signmask)
+ if (((~ (a ^ b)) & (a ^ sum)) & signmask & addrmask)
flag = bfd_reloc_overflow;
break;