From 397998fc32a34d3c8993ef46da45c3957a4dd402 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Tue, 3 Jun 2014 10:55:29 +0930 Subject: 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. --- gdb/ppc64-tdep.c | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) (limited to 'gdb/ppc64-tdep.c') diff --git a/gdb/ppc64-tdep.c b/gdb/ppc64-tdep.c index cbbbedc..8acd754 100644 --- a/gdb/ppc64-tdep.c +++ b/gdb/ppc64-tdep.c @@ -303,6 +303,29 @@ static struct ppc_insn_pattern ppc64_standard_linkage7[] = { 0, 0, 0 } }; +/* ELFv2 PLT call stub to access PLT entries more than +/- 32k from r2, + supporting fusion. */ + +static struct ppc_insn_pattern ppc64_standard_linkage8[] = + { + /* std r2, 24(r1) */ + { -1, insn_ds (62, 2, 1, 24, 0), 1 }, + + /* addis r12, r2, */ + { insn_d (-1, -1, -1, 0), insn_d (15, 12, 2, 0), 0 }, + + /* ld r12, (r12) */ + { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 12, 12, 0, 0), 0 }, + + /* mtctr r12 */ + { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 12, 9, 467), 0 }, + + /* bctr */ + { -1, 0x4e800420, 0 }, + + { 0, 0, 0 } + }; + /* When the dynamic linker is doing lazy symbol resolution, the first call to a function in another object will go like this: @@ -437,10 +460,14 @@ ppc64_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc) ARRAY_SIZE (ppc64_standard_linkage4))), MAX (MAX (ARRAY_SIZE (ppc64_standard_linkage5), ARRAY_SIZE (ppc64_standard_linkage6)), - ARRAY_SIZE (ppc64_standard_linkage7))) - 1]; + MAX (ARRAY_SIZE (ppc64_standard_linkage7), + ARRAY_SIZE (ppc64_standard_linkage8)))) + - 1]; CORE_ADDR target; - if (ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage7, insns)) + if (ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage8, insns)) + pc = ppc64_standard_linkage4_target (frame, pc, insns); + else if (ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage7, insns)) pc = ppc64_standard_linkage3_target (frame, pc, insns); else if (ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage6, insns)) pc = ppc64_standard_linkage4_target (frame, pc, insns); -- cgit v1.1