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.
This commit is contained in:
Alan Modra
2014-06-03 10:55:29 +09:30
parent 61f5c66f62
commit 397998fc32
8 changed files with 85 additions and 18 deletions

View File

@@ -3077,6 +3077,7 @@ static const uint32_t addis_3_13 = 0x3c6d0000;
static const uint32_t addis_11_2 = 0x3d620000;
static const uint32_t addis_11_11 = 0x3d6b0000;
static const uint32_t addis_11_30 = 0x3d7e0000;
static const uint32_t addis_12_2 = 0x3d820000;
static const uint32_t addis_12_12 = 0x3d8c0000;
static const uint32_t b = 0x48000000;
static const uint32_t bcl_20_31 = 0x429f0005;
@@ -4210,10 +4211,20 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
{
write_insn<big_endian>(p, std_2_1 + this->targ_->stk_toc());
p += 4;
write_insn<big_endian>(p, addis_11_2 + ha(off));
p += 4;
write_insn<big_endian>(p, ld_12_11 + l(off));
p += 4;
if (plt_load_toc)
{
write_insn<big_endian>(p, addis_11_2 + ha(off));
p += 4;
write_insn<big_endian>(p, ld_12_11 + l(off));
p += 4;
}
else
{
write_insn<big_endian>(p, addis_12_2 + ha(off));
p += 4;
write_insn<big_endian>(p, ld_12_12 + l(off));
p += 4;
}
if (plt_load_toc
&& ha(off + 8 + 8 * static_chain) != ha(off))
{
@@ -4312,8 +4323,8 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
}
else
{
write_insn<big_endian>(p, addis_11_2 + ha(brltoff)), p += 4;
write_insn<big_endian>(p, ld_12_11 + l(brltoff)), p += 4;
write_insn<big_endian>(p, addis_12_2 + ha(brltoff)), p += 4;
write_insn<big_endian>(p, ld_12_12 + l(brltoff)), p += 4;
}
write_insn<big_endian>(p, mtctr_12), p += 4;
write_insn<big_endian>(p, bctr);