summaryrefslogtreecommitdiff
path: root/bfd/elf32-microblaze.c
diff options
context:
space:
mode:
authorMichael Eager <eager@eagercon.com>2012-11-09 16:24:57 +0000
committerMichael Eager <eager@eagercon.com>2012-11-09 16:24:57 +0000
commiteb7b10e71f9569f0b90e0c6c128121ecf14c2e8e (patch)
tree3f89f0fcd615df13203b71ae20eb32bfb6bbcd7d /bfd/elf32-microblaze.c
parent24e99800519974483cd7bb69e6875bf67da9d7af (diff)
downloadbinutils-redhat-eb7b10e71f9569f0b90e0c6c128121ecf14c2e8e.tar.gz
Add microblazeel target support to bfd, gas and ld.
binutils/bfd/Changelog 2012-11-09 Edgar E. Iglesias <edgar.iglesias@gmail.com> * config.bfd: Add microblazeel-*-* * configure.in: Likewise. * configure: Regenerate. * elf32-microblaze.c (microblaze_elf_relocate_section): Add endian awareness. (microblaze_elf_merge_private_bfd_data): New. (microblaze_bfd_write_imm_value_32): New. (microblaze_bfd_write_imm_value_64): New. (microblaze_elf_relax_section): Add endian awareness. (microblaze_elf_add_symbol_hook): Define TARGET_LITTLE_NAME, TARGET_LITTLE_SYM and bfd_elf32_bfd_merge_private_bfd_data. * targets.c: Add bfd target bfd_elf32_microblazeel_vec. binutils/gas/Changelog 2012-11-09 Edgar E. Iglesias <edgar.iglesias@gmail.com> * tc-microblaze.c (md_longopts): Define OPTION_EB and OPTION_EL for target. (md_parse_option): Likewise. * tc-microblaze.h: Set elf32-microblazeel if not target_big_endian for TARGET_FORMAT. * configure.tgt: Add microblazeel and set endian per target. binutils/gas/testsuite/Changelog 2012-11-09 David Holsgrove <david.holsgrove@xilinx.com> * gas/microblaze/endian.exp: New file - endian testcase for microblaze / microblazeel. * gas/microblaze/endian.s: Likewise. * gas/microblaze/endian_be.d: Likewise. * gas/microblaze/endian_le.d: Likewise. * gas/microblaze/endian_le_elf.d: Likewise. * gas/microblaze/reloc_sym.d: Update to accept targets other than elf32-microblaze. * gas/microblaze/special_reg.d: Likewise. binutils/ld/Changelog 2012-11-09 Edgar E. Iglesias <edgar.iglesias@gmail.com> * Makefile.am: Add eelf32microblazeel.c and eelf32mbel_linux.c. * Makefile.in: Regenerated. * configure.tgt: Add microblazeel and set endian per target. * emulparams/elf32mb_linux.sh: Add OUTPUT_FORMAT. * emulparams/elf32microblaze.sh: Likewise. * emulparams/elf32mbel_linux.sh: New file. * emulparams/elf32microblazeel.sh: Likewise.
Diffstat (limited to 'bfd/elf32-microblaze.c')
-rw-r--r--bfd/elf32-microblaze.c134
1 files changed, 92 insertions, 42 deletions
diff --git a/bfd/elf32-microblaze.c b/bfd/elf32-microblaze.c
index c0004248a2..be2de13425 100644
--- a/bfd/elf32-microblaze.c
+++ b/bfd/elf32-microblaze.c
@@ -702,6 +702,7 @@ microblaze_elf_relocate_section (bfd *output_bfd,
Elf_Internal_Shdr *symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (input_bfd);
Elf_Internal_Rela *rel, *relend;
+ int endian = (bfd_little_endian (output_bfd)) ? 0 : 2;
/* Assume success. */
bfd_boolean ret = TRUE;
asection *sreloc;
@@ -933,9 +934,9 @@ microblaze_elf_relocate_section (bfd *output_bfd,
+ offset + INST_WORD_SIZE);
relocation += addend;
bfd_put_16 (input_bfd, (relocation >> 16) & 0xffff,
- contents + offset + 2);
+ contents + offset + endian);
bfd_put_16 (input_bfd, relocation & 0xffff,
- contents + offset + 2 + INST_WORD_SIZE);
+ contents + offset + endian + INST_WORD_SIZE);
break;
case (int) R_MICROBLAZE_PLT_64:
@@ -952,9 +953,9 @@ microblaze_elf_relocate_section (bfd *output_bfd,
+ input_section->output_offset
+ offset + INST_WORD_SIZE);
bfd_put_16 (input_bfd, (immediate >> 16) & 0xffff,
- contents + offset + 2);
+ contents + offset + endian);
bfd_put_16 (input_bfd, immediate & 0xffff,
- contents + offset + 2 + INST_WORD_SIZE);
+ contents + offset + endian + INST_WORD_SIZE);
}
else
{
@@ -963,9 +964,9 @@ microblaze_elf_relocate_section (bfd *output_bfd,
+ offset + INST_WORD_SIZE);
immediate = relocation;
bfd_put_16 (input_bfd, (immediate >> 16) & 0xffff,
- contents + offset + 2);
+ contents + offset + endian);
bfd_put_16 (input_bfd, immediate & 0xffff,
- contents + offset + 2 + INST_WORD_SIZE);
+ contents + offset + endian + INST_WORD_SIZE);
}
break;
}
@@ -1031,9 +1032,9 @@ microblaze_elf_relocate_section (bfd *output_bfd,
abort (); /* ??? */
}
bfd_put_16 (input_bfd, (relocation >> 16) & 0xffff,
- contents + offset + 2);
+ contents + offset + endian);
bfd_put_16 (input_bfd, relocation & 0xffff,
- contents + offset + 2 + INST_WORD_SIZE);
+ contents + offset + endian + INST_WORD_SIZE);
break;
}
@@ -1048,8 +1049,8 @@ microblaze_elf_relocate_section (bfd *output_bfd,
immediate = relocation;
lo = immediate & 0x0000ffff;
high = (immediate >> 16) & 0x0000ffff;
- bfd_put_16 (input_bfd, high, contents + offset + 2);
- bfd_put_16 (input_bfd, lo, contents + offset + INST_WORD_SIZE + 2);
+ bfd_put_16 (input_bfd, high, contents + offset + endian);
+ bfd_put_16 (input_bfd, lo, contents + offset + INST_WORD_SIZE + endian);
break;
}
@@ -1082,9 +1083,9 @@ microblaze_elf_relocate_section (bfd *output_bfd,
+ input_section->output_offset
+ offset + INST_WORD_SIZE);
bfd_put_16 (input_bfd, (relocation >> 16) & 0xffff,
- contents + offset + 2);
+ contents + offset + endian);
bfd_put_16 (input_bfd, relocation & 0xffff,
- contents + offset + 2 + INST_WORD_SIZE);
+ contents + offset + endian + INST_WORD_SIZE);
}
break;
}
@@ -1176,9 +1177,9 @@ microblaze_elf_relocate_section (bfd *output_bfd,
+ input_section->output_offset
+ offset + INST_WORD_SIZE);
bfd_put_16 (input_bfd, (relocation >> 16) & 0xffff,
- contents + offset + 2);
+ contents + offset + endian);
bfd_put_16 (input_bfd, relocation & 0xffff,
- contents + offset + 2 + INST_WORD_SIZE);
+ contents + offset + endian + INST_WORD_SIZE);
}
break;
}
@@ -1253,6 +1254,21 @@ microblaze_elf_relocate_section (bfd *output_bfd,
return ret;
}
+
+/* Merge backend specific data from an object file to the output
+ object file when linking.
+
+ Note: We only use this hook to catch endian mismatches. */
+static bfd_boolean
+microblaze_elf_merge_private_bfd_data (bfd * ibfd, bfd * obfd)
+{
+ /* Check if we have the same endianess. */
+ if (! _bfd_generic_verify_endian_match (ibfd, obfd))
+ return FALSE;
+
+ return TRUE;
+}
+
/* Calculate fixup value for reference. */
@@ -1275,6 +1291,36 @@ calc_fixup (bfd_vma addr, asection *sec)
return fixup;
}
+/* Read-modify-write into the bfd, an immediate value into appropriate fields of
+ a 32-bit instruction. */
+static void
+microblaze_bfd_write_imm_value_32 (bfd *abfd, bfd_byte *bfd_addr, bfd_vma val)
+{
+ unsigned long instr = bfd_get_32 (abfd, bfd_addr);
+ instr &= ~0x0000ffff;
+ instr |= (val & 0x0000ffff);
+ bfd_put_32 (abfd, instr, bfd_addr);
+}
+
+/* Read-modify-write into the bfd, an immediate value into appropriate fields of
+ two consecutive 32-bit instructions. */
+static void
+microblaze_bfd_write_imm_value_64 (bfd *abfd, bfd_byte *bfd_addr, bfd_vma val)
+{
+ unsigned long instr_hi;
+ unsigned long instr_lo;
+
+ instr_hi = bfd_get_32 (abfd, bfd_addr);
+ instr_hi &= ~0x0000ffff;
+ instr_hi |= ((val >> 16) & 0x0000ffff);
+ bfd_put_32 (abfd, instr_hi, bfd_addr);
+
+ instr_lo = bfd_get_32 (abfd, bfd_addr + INST_WORD_SIZE);
+ instr_lo &= ~0x0000ffff;
+ instr_lo |= (val & 0x0000ffff);
+ bfd_put_32 (abfd, instr_lo, bfd_addr + INST_WORD_SIZE);
+}
+
static bfd_boolean
microblaze_elf_relax_section (bfd *abfd,
asection *sec,
@@ -1305,7 +1351,8 @@ microblaze_elf_relax_section (bfd *abfd,
/* Only do this for a text section. */
if (link_info->relocatable
|| (sec->flags & SEC_RELOC) == 0
- || (sec->reloc_count == 0))
+ || (sec->reloc_count == 0)
+ || (sec->flags & SEC_CODE) == 0)
return TRUE;
BFD_ASSERT ((sec->size > 0) || (sec->rawsize > 0));
@@ -1485,7 +1532,8 @@ microblaze_elf_relax_section (bfd *abfd,
efix = calc_fixup (target_address, sec);
irel->r_addend -= (efix - sfix);
/* Should use HOWTO. */
- bfd_put_16 (abfd, irel->r_addend, contents + irel->r_offset + 2);
+ microblaze_bfd_write_imm_value_32 (abfd, contents + irel->r_offset,
+ irel->r_addend);
}
break;
case R_MICROBLAZE_64_NONE:
@@ -1498,8 +1546,8 @@ microblaze_elf_relax_section (bfd *abfd,
sfix = calc_fixup (irel->r_offset + INST_WORD_SIZE, sec);
efix = calc_fixup (target_address, sec);
irel->r_addend -= (efix - sfix);
- bfd_put_16 (abfd, irel->r_addend, contents + irel->r_offset
- + INST_WORD_SIZE + 2);
+ microblaze_bfd_write_imm_value_32 (abfd, contents + irel->r_offset
+ + INST_WORD_SIZE, irel->r_addend);
}
break;
}
@@ -1627,13 +1675,14 @@ microblaze_elf_relax_section (bfd *abfd,
}
}
- immediate = (unsigned short) bfd_get_16 (abfd, ocontents +
- irelscan->r_offset + 2);
+ unsigned long instr = bfd_get_32 (abfd, ocontents + irelscan->r_offset);
+ immediate = instr & 0x0000ffff;
target_address = immediate;
offset = calc_fixup (target_address, sec);
immediate -= offset;
irelscan->r_addend -= offset;
- bfd_put_16 (abfd, immediate, ocontents + irelscan->r_offset + 2);
+ microblaze_bfd_write_imm_value_32 (abfd, ocontents + irelscan->r_offset,
+ irelscan->r_addend);
}
}
@@ -1669,15 +1718,13 @@ microblaze_elf_relax_section (bfd *abfd,
elf_section_data (o)->this_hdr.contents = ocontents;
}
}
- immediate = (unsigned short) (bfd_get_16 (abfd, ocontents
- + irelscan->r_offset
- + 2) << 16)
- & 0xffff0000;
- immediate += (unsigned short) (bfd_get_16 (abfd, ocontents
- + irelscan->r_offset
- + INST_WORD_SIZE + 2))
- & 0x0000ffff;
-
+ unsigned long instr_hi = bfd_get_32 (abfd, ocontents
+ + irelscan->r_offset);
+ unsigned long instr_lo = bfd_get_32 (abfd, ocontents
+ + irelscan->r_offset
+ + INST_WORD_SIZE);
+ immediate = (instr_hi & 0x0000ffff) << 16;
+ immediate |= (instr_lo & 0x0000ffff);
offset = calc_fixup (irelscan->r_addend, sec);
immediate -= offset;
irelscan->r_addend -= offset;
@@ -1715,22 +1762,19 @@ microblaze_elf_relax_section (bfd *abfd,
elf_section_data (o)->this_hdr.contents = ocontents;
}
}
-
- immediate = (unsigned short)
- (bfd_get_16 (abfd, ocontents + irelscan->r_offset + 2) << 16)
- & 0xffff0000;
- immediate += (unsigned short)
- (bfd_get_16 (abfd, ocontents + irelscan->r_offset
- + INST_WORD_SIZE + 2))
- & 0x0000ffff;
+ unsigned long instr_hi = bfd_get_32 (abfd, ocontents
+ + irelscan->r_offset);
+ unsigned long instr_lo = bfd_get_32 (abfd, ocontents
+ + irelscan->r_offset
+ + INST_WORD_SIZE);
+ immediate = (instr_hi & 0x0000ffff) << 16;
+ immediate |= (instr_lo & 0x0000ffff);
target_address = immediate;
offset = calc_fixup (target_address, sec);
immediate -= offset;
irelscan->r_addend -= offset;
- bfd_put_16 (abfd, ((immediate >> 16) & 0x0000ffff),
- ocontents + irelscan->r_offset + 2);
- bfd_put_16 (abfd, (immediate & 0x0000ffff),
- ocontents + irelscan->r_offset + INST_WORD_SIZE + 2);
+ microblaze_bfd_write_imm_value_64 (abfd, ocontents
+ + irelscan->r_offset, immediate);
}
}
}
@@ -1800,9 +1844,12 @@ microblaze_elf_relax_section (bfd *abfd,
if (sec->relax_count == 0)
{
+ *again = FALSE;
free (sec->relax);
sec->relax = NULL;
}
+ else
+ *again = TRUE;
return TRUE;
error_return:
@@ -3016,6 +3063,8 @@ microblaze_elf_add_symbol_hook (bfd *abfd,
return TRUE;
}
+#define TARGET_LITTLE_SYM bfd_elf32_microblazeel_vec
+#define TARGET_LITTLE_NAME "elf32-microblazeel"
#define TARGET_BIG_SYM bfd_elf32_microblaze_vec
#define TARGET_BIG_NAME "elf32-microblaze"
@@ -3032,6 +3081,7 @@ microblaze_elf_add_symbol_hook (bfd *abfd,
#define bfd_elf32_bfd_is_local_label_name microblaze_elf_is_local_label_name
#define elf_backend_relocate_section microblaze_elf_relocate_section
#define bfd_elf32_bfd_relax_section microblaze_elf_relax_section
+#define bfd_elf32_bfd_merge_private_bfd_data microblaze_elf_merge_private_bfd_data
#define bfd_elf32_bfd_reloc_name_lookup microblaze_elf_reloc_name_lookup
#define elf_backend_gc_mark_hook microblaze_elf_gc_mark_hook