aboutsummaryrefslogtreecommitdiff
path: root/bfd
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2014-06-03 10:55:29 +0930
committerAlan Modra <amodra@gmail.com>2014-06-03 10:55:29 +0930
commit397998fc32a34d3c8993ef46da45c3957a4dd402 (patch)
tree2dba3305c8567097b13505879d970299d2b9ad08 /bfd
parent61f5c66f62502f33e1f2441a043bd29bb3ad6ea5 (diff)
downloadbinutils-397998fc32a34d3c8993ef46da45c3957a4dd402.zip
binutils-397998fc32a34d3c8993ef46da45c3957a4dd402.tar.gz
binutils-397998fc32a34d3c8993ef46da45c3957a4dd402.tar.bz2
Support fusion for ELFv2 stubs
Power8 fuses addis,addi and addis,ld sequences when the target of the addis is the same as the addi/ld. Thus addis r12,r2,xxx@ha addi r12,r12,xxx@l / ld r12,xxx@l(r12) is faster than addis r11,r2,xxx@ha addi r12,r11,xxx@l / ld r12,xxx@l(r11) So use the form that allows fusion in plt call and branch stubs. bfd/ * elf64-ppc.c (ADDIS_R12_R2): Define. (build_plt_stub): Support fusion on ELFv2 stub. (ppc_build_one_stub): Likewise for plt branch stubs. gold/ * powerpc.cc (addis_12_2): Define. (Stub_table::do_write): Support fusion on ELFv2 stubs. ld/testsuite/ * ld-powerpc/elfv2exe.d: Update for changed plt call stubs. gdb/ * ppc64-tdep.c (ppc64_standard_linkage8): New. (ppc64_skip_trampoline_code): Recognise ELFv2 stub supporting fusion.
Diffstat (limited to 'bfd')
-rw-r--r--bfd/ChangeLog6
-rw-r--r--bfd/elf64-ppc.c21
2 files changed, 21 insertions, 6 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 8c93f39..396b7ab 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,9 @@
+2014-06-03 Alan Modra <amodra@gmail.com>
+
+ * elf64-ppc.c (ADDIS_R12_R2): Define.
+ (build_plt_stub): Support fusion on ELFv2 stub.
+ (ppc_build_one_stub): Likewise for plt branch stubs.
+
2014-05-28 Alan Modra <amodra@gmail.com>
* elf32-rx.c (rx_table_map): Delete set but not used variables.
diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
index fdca0c6..e7e2e39 100644
--- a/bfd/elf64-ppc.c
+++ b/bfd/elf64-ppc.c
@@ -173,6 +173,7 @@ static bfd_vma opd_entry_value
#define LD_R2_0R1 0xe8410000 /* ld %r2,0(%r1) */
+#define ADDIS_R12_R2 0x3d820000 /* addis %r12,%r2,xxx@ha */
#define ADDIS_R12_R12 0x3d8c0000 /* addis %r12,%r12,xxx@ha */
#define LD_R12_0R12 0xe98c0000 /* ld %r12,xxx@l(%r12) */
@@ -10246,8 +10247,16 @@ build_plt_stub (struct ppc_link_hash_table *htab,
if (ALWAYS_EMIT_R2SAVE
|| stub_entry->stub_type == ppc_stub_plt_call_r2save)
bfd_put_32 (obfd, STD_R2_0R1 + STK_TOC (htab), p), p += 4;
- bfd_put_32 (obfd, ADDIS_R11_R2 | PPC_HA (offset), p), p += 4;
- bfd_put_32 (obfd, LD_R12_0R11 | PPC_LO (offset), p), p += 4;
+ if (plt_load_toc)
+ {
+ bfd_put_32 (obfd, ADDIS_R11_R2 | PPC_HA (offset), p), p += 4;
+ bfd_put_32 (obfd, LD_R12_0R11 | PPC_LO (offset), p), p += 4;
+ }
+ else
+ {
+ bfd_put_32 (obfd, ADDIS_R12_R2 | PPC_HA (offset), p), p += 4;
+ bfd_put_32 (obfd, LD_R12_0R12 | PPC_LO (offset), p), p += 4;
+ }
if (plt_load_toc
&& PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset))
{
@@ -10668,10 +10677,10 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
{
size = 16;
bfd_put_32 (htab->params->stub_bfd,
- ADDIS_R11_R2 | PPC_HA (off), loc);
+ ADDIS_R12_R2 | PPC_HA (off), loc);
loc += 4;
bfd_put_32 (htab->params->stub_bfd,
- LD_R12_0R11 | PPC_LO (off), loc);
+ LD_R12_0R12 | PPC_LO (off), loc);
}
else
{
@@ -10697,10 +10706,10 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
{
size += 4;
bfd_put_32 (htab->params->stub_bfd,
- ADDIS_R11_R2 | PPC_HA (off), loc);
+ ADDIS_R12_R2 | PPC_HA (off), loc);
loc += 4;
bfd_put_32 (htab->params->stub_bfd,
- LD_R12_0R11 | PPC_LO (off), loc);
+ LD_R12_0R12 | PPC_LO (off), loc);
}
else
bfd_put_32 (htab->params->stub_bfd, LD_R12_0R2 | PPC_LO (off), loc);