(bfd_perform_relocation): Handle 64-bit relocs.
authorKen Raeburn <raeburn@cygnus>
Mon, 26 Jul 1993 18:42:09 +0000 (18:42 +0000)
committerKen Raeburn <raeburn@cygnus>
Mon, 26 Jul 1993 18:42:09 +0000 (18:42 +0000)
bfd/reloc.c

index 890cb6f3d626d33b3dd8c35abac57833ef023734..c2df4b722b0dac4cef624b73c5bd3e5caf6fa0fe 100644 (file)
@@ -575,51 +575,68 @@ DEFUN(bfd_perform_relocation,(abfd,
       reloc_entry->addend = 0;
     }
 
-
   /* FIXME: This overflow checking is incomplete, because the value
      might have overflowed before we get here.  For a correct check we
      need to compute the value in a size larger than bitsize, but we
      can't reasonably do that for a reloc the same size as a host
      machine word.  */
-  switch (howto->complain_on_overflow)
+  if (howto->complain_on_overflow != complain_overflow_dont)
     {
-    case complain_overflow_dont:
-      break;
-    case complain_overflow_signed:
-      {
-       /* Assumes two's complement.  */
-       bfd_signed_vma reloc_signed_max = (1 << (howto->bitsize - 1)) - 1;
-       bfd_signed_vma reloc_signed_min = ~ reloc_signed_max;
-
-       if ((bfd_signed_vma) relocation > reloc_signed_max
-           || (bfd_signed_vma) relocation < reloc_signed_min)
-         flag = bfd_reloc_overflow;
-      }
-      break;
-    case complain_overflow_unsigned:
-      {
-       /* Assumes two's complement.  This expression avoids overflow
-          if howto->bitsize is the number of bits in bfd_vma.  */
-       bfd_vma reloc_unsigned_max =
-         (((1 << (howto->bitsize - 1)) - 1) << 1) | 1;
-
-       if ((bfd_vma) relocation > reloc_unsigned_max)
-         flag = bfd_reloc_overflow;
-      }
-      break;
-    case complain_overflow_bitfield:
-      {
-       /* Assumes two's complement.  This expression avoids overflow
-          if howto->bitsize is the number of bits in bfd_vma.  */
-       bfd_vma reloc_bits = (((1 << (howto->bitsize - 1)) - 1) << 1) | 1;
+      bfd_vma check;
 
-       if (((bfd_vma) relocation &~ reloc_bits) != 0
-           && ((bfd_vma) relocation &~ reloc_bits) != (-1 &~ reloc_bits))
-         flag = bfd_reloc_overflow;
-      }
-      break;
-    default:
-      abort ();
+      /* Get the value that will be used for the relocation, but
+        starting at bit position zero.  */
+      if (howto->rightshift > howto->bitpos)
+       check = relocation >> (howto->rightshift - howto->bitpos);
+      else
+       check = relocation << (howto->bitpos - howto->rightshift);
+      switch (howto->complain_on_overflow)
+       {
+       case complain_overflow_signed:
+         {
+           /* Assumes two's complement.  */
+           bfd_signed_vma reloc_signed_max = (1 << (howto->bitsize - 1)) - 1;
+           bfd_signed_vma reloc_signed_min = ~ reloc_signed_max;
+
+           /* The above right shift is incorrect for a signed value.
+              Fix it up by forcing on the upper bits.  */
+           if (howto->rightshift > howto->bitpos
+               && (bfd_signed_vma) relocation < 0)
+             check |= ((bfd_vma) -1
+                       &~ ((bfd_vma) -1
+                           >> (howto->rightshift - howto->bitpos)));
+           if ((bfd_signed_vma) check > reloc_signed_max
+               || (bfd_signed_vma) check < reloc_signed_min)
+             flag = bfd_reloc_overflow;
+         }
+         break;
+       case complain_overflow_unsigned:
+         {
+           /* Assumes two's complement.  This expression avoids
+              overflow if howto->bitsize is the number of bits in
+              bfd_vma.  */
+           bfd_vma reloc_unsigned_max =
+             (((1 << (howto->bitsize - 1)) - 1) << 1) | 1;
+
+           if ((bfd_vma) check > reloc_unsigned_max)
+             flag = bfd_reloc_overflow;
+         }
+         break;
+       case complain_overflow_bitfield:
+         {
+           /* Assumes two's complement.  This expression avoids
+              overflow if howto->bitsize is the number of bits in
+              bfd_vma.  */
+           bfd_vma reloc_bits = (((1 << (howto->bitsize - 1)) - 1) << 1) | 1;
+
+           if (((bfd_vma) check &~ reloc_bits) != 0
+               && ((bfd_vma) check &~ reloc_bits) != (-1 &~ reloc_bits))
+             flag = bfd_reloc_overflow;
+         }
+         break;
+       default:
+         abort ();
+       }
     }
   
   /* 
@@ -705,9 +722,21 @@ DEFUN(bfd_perform_relocation,(abfd,
        break;
 
      case 3:
-
        /* Do nothing */
        break;
+
+     case 4:
+#ifdef BFD64
+       if (relocation)
+        {
+          bfd_vma x = bfd_get_64 (abfd, (bfd_byte *) data + addr);
+          DOIT (x);
+          bfd_put_64 (abfd, x, (bfd_byte *) data + addr);
+        }
+#else
+       abort ();
+#endif
+       break;
      default:
        return bfd_reloc_other;
      }