+ /* See if we have a REL type relocation. */
+ is_rel_reloc = (esd->rel.hdr != NULL);
+ /* Sanity check - only one type of relocation per section.
+ FIXME: Theoretically it is possible to have both types,
+ but if that happens how can we distinguish between the two ? */
+ BFD_ASSERT (! is_rel_reloc || ! esd->rela.hdr);
+ /* If we are using a REL relocation then the addend should be empty. */
+ BFD_ASSERT (! is_rel_reloc || rel->r_addend == 0);
+ }
+
+ if (sym_diff_section != NULL)
+ {
+ BFD_ASSERT (sym_diff_section == input_section);
+
+ if (uses_msp430x_relocs (input_bfd))
+ switch (howto->type)
+ {
+ case R_MSP430_ABS32:
+ /* If we are computing a 32-bit value for the location lists
+ and the result is 0 then we add one to the value. A zero
+ value can result because of linker relaxation deleteing
+ prologue instructions and using a value of 1 (for the begin
+ and end offsets in the location list entry) results in a
+ nul entry which does not prevent the following entries from
+ being parsed. */
+ if (relocation == sym_diff_value
+ && strcmp (input_section->name, ".debug_loc") == 0)
+ ++ relocation;
+ /* Fall through. */
+ case R_MSP430_ABS16:
+ case R_MSP430X_ABS16:
+ case R_MSP430_ABS8:
+ BFD_ASSERT (! is_rel_reloc);
+ relocation -= sym_diff_value;
+ break;
+
+ default:
+ return bfd_reloc_dangerous;
+ }
+ else
+ switch (howto->type)
+ {
+ case R_MSP430_32:
+ case R_MSP430_16:
+ case R_MSP430_16_BYTE:
+ case R_MSP430_8:
+ relocation -= sym_diff_value;
+ break;
+
+ default:
+ return bfd_reloc_dangerous;
+ }
+
+ sym_diff_section = NULL;
+ }
+
+ if (uses_msp430x_relocs (input_bfd))
+ switch (howto->type)
+ {
+ case R_MSP430X_SYM_DIFF:
+ /* Cache the input section and value.
+ The offset is unreliable, since relaxation may
+ have reduced the following reloc's offset. */
+ BFD_ASSERT (! is_rel_reloc);
+ sym_diff_section = input_section;
+ sym_diff_value = relocation;
+ return bfd_reloc_ok;
+
+ case R_MSP430_ABS16:
+ contents += rel->r_offset;
+ srel = (bfd_signed_vma) relocation;
+ if (is_rel_reloc)
+ srel += bfd_get_16 (input_bfd, contents);
+ else
+ srel += rel->r_addend;
+ bfd_put_16 (input_bfd, srel & 0xffff, contents);
+ break;
+
+ case R_MSP430X_10_PCREL:
+ contents += rel->r_offset;
+ srel = (bfd_signed_vma) relocation;
+ if (is_rel_reloc)
+ srel += bfd_get_16 (input_bfd, contents) & 0x3ff;
+ else
+ srel += rel->r_addend;
+ srel -= rel->r_offset;
+ srel -= 2; /* Branch instructions add 2 to the PC... */
+ srel -= (input_section->output_section->vma +
+ input_section->output_offset);
+ if (srel & 1)
+ return bfd_reloc_outofrange;
+
+ /* MSP430 addresses commands as words. */
+ srel >>= 1;
+
+ /* Check for an overflow. */
+ if (srel < -512 || srel > 511)
+ {
+ if (info->disable_target_specific_optimizations < 0)
+ {
+ static bfd_boolean warned = FALSE;
+ if (! warned)
+ {
+ info->callbacks->warning
+ (info,
+ _("Try enabling relaxation to avoid relocation truncations"),
+ NULL, input_bfd, input_section, relocation);
+ warned = TRUE;
+ }
+ }
+ return bfd_reloc_overflow;
+ }
+
+ x = bfd_get_16 (input_bfd, contents);
+ x = (x & 0xfc00) | (srel & 0x3ff);
+ bfd_put_16 (input_bfd, x, contents);
+ break;
+
+ case R_MSP430X_PCR20_EXT_ODST:
+ /* [0,4]+[48,16] = ---F ---- ---- FFFF */
+ contents += rel->r_offset;
+ srel = (bfd_signed_vma) relocation;
+ if (is_rel_reloc)
+ {
+ bfd_vma addend;
+ addend = (bfd_get_16 (input_bfd, contents) & 0xf) << 16;
+ addend |= bfd_get_16 (input_bfd, contents + 6);
+ srel += addend;
+
+ }
+ else
+ srel += rel->r_addend;
+ srel -= rel->r_offset;
+ srel -= (input_section->output_section->vma +
+ input_section->output_offset);
+ bfd_put_16 (input_bfd, (srel & 0xffff), contents + 6);
+ x = bfd_get_16 (input_bfd, contents);
+ x = (x & 0xfff0) | ((srel >> 16) & 0xf);
+ bfd_put_16 (input_bfd, x, contents);
+ break;
+
+ case R_MSP430X_ABS20_EXT_SRC:
+ /* [7,4]+[32,16] = -78- ---- FFFF */
+ contents += rel->r_offset;
+ srel = (bfd_signed_vma) relocation;
+ if (is_rel_reloc)
+ {
+ bfd_vma addend;
+ addend = (bfd_get_16 (input_bfd, contents) & 0x0780) << 9;
+ addend |= bfd_get_16 (input_bfd, contents + 4);
+ srel += addend;
+ }
+ else
+ srel += rel->r_addend;
+ bfd_put_16 (input_bfd, (srel & 0xffff), contents + 4);
+ srel >>= 16;
+ x = bfd_get_16 (input_bfd, contents);
+ x = (x & 0xf87f) | ((srel << 7) & 0x0780);
+ bfd_put_16 (input_bfd, x, contents);
+ break;
+
+ case R_MSP430_16_PCREL:
+ contents += rel->r_offset;
+ srel = (bfd_signed_vma) relocation;
+ if (is_rel_reloc)
+ srel += bfd_get_16 (input_bfd, contents);
+ else
+ srel += rel->r_addend;
+ srel -= rel->r_offset;
+ /* Only branch instructions add 2 to the PC... */
+ srel -= (input_section->output_section->vma +
+ input_section->output_offset);
+ if (srel & 1)
+ return bfd_reloc_outofrange;
+ bfd_put_16 (input_bfd, srel & 0xffff, contents);
+ break;
+
+ case R_MSP430X_PCR20_EXT_DST:
+ /* [0,4]+[32,16] = ---F ---- FFFF */
+ contents += rel->r_offset;
+ srel = (bfd_signed_vma) relocation;
+ if (is_rel_reloc)
+ {
+ bfd_vma addend;
+ addend = (bfd_get_16 (input_bfd, contents) & 0xf) << 16;
+ addend |= bfd_get_16 (input_bfd, contents + 4);
+ srel += addend;
+ }
+ else
+ srel += rel->r_addend;
+ srel -= rel->r_offset;
+ srel -= (input_section->output_section->vma +
+ input_section->output_offset);
+ bfd_put_16 (input_bfd, (srel & 0xffff), contents + 4);
+ srel >>= 16;
+ x = bfd_get_16 (input_bfd, contents);
+ x = (x & 0xfff0) | (srel & 0xf);
+ bfd_put_16 (input_bfd, x, contents);
+ break;
+
+ case R_MSP430X_PCR20_EXT_SRC:
+ /* [7,4]+[32,16] = -78- ---- FFFF */
+ contents += rel->r_offset;
+ srel = (bfd_signed_vma) relocation;
+ if (is_rel_reloc)
+ {
+ bfd_vma addend;
+ addend = ((bfd_get_16 (input_bfd, contents) & 0x0780) << 9);
+ addend |= bfd_get_16 (input_bfd, contents + 4);
+ srel += addend;;
+ }
+ else
+ srel += rel->r_addend;
+ srel -= rel->r_offset;
+ /* Only branch instructions add 2 to the PC... */
+ srel -= (input_section->output_section->vma +
+ input_section->output_offset);
+ bfd_put_16 (input_bfd, (srel & 0xffff), contents + 4);
+ srel >>= 16;
+ x = bfd_get_16 (input_bfd, contents);
+ x = (x & 0xf87f) | ((srel << 7) & 0x0780);
+ bfd_put_16 (input_bfd, x, contents);
+ break;
+
+ case R_MSP430_ABS8:
+ contents += rel->r_offset;
+ srel = (bfd_signed_vma) relocation;
+ if (is_rel_reloc)
+ srel += bfd_get_8 (input_bfd, contents);
+ else
+ srel += rel->r_addend;
+ bfd_put_8 (input_bfd, srel & 0xff, contents);
+ break;
+
+ case R_MSP430X_ABS20_EXT_DST:
+ /* [0,4]+[32,16] = ---F ---- FFFF */
+ contents += rel->r_offset;
+ srel = (bfd_signed_vma) relocation;
+ if (is_rel_reloc)
+ {
+ bfd_vma addend;
+ addend = (bfd_get_16 (input_bfd, contents) & 0xf) << 16;
+ addend |= bfd_get_16 (input_bfd, contents + 4);
+ srel += addend;
+ }
+ else
+ srel += rel->r_addend;
+ bfd_put_16 (input_bfd, (srel & 0xffff), contents + 4);
+ srel >>= 16;
+ x = bfd_get_16 (input_bfd, contents);
+ x = (x & 0xfff0) | (srel & 0xf);
+ bfd_put_16 (input_bfd, x, contents);
+ break;
+
+ case R_MSP430X_ABS20_EXT_ODST:
+ /* [0,4]+[48,16] = ---F ---- ---- FFFF */
+ contents += rel->r_offset;
+ srel = (bfd_signed_vma) relocation;
+ if (is_rel_reloc)
+ {
+ bfd_vma addend;
+ addend = (bfd_get_16 (input_bfd, contents) & 0xf) << 16;
+ addend |= bfd_get_16 (input_bfd, contents + 6);
+ srel += addend;
+ }
+ else
+ srel += rel->r_addend;
+ bfd_put_16 (input_bfd, (srel & 0xffff), contents + 6);
+ srel >>= 16;
+ x = bfd_get_16 (input_bfd, contents);
+ x = (x & 0xfff0) | (srel & 0xf);
+ bfd_put_16 (input_bfd, x, contents);
+ break;
+
+ case R_MSP430X_ABS20_ADR_SRC:
+ /* [8,4]+[16,16] = -F-- FFFF */
+ contents += rel->r_offset;
+ srel = (bfd_signed_vma) relocation;
+ if (is_rel_reloc)
+ {
+ bfd_vma addend;
+
+ addend = ((bfd_get_16 (input_bfd, contents) & 0xf00) << 8);
+ addend |= bfd_get_16 (input_bfd, contents + 2);
+ srel += addend;
+ }
+ else
+ srel += rel->r_addend;
+ bfd_put_16 (input_bfd, (srel & 0xffff), contents + 2);
+ srel >>= 16;
+ x = bfd_get_16 (input_bfd, contents);
+ x = (x & 0xf0ff) | ((srel << 8) & 0x0f00);
+ bfd_put_16 (input_bfd, x, contents);
+ break;
+
+ case R_MSP430X_ABS20_ADR_DST:
+ /* [0,4]+[16,16] = ---F FFFF */
+ contents += rel->r_offset;
+ srel = (bfd_signed_vma) relocation;
+ if (is_rel_reloc)
+ {
+ bfd_vma addend;
+ addend = ((bfd_get_16 (input_bfd, contents) & 0xf) << 16);
+ addend |= bfd_get_16 (input_bfd, contents + 2);
+ srel += addend;
+ }
+ else
+ srel += rel->r_addend;
+ bfd_put_16 (input_bfd, (srel & 0xffff), contents + 2);
+ srel >>= 16;
+ x = bfd_get_16 (input_bfd, contents);
+ x = (x & 0xfff0) | (srel & 0xf);
+ bfd_put_16 (input_bfd, x, contents);
+ break;
+
+ case R_MSP430X_ABS16:
+ contents += rel->r_offset;
+ srel = (bfd_signed_vma) relocation;
+ if (is_rel_reloc)
+ srel += bfd_get_16 (input_bfd, contents);
+ else
+ srel += rel->r_addend;
+ x = srel;
+ if (x > 0xffff)
+ return bfd_reloc_overflow;
+ bfd_put_16 (input_bfd, srel & 0xffff, contents);
+ break;
+
+ case R_MSP430_ABS_HI16:
+ /* The EABI specifies that this must be a RELA reloc. */
+ BFD_ASSERT (! is_rel_reloc);
+ contents += rel->r_offset;
+ srel = (bfd_signed_vma) relocation;
+ srel += rel->r_addend;
+ bfd_put_16 (input_bfd, (srel >> 16) & 0xffff, contents);
+ break;
+
+ case R_MSP430X_PCR20_CALL:
+ /* [0,4]+[16,16] = ---F FFFF*/
+ contents += rel->r_offset;
+ srel = (bfd_signed_vma) relocation;
+ if (is_rel_reloc)
+ {
+ bfd_vma addend;
+ addend = (bfd_get_16 (input_bfd, contents) & 0xf) << 16;
+ addend |= bfd_get_16 (input_bfd, contents + 2);
+ srel += addend;
+ }
+ else
+ srel += rel->r_addend;
+ srel -= rel->r_offset;
+ srel -= (input_section->output_section->vma +
+ input_section->output_offset);
+ bfd_put_16 (input_bfd, srel & 0xffff, contents + 2);
+ srel >>= 16;
+ x = bfd_get_16 (input_bfd, contents);
+ x = (x & 0xfff0) | (srel & 0xf);
+ bfd_put_16 (input_bfd, x, contents);
+ break;
+
+ case R_MSP430X_PCR16:
+ contents += rel->r_offset;
+ srel = (bfd_signed_vma) relocation;
+ if (is_rel_reloc)
+ srel += bfd_get_16 (input_bfd, contents);
+ else
+ srel += rel->r_addend;
+ srel -= rel->r_offset;
+ srel -= (input_section->output_section->vma +
+ input_section->output_offset);
+ bfd_put_16 (input_bfd, srel & 0xffff, contents);
+ break;
+
+ case R_MSP430_PREL31:
+ contents += rel->r_offset;
+ srel = (bfd_signed_vma) relocation;
+ if (is_rel_reloc)
+ srel += (bfd_get_32 (input_bfd, contents) & 0x7fffffff);
+ else
+ srel += rel->r_addend;
+ srel += rel->r_addend;
+ x = bfd_get_32 (input_bfd, contents);
+ x = (x & 0x80000000) | ((srel >> 31) & 0x7fffffff);
+ bfd_put_32 (input_bfd, x, contents);
+ break;
+
+ default:
+ r = _bfd_final_link_relocate (howto, input_bfd, input_section,
+ contents, rel->r_offset,
+ relocation, rel->r_addend);
+ }
+ else
+ switch (howto->type)
+ {