summaryrefslogtreecommitdiff
path: root/bfd/elf32-iq2000.c
diff options
context:
space:
mode:
authorDJ Delorie <dj@delorie.com>2008-02-12 19:11:55 +0000
committerDJ Delorie <dj@delorie.com>2008-02-12 19:11:55 +0000
commit8127815f75c893996f9ba626ee90511bb282d59f (patch)
treeb7b16a0be695a255c9b90c41a0cff234f18689db /bfd/elf32-iq2000.c
parent056206d202637d03a27f7629d39fdee6f42965ee (diff)
downloadbinutils-redhat-8127815f75c893996f9ba626ee90511bb282d59f.tar.gz
* elf32-iq2000.c (iq2000_elf_relocate_section): Adjust addend of
relocation pointing to local symbol in merged section. * elf32-iq2000.c (iq2000_elf_relocate_offset16): New. (iq2000_elf_relocate_section): Call it.
Diffstat (limited to 'bfd/elf32-iq2000.c')
-rw-r--r--bfd/elf32-iq2000.c49
1 files changed, 47 insertions, 2 deletions
diff --git a/bfd/elf32-iq2000.c b/bfd/elf32-iq2000.c
index 2a5ad780d4..73ab8e9832 100644
--- a/bfd/elf32-iq2000.c
+++ b/bfd/elf32-iq2000.c
@@ -306,6 +306,34 @@ iq2000_elf_relocate_hi16 (bfd *input_bfd,
return bfd_reloc_ok;
}
+static bfd_reloc_status_type
+iq2000_elf_relocate_offset16 (bfd *input_bfd,
+ Elf_Internal_Rela *rel,
+ bfd_byte *contents,
+ bfd_vma value,
+ bfd_vma location)
+{
+ bfd_vma insn;
+ bfd_vma jtarget;
+
+ insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+
+ value += rel->r_addend;
+
+ if (value & 3)
+ return bfd_reloc_dangerous;
+
+ jtarget = (value & 0x3fffc) | (location & 0xf0000000L);
+
+ if (jtarget != value)
+ return bfd_reloc_overflow;
+
+ insn = (insn & ~0xFFFF) | ((value >> 2) & 0xFFFF);
+
+ bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+ return bfd_reloc_ok;
+}
+
/* Map BFD reloc types to IQ2000 ELF reloc types. */
static reloc_howto_type *
@@ -572,15 +600,25 @@ iq2000_elf_relocate_section (bfd * output_bfd ATTRIBUTE_UNUSED,
if (r_symndx < symtab_hdr->sh_info)
{
+ asection *osec;
+
sym = local_syms + r_symndx;
- sec = local_sections [r_symndx];
+ osec = sec = local_sections [r_symndx];
+ if ((sec->flags & SEC_MERGE)
+ && ELF_ST_TYPE (sym->st_info) == STT_SECTION)
+ /* This relocation is relative to a section symbol that is
+ going to be merged. Change it so that it is relative
+ to the merged section symbol. */
+ rel->r_addend = _bfd_elf_rel_local_sym (output_bfd, sym, &sec,
+ rel->r_addend);
+
relocation = (sec->output_section->vma
+ sec->output_offset
+ sym->st_value);
name = bfd_elf_string_from_elf_section
(input_bfd, symtab_hdr->sh_link, sym->st_name);
- name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
+ name = (name == NULL) ? bfd_section_name (input_bfd, osec) : name;
}
else
{
@@ -615,6 +653,13 @@ iq2000_elf_relocate_section (bfd * output_bfd ATTRIBUTE_UNUSED,
r = iq2000_elf_relocate_hi16 (input_bfd, rel, contents, relocation);
break;
+ case R_IQ2000_OFFSET_16:
+ r = iq2000_elf_relocate_offset16 (input_bfd, rel, contents, relocation,
+ input_section->output_section->vma
+ + input_section->output_offset
+ + rel->r_offset);
+ break;
+
case R_IQ2000_PC16:
rel->r_addend -= 4;
/* Fall through. */