aboutsummaryrefslogtreecommitdiff
path: root/bfd/elf32-msp430.c
diff options
context:
space:
mode:
authorNick Clifton <nickc@redhat.com>2015-06-05 16:40:37 +0100
committerNick Clifton <nickc@redhat.com>2015-06-05 16:40:37 +0100
commit1ade71756948cad279f9b01d88ae762d144643e3 (patch)
tree31727e3a57d39007ca3441cccc90fb2a6b7e1591 /bfd/elf32-msp430.c
parente3dd7556ad89bf00c2a92f76079ae1c53dc130a8 (diff)
downloadbinutils-1ade71756948cad279f9b01d88ae762d144643e3.zip
binutils-1ade71756948cad279f9b01d88ae762d144643e3.tar.gz
binutils-1ade71756948cad279f9b01d88ae762d144643e3.tar.bz2
Fixes computation of MSP430 SYM_DIFF relocs in very small sections.
* elf32-msp430.c (rl78_sym_diff_handler): New function. (msp430_howto_table): Use the new function for the SYM_DIFF reloc. (msp430x_howto_table): Likewise.
Diffstat (limited to 'bfd/elf32-msp430.c')
-rw-r--r--bfd/elf32-msp430.c31
1 files changed, 28 insertions, 3 deletions
diff --git a/bfd/elf32-msp430.c b/bfd/elf32-msp430.c
index fdab3d3..edd49f7 100644
--- a/bfd/elf32-msp430.c
+++ b/bfd/elf32-msp430.c
@@ -26,6 +26,31 @@
#include "elf-bfd.h"
#include "elf/msp430.h"
+static bfd_reloc_status_type
+rl78_sym_diff_handler (bfd * abfd,
+ arelent * reloc,
+ asymbol * sym ATTRIBUTE_UNUSED,
+ void * addr ATTRIBUTE_UNUSED,
+ asection * input_sec,
+ bfd * out_bfd ATTRIBUTE_UNUSED,
+ char ** error_message ATTRIBUTE_UNUSED)
+{
+ bfd_size_type octets;
+ octets = reloc->address * bfd_octets_per_byte (abfd);
+
+ /* Catch the case where bfd_install_relocation would return
+ bfd_reloc_outofrange because the SYM_DIFF reloc is being used in a very
+ small section. It does not actually matter if this happens because all
+ that SYM_DIFF does is compute a (4-byte) value. A second reloc then uses
+ this value, and it is that reloc that must fit into the section.
+
+ This happens in eg, gcc/testsuite/gcc.c-torture/compile/labels-3.c. */
+ if ((octets + bfd_get_reloc_size (reloc->howto))
+ > bfd_get_section_limit_octets (abfd, input_sec))
+ return bfd_reloc_ok;
+ return bfd_reloc_continue;
+}
+
static reloc_howto_type elf_msp430_howto_table[] =
{
HOWTO (R_MSP430_NONE, /* type */
@@ -185,7 +210,7 @@ static reloc_howto_type elf_msp430_howto_table[] =
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont,/* complain_on_overflow */
- NULL, /* special handler. */
+ rl78_sym_diff_handler, /* special handler. */
"R_MSP430_SYM_DIFF", /* name */
FALSE, /* partial_inplace */
0xffffffff, /* src_mask */
@@ -488,7 +513,7 @@ static reloc_howto_type elf_msp430x_howto_table[] =
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont,/* complain_on_overflow */
- NULL, /* special handler. */
+ rl78_sym_diff_handler, /* special handler. */
"R_MSP430X_SYM_DIFF", /* name */
FALSE, /* partial_inplace */
0xffffffff, /* src_mask */
@@ -1596,7 +1621,7 @@ msp430_elf_relax_adjust_locals (bfd * abfd, asection * sec, bfd_vma addr,
unsigned int sidx = ELF32_R_SYM(irel->r_info);
Elf_Internal_Sym *lsym = isym + sidx;
- /* Adjust symbols referenced by .sec+0xXX */
+ /* Adjust symbols referenced by .sec+0xXX. */
if (irel->r_addend > addr && irel->r_addend < toaddr
&& sidx < symtab_hdr->sh_info
&& lsym->st_shndx == sec_shndx)