aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaciej W. Rozycki <macro@linux-mips.org>2011-08-02 14:28:26 +0000
committerMaciej W. Rozycki <macro@linux-mips.org>2011-08-02 14:28:26 +0000
commit80cab405aaf31dbed01d0a97547e61b8e9b0321d (patch)
treeb7b781b429da58770c9cd1f171bf9d3bb6705502
parentc7131b65cee44f94038e75666282b77f01402958 (diff)
downloadfsf-binutils-gdb-80cab405aaf31dbed01d0a97547e61b8e9b0321d.zip
fsf-binutils-gdb-80cab405aaf31dbed01d0a97547e61b8e9b0321d.tar.gz
fsf-binutils-gdb-80cab405aaf31dbed01d0a97547e61b8e9b0321d.tar.bz2
* elfxx-mips.c (check_4byte_branch): Remove function.
(check_relocated_bzc): New function. (_bfd_mips_elf_relax_section): Permit the relaxation of LUI instructions that immediately follow a compact branch instruction.
-rw-r--r--bfd/ChangeLog8
-rw-r--r--bfd/elfxx-mips.c59
2 files changed, 41 insertions, 26 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 1c6d0a0..9d25437 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,11 @@
+2011-08-02 Maciej W. Rozycki <macro@codesourcery.com>
+
+ * elfxx-mips.c (check_4byte_branch): Remove function.
+ (check_relocated_bzc): New function.
+ (_bfd_mips_elf_relax_section): Permit the relaxation of LUI
+ instructions that immediately follow a compact branch
+ instruction.
+
2011-08-02 Alan Modra <amodra@gmail.com>
* elf64-ppc.c (build_plt_stub): Correct emitted relocs when no
diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c
index c628b8b..4d80fe8 100644
--- a/bfd/elfxx-mips.c
+++ b/bfd/elfxx-mips.c
@@ -12264,32 +12264,37 @@ check_br32 (bfd *abfd, bfd_byte *ptr, unsigned long reg)
return FALSE;
}
-/* Bitsize checking. */
-#define IS_BITSIZE(val, N) \
- (((((val) & ((1ULL << (N)) - 1)) ^ (1ULL << ((N) - 1))) \
- - (1ULL << ((N) - 1))) == (val))
-
-/* See if relocations [INTERNAL_RELOCS, IRELEND) confirm that there
- is a 4-byte branch at offset OFFSET. */
+/* If the instruction encoding at PTR and relocations [INTERNAL_RELOCS,
+ IRELEND) at OFFSET indicate that there must be a compact branch there,
+ then return TRUE, otherwise FALSE. */
static bfd_boolean
-check_4byte_branch (Elf_Internal_Rela *internal_relocs,
- Elf_Internal_Rela *irelend, bfd_vma offset)
+check_relocated_bzc (bfd *abfd, const bfd_byte *ptr, bfd_vma offset,
+ const Elf_Internal_Rela *internal_relocs,
+ const Elf_Internal_Rela *irelend)
{
- Elf_Internal_Rela *irel;
- unsigned long r_type;
+ const Elf_Internal_Rela *irel;
+ unsigned long opcode;
+
+ opcode = bfd_get_16 (abfd, ptr);
+ opcode <<= 16;
+ opcode |= bfd_get_16 (abfd, ptr + 2);
+ if (find_match (opcode, bzc_insns_32) < 0)
+ return FALSE;
for (irel = internal_relocs; irel < irelend; irel++)
- if (irel->r_offset == offset)
- {
- r_type = ELF32_R_TYPE (irel->r_info);
- if (r_type == R_MICROMIPS_26_S1
- || r_type == R_MICROMIPS_PC16_S1
- || r_type == R_MICROMIPS_JALR)
- return TRUE;
- }
+ if (irel->r_offset == offset
+ && ELF32_R_TYPE (irel->r_info) == R_MICROMIPS_PC16_S1)
+ return TRUE;
+
return FALSE;
}
+
+/* Bitsize checking. */
+#define IS_BITSIZE(val, N) \
+ (((((val) & ((1ULL << (N)) - 1)) ^ (1ULL << ((N) - 1))) \
+ - (1ULL << ((N) - 1))) == (val))
+
bfd_boolean
_bfd_mips_elf_relax_section (bfd *abfd, asection *sec,
@@ -12451,6 +12456,7 @@ _bfd_mips_elf_relax_section (bfd *abfd, asection *sec,
out the offset). */
if (r_type == R_MICROMIPS_HI16 && MATCH (opcode, lui_insn))
{
+ bfd_boolean bzc = FALSE;
unsigned long nextopc;
unsigned long reg;
bfd_vma offset;
@@ -12474,18 +12480,19 @@ _bfd_mips_elf_relax_section (bfd *abfd, asection *sec,
&& ELF32_R_SYM (irel[2].r_info) == r_symndx)
continue;
- /* See if the LUI instruction *might* be in a branch delay slot. */
+ /* See if the LUI instruction *might* be in a branch delay slot.
+ We check whether what looks like a 16-bit branch or jump is
+ actually an immediate argument to a compact branch, and let
+ it through if so. */
if (irel->r_offset >= 2
&& check_br16_dslot (abfd, ptr - 2)
&& !(irel->r_offset >= 4
- /* If the instruction is actually a 4-byte branch,
- the value of check_br16_dslot doesn't matter.
- We should use check_br32_dslot to check whether
- the branch has a delay slot. */
- && check_4byte_branch (internal_relocs, irelend,
- irel->r_offset - 4)))
+ && (bzc = check_relocated_bzc (abfd,
+ ptr - 4, irel->r_offset - 4,
+ internal_relocs, irelend))))
continue;
if (irel->r_offset >= 4
+ && !bzc
&& check_br32_dslot (abfd, ptr - 4))
continue;