FALSE, 0, 0, FALSE),
 
   /* Relocations for supporting difference of symbols.  */
-  HOWTO (R_XTENSA_DIFF8, 0, 0, 8, FALSE, 0, complain_overflow_bitfield,
+  HOWTO (R_XTENSA_DIFF8, 0, 0, 8, FALSE, 0, complain_overflow_signed,
         bfd_elf_xtensa_reloc, "R_XTENSA_DIFF8", FALSE, 0, 0xff, FALSE),
-  HOWTO (R_XTENSA_DIFF16, 0, 1, 16, FALSE, 0, complain_overflow_bitfield,
+  HOWTO (R_XTENSA_DIFF16, 0, 1, 16, FALSE, 0, complain_overflow_signed,
         bfd_elf_xtensa_reloc, "R_XTENSA_DIFF16", FALSE, 0, 0xffff, FALSE),
-  HOWTO (R_XTENSA_DIFF32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
+  HOWTO (R_XTENSA_DIFF32, 0, 2, 32, FALSE, 0, complain_overflow_signed,
         bfd_elf_xtensa_reloc, "R_XTENSA_DIFF32", FALSE, 0, 0xffffffff, FALSE),
 
   /* General immediate operand relocations.  */
                  || r_type == R_XTENSA_DIFF16
                  || r_type == R_XTENSA_DIFF32)
                {
-                 bfd_vma diff_value = 0, new_end_offset, diff_mask = 0;
+                 bfd_signed_vma diff_value = 0;
+                 bfd_vma new_end_offset, diff_mask = 0;
 
                  if (bfd_get_section_limit (abfd, sec) < old_source_offset)
                    {
                    {
                    case R_XTENSA_DIFF8:
                      diff_value =
-                       bfd_get_8 (abfd, &contents[old_source_offset]);
+                       bfd_get_signed_8 (abfd, &contents[old_source_offset]);
                      break;
                    case R_XTENSA_DIFF16:
                      diff_value =
-                       bfd_get_16 (abfd, &contents[old_source_offset]);
+                       bfd_get_signed_16 (abfd, &contents[old_source_offset]);
                      break;
                    case R_XTENSA_DIFF32:
                      diff_value =
-                       bfd_get_32 (abfd, &contents[old_source_offset]);
+                       bfd_get_signed_32 (abfd, &contents[old_source_offset]);
                      break;
                    }
 
                  switch (r_type)
                    {
                    case R_XTENSA_DIFF8:
-                     diff_mask = 0xff;
-                     bfd_put_8 (abfd, diff_value,
+                     diff_mask = 0x7f;
+                     bfd_put_signed_8 (abfd, diff_value,
                                 &contents[old_source_offset]);
                      break;
                    case R_XTENSA_DIFF16:
-                     diff_mask = 0xffff;
-                     bfd_put_16 (abfd, diff_value,
+                     diff_mask = 0x7fff;
+                     bfd_put_signed_16 (abfd, diff_value,
                                  &contents[old_source_offset]);
                      break;
                    case R_XTENSA_DIFF32:
-                     diff_mask = 0xffffffff;
-                     bfd_put_32 (abfd, diff_value,
+                     diff_mask = 0x7fffffff;
+                     bfd_put_signed_32 (abfd, diff_value,
                                  &contents[old_source_offset]);
                      break;
                    }
 
-                 /* Check for overflow.  */
-                 if ((diff_value & ~diff_mask) != 0)
+                 /* Check for overflow. Sign bits must be all zeroes or all ones */
+                 if ((diff_value & ~diff_mask) != 0 &&
+                     (diff_value & ~diff_mask) != (-1 & ~diff_mask))
                    {
                      (*link_info->callbacks->reloc_dangerous)
                        (link_info, _("overflow after relaxation"),
 
--- /dev/null
+# Test DIFF* relocation signedness and overflow checking
+# By Max Filippov, Cadence Design Systems, Inc.
+#   Copyright (C) 2014 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+if ![istarget "xtensa*-*-*"] {
+    return
+}
+
+set testname "DIFF_OVERFLOW"
+
+if ![ld_assemble $as "--text-section-literals $srcdir/$subdir/diff_overflow1.s" tmpdir/diff_overflow1.o] {
+    unresolved $testname
+    return
+}
+if ![ld_assemble $as "--text-section-literals $srcdir/$subdir/diff_overflow2.s" tmpdir/diff_overflow2.o] {
+    unresolved $testname
+    return
+}
+
+set object "tmpdir/diff_overflow"
+
+if ![ld_simple_link $ld $object "tmpdir/diff_overflow1.o tmpdir/diff_overflow2.o"] {
+    verbose -log "failure in ld"
+    fail $testname
+    return
+}
+
+pass $testname