Handle R_M32C_24 specially
authorDJ Delorie <dj@redhat.com>
Thu, 22 Jan 2015 22:30:58 +0000 (17:30 -0500)
committerDJ Delorie <dj@redhat.com>
Thu, 22 Jan 2015 22:30:58 +0000 (17:30 -0500)
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.

bfd/ChangeLog
bfd/elf32-m32c.c

index bd2f0c1c7ebe956f309adef0dce2c132461ecf2b..e3a428aa929ea831d318a63ecaf40b09a08bca06 100644 (file)
@@ -1,3 +1,9 @@
+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.
+
 2015-01-22  Nick Clifton  <nickc@redhat.com>
 
        PR binutils/17512
index cbc17659e85a345528c0e22cd5c3d0494fabd705..75725811599b05d6c24277ca420b8228caa03a47 100644 (file)
@@ -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
 
 \f
 
+/* 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)
        {