+ FIXME: This routine ignores any special_function in the HOWTO,
+ since the existing special_function values have been written for
+ bfd_perform_relocation.
+
+ HOWTO is the reloc howto information.
+ INPUT_BFD is the BFD which the reloc applies to.
+ INPUT_SECTION is the section which the reloc applies to.
+ CONTENTS is the contents of the section.
+ ADDRESS is the address of the reloc within INPUT_SECTION.
+ VALUE is the value of the symbol the reloc refers to.
+ ADDEND is the addend of the reloc. */
+
+bfd_reloc_status_type
+_bfd_final_link_relocate (howto, input_bfd, input_section, contents, address,
+ value, addend)
+ const reloc_howto_type *howto;
+ bfd *input_bfd;
+ asection *input_section;
+ bfd_byte *contents;
+ bfd_vma address;
+ bfd_vma value;
+ bfd_vma addend;
+{
+ bfd_vma relocation;
+
+ /* Sanity check the address. */
+ if (address > input_section->_cooked_size)
+ return bfd_reloc_outofrange;
+
+ /* This function assumes that we are dealing with a basic relocation
+ against a symbol. We want to compute the value of the symbol to
+ relocate to. This is just VALUE, the value of the symbol, plus
+ ADDEND, any addend associated with the reloc. */
+ relocation = value + addend;
+
+ /* If the relocation is PC relative, we want to set RELOCATION to
+ the distance between the symbol (currently in RELOCATION) and the
+ location we are relocating. Some targets (e.g., i386-aout)
+ arrange for the contents of the section to be the negative of the
+ offset of the location within the section; for such targets
+ pcrel_offset is false. Other targets (e.g., m88kbcs or ELF)
+ simply leave the contents of the section as zero; for such
+ targets pcrel_offset is true. If pcrel_offset is false we do not
+ need to subtract out the offset of the location within the
+ section (which is just ADDRESS). */
+ if (howto->pc_relative)
+ {
+ relocation -= (input_section->output_section->vma
+ + input_section->output_offset);
+ if (howto->pcrel_offset)
+ relocation -= address;
+ }
+
+ return _bfd_relocate_contents (howto, input_bfd, relocation,
+ contents + address);
+}
+
+/* Relocate a given location using a given value and howto. */
+
+bfd_reloc_status_type
+_bfd_relocate_contents (howto, input_bfd, relocation, location)
+ const reloc_howto_type *howto;
+ bfd *input_bfd;
+ bfd_vma relocation;
+ bfd_byte *location;
+{
+ int size;
+ bfd_vma x;
+ boolean overflow;
+
+ /* If the size is negative, negate RELOCATION. This isn't very
+ general. */
+ if (howto->size < 0)
+ relocation = - relocation;
+
+ /* Get the value we are going to relocate. */
+ size = bfd_get_reloc_size (howto);
+ switch (size)
+ {
+ default:
+ case 0:
+ abort ();
+ case 1:
+ x = bfd_get_8 (input_bfd, location);
+ break;
+ case 2:
+ x = bfd_get_16 (input_bfd, location);
+ break;
+ case 4:
+ x = bfd_get_32 (input_bfd, location);
+ break;
+ case 8:
+#ifdef BFD64
+ x = bfd_get_64 (input_bfd, location);
+#else
+ abort ();
+#endif
+ break;
+ }
+
+ /* Check for overflow. FIXME: We may drop bits during the addition
+ which we don't check for. We must either check at every single
+ operation, which would be tedious, or we must do the computations
+ in a type larger than bfd_vma, which would be inefficient. */
+ overflow = false;
+ if (howto->complain_on_overflow != complain_overflow_dont)
+ {
+ bfd_vma check;
+ bfd_signed_vma signed_check;
+ bfd_vma add;
+ bfd_signed_vma signed_add;
+
+ if (howto->rightshift == 0)
+ {
+ check = relocation;
+ signed_check = (bfd_signed_vma) relocation;
+ }
+ else
+ {
+ /* Drop unwanted bits from the value we are relocating to. */
+ check = relocation >> howto->rightshift;
+
+ /* If this is a signed value, the rightshift just dropped
+ leading 1 bits (assuming twos complement). */
+ if ((bfd_signed_vma) relocation >= 0)
+ signed_check = check;
+ else
+ signed_check = (check
+ | ((bfd_vma) -1
+ &~ ((bfd_vma) -1 >> howto->rightshift)));
+ }
+
+ /* Get the value from the object file. */
+ add = x & howto->src_mask;
+
+ /* Get the value from the object file with an appropriate sign.
+ The expression involving howto->src_mask isolates the upper
+ bit of src_mask. If that bit is set in the value we are
+ adding, it is negative, and we subtract out that number times
+ two. If src_mask includes the highest possible bit, then we
+ can not get the upper bit, but that does not matter since
+ signed_add needs no adjustment to become negative in that
+ case. */
+ signed_add = add;
+ if ((add & (((~ howto->src_mask) >> 1) & howto->src_mask)) != 0)
+ signed_add -= (((~ howto->src_mask) >> 1) & howto->src_mask) << 1;
+
+ /* Add the value from the object file, shifted so that it is a
+ straight number. */
+ if (howto->bitpos == 0)
+ {
+ check += add;
+ signed_check += signed_add;
+ }
+ else
+ {
+ check += add >> howto->bitpos;
+
+ /* For the signed case we use ADD, rather than SIGNED_ADD,
+ to avoid warnings from SVR4 cc. This is OK since we
+ explictly handle the sign bits. */
+ if (signed_add >= 0)
+ signed_check += add >> howto->bitpos;
+ else
+ signed_check += ((add >> howto->bitpos)
+ | ((bfd_vma) -1
+ &~ ((bfd_vma) -1 >> howto->bitpos)));
+ }
+
+ 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;
+
+ if (signed_check > reloc_signed_max
+ || signed_check < reloc_signed_min)
+ overflow = true;
+ }
+ 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 (check > reloc_unsigned_max)
+ overflow = true;
+ }
+ 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 ((check &~ reloc_bits) != 0
+ && (((bfd_vma) signed_check &~ reloc_bits)
+ != (-1 &~ reloc_bits)))
+ overflow = true;
+ }
+ break;
+ default:
+ abort ();
+ }
+ }
+
+ /* Put RELOCATION in the right bits. */
+ relocation >>= (bfd_vma) howto->rightshift;
+ relocation <<= (bfd_vma) howto->bitpos;
+
+ /* Add RELOCATION to the right bits of X. */
+ x = ((x &~ howto->dst_mask)
+ | (((x & howto->src_mask) + relocation) & howto->dst_mask));
+
+ /* Put the relocated value back in the object file. */
+ switch (size)
+ {
+ default:
+ case 0:
+ abort ();
+ case 1:
+ bfd_put_8 (input_bfd, x, location);
+ break;
+ case 2:
+ bfd_put_16 (input_bfd, x, location);
+ break;
+ case 4:
+ bfd_put_32 (input_bfd, x, location);
+ break;
+ case 8:
+#ifdef BFD64
+ bfd_put_64 (input_bfd, x, location);
+#else
+ abort ();
+#endif
+ break;
+ }
+
+ return overflow ? bfd_reloc_overflow : bfd_reloc_ok;
+}