aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Henderson <rth@redhat.com>2001-09-09 20:42:11 +0000
committerRichard Henderson <rth@redhat.com>2001-09-09 20:42:11 +0000
commit1cd6895c5500ca8bdab8720e856fd4eba11589f0 (patch)
treebabbd0acb90f34a193237d0748f3be7c82e94d47
parent79bcdb567f930dd4e76f1353df489c31d1ec4283 (diff)
downloadfsf-binutils-gdb-1cd6895c5500ca8bdab8720e856fd4eba11589f0.zip
fsf-binutils-gdb-1cd6895c5500ca8bdab8720e856fd4eba11589f0.tar.gz
fsf-binutils-gdb-1cd6895c5500ca8bdab8720e856fd4eba11589f0.tar.bz2
* elf64-alpha.c (elf64_alpha_relax_with_lituse): Nop out gpdisp
following a call to a near function.
-rw-r--r--bfd/ChangeLog5
-rw-r--r--bfd/elf64-alpha.c38
2 files changed, 35 insertions, 8 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index c17ff62..78f3649 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,8 @@
+2001-09-09 Richard Henderson <rth@redhat.com>
+
+ * elf64-alpha.c (elf64_alpha_relax_with_lituse): Nop out gpdisp
+ following a call to a near function.
+
2001-09-08 Richard Henderson <rth@redhat.com>
* elf64-alpha.c (elf64_alpha_relocate_section): Soft fail
diff --git a/bfd/elf64-alpha.c b/bfd/elf64-alpha.c
index 9e22023..df0650b 100644
--- a/bfd/elf64-alpha.c
+++ b/bfd/elf64-alpha.c
@@ -1149,14 +1149,36 @@ elf64_alpha_relax_with_lituse (info, symval, irel, irelend)
else
all_optimized = false;
- /* ??? If target gp == current gp we can eliminate the gp reload.
- This does depend on every place a gp could be reloaded will
- be, which currently happens for all code produced by gcc, but
- not necessarily by hand-coded assembly, or if sibling calls
- are enabled in gcc.
-
- Perhaps conditionalize this on a flag being set in the target
- object file's header, and have gcc set it? */
+ /* Even if the target is not in range for a direct branch,
+ if we share a GP, we can eliminate the gp reload. */
+ if (optdest)
+ {
+ Elf_Internal_Rela *gpdisp
+ = (elf64_alpha_find_reloc_at_ofs
+ (irel, irelend, urel->r_offset + 4, R_ALPHA_GPDISP));
+ if (gpdisp)
+ {
+ bfd_byte *p_ldah = info->contents + gpdisp->r_offset;
+ bfd_byte *p_lda = p_ldah + gpdisp->r_addend;
+ unsigned int ldah = bfd_get_32 (info->abfd, p_ldah);
+ unsigned int lda = bfd_get_32 (info->abfd, p_lda);
+
+ /* Verify that the instruction is "ldah $29,0($26)".
+ Consider a function that ends in a noreturn call,
+ and that the next function begins with an ldgp,
+ and that by accident there is no padding between.
+ In that case the insn would use $27 as the base. */
+ if (ldah == 0x27ba0000 && lda == 0x23bd0000)
+ {
+ bfd_put_32 (info->abfd, INSN_UNOP, p_ldah);
+ bfd_put_32 (info->abfd, INSN_UNOP, p_lda);
+
+ gpdisp->r_info = ELF64_R_INFO (0, R_ALPHA_NONE);
+ info->changed_contents = true;
+ info->changed_relocs = true;
+ }
+ }
+ }
}
break;
}