* elf32-d10v.c (extract_rel_addend, insert_rel_addend): New functions.
authorAlan Modra <amodra@gmail.com>
Wed, 5 Nov 2003 01:23:55 +0000 (01:23 +0000)
committerAlan Modra <amodra@gmail.com>
Wed, 5 Nov 2003 01:23:55 +0000 (01:23 +0000)
(elf32_d10v_relocate_section): Use them to handle -r reloc
adjustments, and in place of _bfd_elf_rela_local_sym.

bfd/ChangeLog
bfd/elf32-d10v.c

index 691427beb0248af566b6309d70ca7ea5fa311d24..7968601fcaae9d86855f3ca53c278cb5f6fcd411 100644 (file)
@@ -1,5 +1,9 @@
 2003-11-05  Alan Modra  <amodra@bigpond.net.au>
 
+       * elf32-d10v.c (extract_rel_addend, insert_rel_addend): New functions.
+       (elf32_d10v_relocate_section): Use them to handle -r reloc
+       adjustments, and in place of _bfd_elf_rela_local_sym.
+
        * cpu-iq2000.c (arch_info_struct): Warning fix.
 
 2003-11-05  Alan Modra  <amodra@bigpond.net.au>
index cc5eddce7fdcc128201263eb5cc6cfe8891a73cf..f9454ffe9f32e8ea32928a792fe5028d8f20e276 100644 (file)
@@ -38,6 +38,10 @@ static bfd_boolean elf32_d10v_gc_sweep_hook
 static bfd_boolean elf32_d10v_check_relocs
   PARAMS ((bfd *, struct bfd_link_info *, asection *,
           const Elf_Internal_Rela *));
+static bfd_vma extract_rel_addend
+  PARAMS ((bfd *, bfd_byte *, reloc_howto_type *));
+static void insert_rel_addend
+  PARAMS ((bfd *, bfd_byte *, reloc_howto_type *, bfd_vma));
 static bfd_boolean elf32_d10v_relocate_section
   PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *,
           bfd_byte *, Elf_Internal_Rela *, Elf_Internal_Sym *,
@@ -346,6 +350,75 @@ elf32_d10v_check_relocs (abfd, info, sec, relocs)
   return TRUE;
 }
 
+static bfd_vma
+extract_rel_addend (abfd, where, howto)
+     bfd *abfd;
+     bfd_byte *where;
+     reloc_howto_type *howto;
+{
+  bfd_vma insn, val;
+
+  switch (howto->size)
+    {
+    case 0:
+      insn = bfd_get_8 (abfd, where);
+      break;
+    case 1:
+      insn = bfd_get_16 (abfd, where);
+      break;
+    case 2:
+      insn = bfd_get_32 (abfd, where);
+      break;
+    default:
+      abort ();
+    }
+
+  val = (insn & howto->dst_mask) >> howto->bitpos << howto->rightshift;
+  /* We should really be testing for signed addends here, but we don't
+     have that info directly in the howto.  */
+  if (howto->pc_relative)
+    {
+      bfd_vma sign;
+      sign = howto->dst_mask & (~howto->dst_mask >> 1 | ~(-(bfd_vma) 1 >> 1));
+      sign = sign >> howto->bitpos << howto->rightshift;
+      val = (val ^ sign) - sign;
+    }
+  return val;
+}
+
+static void
+insert_rel_addend (abfd, where, howto, addend)
+     bfd *abfd;
+     bfd_byte *where;
+     reloc_howto_type *howto;
+     bfd_vma addend;
+{
+  bfd_vma insn;
+
+  addend = (addend >> howto->rightshift << howto->bitpos) & howto->dst_mask;
+  insn = ~howto->dst_mask;
+  switch (howto->size)
+    {
+    case 0:
+      insn &= bfd_get_8 (abfd, where);
+      insn |= addend;
+      bfd_put_8 (abfd, insn, where);
+      break;
+    case 1:
+      insn &= bfd_get_16 (abfd, where);
+      insn |= addend;
+      bfd_put_16 (abfd, insn, where);
+      break;
+    case 2:
+      insn &= bfd_get_32 (abfd, where);
+      insn |= addend;
+      bfd_put_32 (abfd, insn, where);
+      break;
+    default:
+      abort ();
+    }
+}
+
 /* Relocate a D10V ELF section.  */
 static bfd_boolean
 elf32_d10v_relocate_section (output_bfd, info, input_bfd, input_section,
@@ -391,20 +464,28 @@ elf32_d10v_relocate_section (output_bfd, info, input_bfd, input_section,
 
       if (info->relocatable)
        {
+         bfd_vma val;
+         bfd_byte *where;
+
          /* This is a relocatable link.  We don't have to change
             anything, unless the reloc is against a section symbol,
             in which case we have to adjust according to where the
             section symbol winds up in the output section.  */
-         if (r_symndx < symtab_hdr->sh_info)
-           {
-             sym = local_syms + r_symndx;
-             if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
-               {
-                 sec = local_sections[r_symndx];
-                 rel->r_addend += sec->output_offset + sym->st_value;
-               }
-           }
+         if (r_symndx >= symtab_hdr->sh_info)
+           continue;
 
+         sym = local_syms + r_symndx;
+         if (ELF_ST_TYPE (sym->st_info) != STT_SECTION)
+           continue;
+
+         sec = local_sections[r_symndx];
+         val = sec->output_offset;
+         if (val == 0)
+           continue;
+
+         where = contents + rel->r_offset;
+         val += extract_rel_addend (input_bfd, where, howto);
+         insert_rel_addend (input_bfd, where, howto, val);
          continue;
        }
 
@@ -416,7 +497,23 @@ elf32_d10v_relocate_section (output_bfd, info, input_bfd, input_section,
        {
          sym = local_syms + r_symndx;
          sec = local_sections[r_symndx];
-         relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel);
+         relocation = (sec->output_section->vma
+                       + sec->output_offset
+                       + sym->st_value);
+         if ((sec->flags & SEC_MERGE)
+             && ELF_ST_TYPE (sym->st_info) == STT_SECTION)
+           {
+             asection *msec;
+             bfd_vma addend;
+             bfd_byte *where = contents + rel->r_offset;
+
+             addend = extract_rel_addend (input_bfd, where, howto);
+             msec = sec;
+             addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend);
+             addend -= relocation;
+             addend += msec->output_section->vma + msec->output_offset;
+             insert_rel_addend (input_bfd, where, howto, addend);
+           }
        }
       else
        {
@@ -456,7 +553,7 @@ elf32_d10v_relocate_section (output_bfd, info, input_bfd, input_section,
 
       r = _bfd_final_link_relocate (howto, input_bfd, input_section,
                                     contents, rel->r_offset,
-                                    relocation, rel->r_addend);
+                                    relocation, (bfd_vma) 0);
 
       if (r != bfd_reloc_ok)
        {