summaryrefslogtreecommitdiff
path: root/bfd/elf32-h8300.c
diff options
context:
space:
mode:
authorDJ Delorie <dj@delorie.com>2009-04-07 18:21:22 +0000
committerDJ Delorie <dj@delorie.com>2009-04-07 18:21:22 +0000
commit6bdbea225163134d3540aeb7d258f5754bf0d046 (patch)
treefe9b09908d577f4c476b8618baf2198305904a4d /bfd/elf32-h8300.c
parent48fee23d703b24c199f9cd09a601051e588c1958 (diff)
downloadbinutils-redhat-6bdbea225163134d3540aeb7d258f5754bf0d046.tar.gz
[bfd]
* elf32-h8300.c (elf32_h8_relax_section): Relax MOVA opcodes. [gas] * tc-h8300.c (do_a_fix_imm): Pass the insn, force relocs for MOVA immediates. (build_bytes): Pass insn to do_a_fix_imm. [include/opcode] * h8300.h: Add relaxation attributes to MOVA opcodes.
Diffstat (limited to 'bfd/elf32-h8300.c')
-rw-r--r--bfd/elf32-h8300.c94
1 files changed, 93 insertions, 1 deletions
diff --git a/bfd/elf32-h8300.c b/bfd/elf32-h8300.c
index 888c9adee8..ea54112a11 100644
--- a/bfd/elf32-h8300.c
+++ b/bfd/elf32-h8300.c
@@ -722,6 +722,13 @@ elf32_h8_relax_section (bfd *abfd, asection *sec,
{
bfd_vma symval;
+ {
+ arelent bfd_reloc;
+ reloc_howto_type *h;
+
+ elf32_h8_info_to_howto (abfd, &bfd_reloc, irel);
+ h = bfd_reloc.howto;
+ }
/* Keep track of the previous reloc so that we can delete
some long jumps created by the compiler. */
if (irel != internal_relocs)
@@ -994,7 +1001,8 @@ elf32_h8_relax_section (bfd *abfd, asection *sec,
/* This is bsr. */
bfd_put_8 (abfd, 0x55, contents + irel->r_offset - 2);
else
- abort ();
+ /* Might be MOVSD. */
+ break;
/* Fix the relocation's type. */
irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
@@ -1207,6 +1215,8 @@ elf32_h8_relax_section (bfd *abfd, asection *sec,
if (value <= 0x7fff || value >= 0xffff8000u)
{
unsigned char code;
+ unsigned char op0, op1, op2, op3;
+ unsigned char *op_ptr;
/* Note that we've changed the relocs, section contents,
etc. */
@@ -1214,6 +1224,87 @@ elf32_h8_relax_section (bfd *abfd, asection *sec,
elf_section_data (sec)->this_hdr.contents = contents;
symtab_hdr->contents = (unsigned char *) isymbuf;
+ if (irel->r_offset >= 4)
+ {
+ /* Check for 4-byte MOVA relaxation. */
+ int second_reloc = 0;
+
+ op_ptr = contents + irel->r_offset - 4;
+
+ if (last_reloc)
+ {
+ arelent bfd_reloc;
+ reloc_howto_type *h;
+ bfd_vma last_reloc_size;
+
+ elf32_h8_info_to_howto (abfd, &bfd_reloc, last_reloc);
+ h = bfd_reloc.howto;
+ last_reloc_size = 1 << h->size;
+ if (last_reloc->r_offset + last_reloc_size
+ == irel->r_offset)
+ {
+ op_ptr -= last_reloc_size;
+ second_reloc = 1;
+ }
+ }
+ if (irel < irelend)
+ {
+ Elf_Internal_Rela *next_reloc = irel + 1;
+ arelent bfd_reloc;
+ reloc_howto_type *h;
+ bfd_vma next_reloc_size;
+
+ elf32_h8_info_to_howto (abfd, &bfd_reloc, next_reloc);
+ h = bfd_reloc.howto;
+ next_reloc_size = 1 << h->size;
+ if (next_reloc->r_offset + next_reloc_size
+ == irel->r_offset)
+ {
+ op_ptr -= next_reloc_size;
+ second_reloc = 1;
+ }
+ }
+
+ op0 = bfd_get_8 (abfd, op_ptr + 0);
+ op1 = bfd_get_8 (abfd, op_ptr + 1);
+ op2 = bfd_get_8 (abfd, op_ptr + 2);
+ op3 = bfd_get_8 (abfd, op_ptr + 3);
+
+ if (op0 == 0x01
+ && (op1 & 0xdf) == 0x5f
+ && (op2 & 0x40) == 0x40
+ && (op3 & 0x80) == 0x80)
+ {
+ if ((op2 & 0x08) == 0)
+ second_reloc = 1;
+
+ if (second_reloc)
+ {
+ op3 &= ~0x08;
+ bfd_put_8 (abfd, op3, op_ptr + 3);
+ }
+ else
+ {
+ op2 &= ~0x08;
+ bfd_put_8 (abfd, op2, op_ptr + 2);
+ }
+ goto r_h8_dir32a16_common;
+ }
+ }
+
+ /* Now check for short version of MOVA. */
+ op_ptr = contents + irel->r_offset - 2;
+ op0 = bfd_get_8 (abfd, op_ptr + 0);
+ op1 = bfd_get_8 (abfd, op_ptr + 1);
+
+ if (op0 == 0x7a
+ && (op1 & 0x88) == 0x80)
+ {
+ op1 |= 0x08;
+ bfd_put_8 (abfd, op1, op_ptr + 1);
+ goto r_h8_dir32a16_common;
+ }
+
/* Get the opcode. */
code = bfd_get_8 (abfd, contents + irel->r_offset - 1);
@@ -1224,6 +1315,7 @@ elf32_h8_relax_section (bfd *abfd, asection *sec,
bfd_put_8 (abfd, code, contents + irel->r_offset - 1);
+ r_h8_dir32a16_common:
/* Fix the relocation's type. */
irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
R_H8_DIR16);