summaryrefslogtreecommitdiff
path: root/bfd/elf32-m32c.c
diff options
context:
space:
mode:
authorDJ Delorie <dj@redhat.com>2015-01-22 17:30:58 -0500
committerDJ Delorie <dj@redhat.com>2015-01-22 17:30:58 -0500
commit055173ca8d1dd3d886e88392a7b2c63c5ff20bda (patch)
treef690beab30e3291b8fcbe685aca47c86f0260a5c /bfd/elf32-m32c.c
parent717cf30c8230bcf1c7cc55353645bfc268a711d0 (diff)
downloadbinutils-gdb-055173ca8d1dd3d886e88392a7b2c63c5ff20bda.tar.gz
Handle R_M32C_24 specially
2015-01-22 DJ Delorie <dj@redhat.com> * elf32-m32c.c (m32c_apply_reloc_24): New. (m32c_elf_howto_table): Use it for R_M32C_24. (m32c_elf_relocate_section): Handle R_M32C_24 specially.
Diffstat (limited to 'bfd/elf32-m32c.c')
-rw-r--r--bfd/elf32-m32c.c75
1 files changed, 71 insertions, 4 deletions
diff --git a/bfd/elf32-m32c.c b/bfd/elf32-m32c.c
index cbc17659e85..75725811599 100644
--- a/bfd/elf32-m32c.c
+++ b/bfd/elf32-m32c.c
@@ -40,6 +40,8 @@ void dump_symtab (bfd *, void *, void *);
#endif
static bfd_boolean m32c_elf_relax_section
(bfd *abfd, asection *sec, struct bfd_link_info *link_info, bfd_boolean *again);
+static bfd_reloc_status_type m32c_apply_reloc_24
+ (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
static reloc_howto_type m32c_elf_howto_table [] =
@@ -83,7 +85,7 @@ static reloc_howto_type m32c_elf_howto_table [] =
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ m32c_apply_reloc_24, /* special_function */
"R_M32C_24", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
@@ -307,6 +309,48 @@ m32c_info_to_howto_rela
+/* Apply R_M32C_24 relocations. We have to do this because it's not a
+ power-of-two size, and the generic code may think it overruns the
+ section if it's right at the end.
+
+ Must return something other than bfd_reloc_continue to avoid the
+ above problem. Typical return values include bfd_reloc_ok or
+ bfd_reloc_overflow.
+*/
+
+static bfd_reloc_status_type m32c_apply_reloc_24 (bfd *abfd ATTRIBUTE_UNUSED,
+ arelent *reloc_entry,
+ asymbol *symbol,
+ void *vdata_start ATTRIBUTE_UNUSED,
+ asection *input_section,
+ bfd *ibfd ATTRIBUTE_UNUSED,
+ char **error_msg ATTRIBUTE_UNUSED)
+{
+ bfd_vma relocation;
+ bfd_reloc_status_type s;
+
+ s = bfd_elf_generic_reloc (abfd, reloc_entry, symbol,
+ vdata_start,
+ input_section, ibfd, error_msg);
+ if (s != bfd_reloc_continue)
+ return s;
+
+ /* Get symbol value. (Common symbols are special.) */
+ if (bfd_is_com_section (symbol->section))
+ relocation = 0;
+ else
+ relocation = symbol->value;
+
+ relocation += symbol->section->output_offset;
+
+ /* Add in supplied addend. */
+ relocation += reloc_entry->addend;
+
+ reloc_entry->addend = relocation;
+ reloc_entry->address += input_section->output_offset;
+ return bfd_reloc_ok;
+}
+
/* Relocate an M32C ELF section.
There is some attempt to make this function usable for many architectures,
both USE_REL and USE_RELA ['twould be nice if such a critter existed],
@@ -535,9 +579,32 @@ m32c_elf_relocate_section
printf ("\n");
}
#endif
- r = _bfd_final_link_relocate (howto, input_bfd, input_section,
- contents, rel->r_offset, relocation,
- rel->r_addend);
+ switch (ELF32_R_TYPE(rel->r_info))
+ {
+ case R_M32C_24:
+ /* Like m32c_apply_reloc_24, we must handle this one separately. */
+ relocation += rel->r_addend;
+
+ /* Sanity check the address. */
+ if (rel->r_offset + 3
+ > bfd_get_section_limit_octets (input_bfd, input_section))
+ r = bfd_reloc_outofrange;
+ else
+ {
+ bfd_put_8 (input_bfd, relocation & 0xff, contents + rel->r_offset);
+ bfd_put_8 (input_bfd, (relocation >> 8) & 0xff, contents + rel->r_offset + 1);
+ bfd_put_8 (input_bfd, (relocation >> 16) & 0xff, contents + rel->r_offset + 2);
+ r = bfd_reloc_ok;
+ }
+
+ break;
+
+ default:
+ r = _bfd_final_link_relocate (howto, input_bfd, input_section,
+ contents, rel->r_offset, relocation,
+ rel->r_addend);
+ break;
+ }
if (r != bfd_reloc_ok)
{