From 1aa4214141d30f99f941266a3bedbc332d674c04 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Wed, 1 Aug 2018 12:14:22 +0930 Subject: [PATCH] PowerPC64 __tls_get_addr_opt stub .eh_frame fix This patch sets stub_offset in ppc_size_one_stub rather than in ppc_build_one_stub. That allows the plt stub alignment to be done in just ppc_size_one_stub rather than both functions. The patch also corrects the place where the alignment was done, fixing a possible error in .eh_frame data, and tidies some offset calculations. bfd/ * elf64-ppc.c (plt_stub_pad): Delay plt_stub_size call until needed. (ppc_build_one_stub): Don't set stub_offset, instead assert that it is sane. Don't adjust stub_offset for alignment. Adjust size calculation. Use "targ" temp when calculating offsets. (ppc_size_one_stub): Set stub_offset here. Use "targ" temp when calculating offsets. Adjust for alignment before setting tls_get_addr_opt_bctrl. ld/ * testsuite/ld-powerpc/powerpc.exp: Run tlsopt5 with plt alignment. * testsuite/ld-powerpc/tlsopt5.s: Add extra call. * testsuite/ld-powerpc/tlsopt5.wf: Adjust expected output. * testsuite/ld-powerpc/tlsopt5.d: Likewise. --- bfd/ChangeLog | 10 +++ bfd/elf64-ppc.c | 125 ++++++++++++++-------------- ld/ChangeLog | 7 ++ ld/testsuite/ld-powerpc/powerpc.exp | 2 +- ld/testsuite/ld-powerpc/tlsopt5.d | 20 ++++- ld/testsuite/ld-powerpc/tlsopt5.s | 3 + ld/testsuite/ld-powerpc/tlsopt5.wf | 3 +- 7 files changed, 103 insertions(+), 67 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index eea90ae948..aebedbaa23 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,13 @@ +2018-08-01 Alan Modra + + * elf64-ppc.c (plt_stub_pad): Delay plt_stub_size call until needed. + (ppc_build_one_stub): Don't set stub_offset, instead assert that + it is sane. Don't adjust stub_offset for alignment. Adjust size + calculation. Use "targ" temp when calculating offsets. + (ppc_size_one_stub): Set stub_offset here. Use "targ" temp when + calculating offsets. Adjust for alignment before setting + tls_get_addr_opt_bctrl. + 2018-08-01 Alan Modra * po/SRC-POTFILES.in: Regenerate. diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index 5cd3b8dde3..b59a505851 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -10829,7 +10829,7 @@ plt_stub_pad (struct ppc_link_hash_table *htab, bfd_vma plt_off) { int stub_align; - unsigned stub_size = plt_stub_size (htab, stub_entry, plt_off); + unsigned stub_size; bfd_vma stub_off = stub_entry->group->stub_sec->size; if (htab->params->plt_stub_align >= 0) @@ -10841,6 +10841,7 @@ plt_stub_pad (struct ppc_link_hash_table *htab, } stub_align = 1 << -htab->params->plt_stub_align; + stub_size = plt_stub_size (htab, stub_entry, plt_off); if (((stub_off + stub_size - 1) & -stub_align) - (stub_off & -stub_align) > ((stub_size - 1) & -stub_align)) return stub_align - (stub_off & (stub_align - 1)); @@ -11148,7 +11149,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) struct ppc_link_hash_table *htab; bfd_byte *loc; bfd_byte *p; - bfd_vma dest, off; + bfd_vma targ, off; Elf_Internal_Rela *r; asection *plt; @@ -11160,8 +11161,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) if (htab == NULL) return FALSE; - /* Make a note of the offset within the stubs for this entry. */ - stub_entry->stub_offset = stub_entry->group->stub_sec->size; + BFD_ASSERT (stub_entry->stub_offset >= stub_entry->group->stub_sec->size); loc = stub_entry->group->stub_sec->contents + stub_entry->stub_offset; htab->stub_count[stub_entry->stub_type - 1] += 1; @@ -11170,16 +11170,16 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) case ppc_stub_long_branch: case ppc_stub_long_branch_r2off: /* Branches are relative. This is where we are going to. */ - dest = (stub_entry->target_value + targ = (stub_entry->target_value + stub_entry->target_section->output_offset + stub_entry->target_section->output_section->vma); - dest += PPC64_LOCAL_ENTRY_OFFSET (stub_entry->other); - off = dest; + targ += PPC64_LOCAL_ENTRY_OFFSET (stub_entry->other); /* And this is where we are coming from. */ - off -= (stub_entry->stub_offset - + stub_entry->group->stub_sec->output_offset - + stub_entry->group->stub_sec->output_section->vma); + off = (stub_entry->stub_offset + + stub_entry->group->stub_sec->output_offset + + stub_entry->group->stub_sec->output_section->vma); + off = targ - off; p = loc; if (stub_entry->stub_type == ppc_stub_long_branch_r2off) @@ -11226,7 +11226,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) return FALSE; r->r_offset = p - 4 - stub_entry->group->stub_sec->contents; r->r_info = ELF64_R_INFO (0, R_PPC64_REL24); - r->r_addend = dest; + r->r_addend = targ; if (stub_entry->h != NULL) { struct elf_link_hash_entry **hashes; @@ -11278,13 +11278,13 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) return FALSE; } - dest = (stub_entry->target_value + targ = (stub_entry->target_value + stub_entry->target_section->output_offset + stub_entry->target_section->output_section->vma); if (stub_entry->stub_type != ppc_stub_plt_branch_r2off) - dest += PPC64_LOCAL_ENTRY_OFFSET (stub_entry->other); + targ += PPC64_LOCAL_ENTRY_OFFSET (stub_entry->other); - bfd_put_64 (htab->brlt->owner, dest, + bfd_put_64 (htab->brlt->owner, targ, htab->brlt->contents + br_entry->offset); if (br_entry->iter == htab->stub_iteration) @@ -11301,7 +11301,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) + htab->brlt->output_offset + htab->brlt->output_section->vma); rela.r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE); - rela.r_addend = dest; + rela.r_addend = targ; rl = htab->relbrlt->contents; rl += (htab->relbrlt->reloc_count++ @@ -11321,17 +11321,17 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) + htab->brlt->output_offset + htab->brlt->output_section->vma); r->r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE); - r->r_addend = dest; + r->r_addend = targ; } } - dest = (br_entry->offset + targ = (br_entry->offset + htab->brlt->output_offset + htab->brlt->output_section->vma); - off = (dest - - elf_gp (info->output_bfd) - - htab->sec_info[stub_entry->group->link_sec->id].toc_off); + off = (elf_gp (info->output_bfd) + + htab->sec_info[stub_entry->group->link_sec->id].toc_off); + off = targ - off; if (off + 0x80008000 > 0xffffffff || (off & 7) != 0) { @@ -11354,7 +11354,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) if (stub_entry->stub_type == ppc_stub_plt_branch_r2off) r[0].r_offset += 4; r[0].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS); - r[0].r_addend = dest; + r[0].r_addend = targ; if (PPC_HA (off) != 0) { r[0].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_HA); @@ -11439,8 +11439,8 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) } /* Now build the stub. */ - dest = stub_entry->plt_ent->plt.offset & ~1; - if (dest >= (bfd_vma) -2) + targ = stub_entry->plt_ent->plt.offset & ~1; + if (targ >= (bfd_vma) -2) abort (); plt = htab->elf.splt; @@ -11453,12 +11453,11 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) else plt = htab->pltlocal; } + targ += plt->output_offset + plt->output_section->vma; - dest += plt->output_offset + plt->output_section->vma; - - off = (dest - - elf_gp (info->output_bfd) - - htab->sec_info[stub_entry->group->link_sec->id].toc_off); + off = (elf_gp (info->output_bfd) + + htab->sec_info[stub_entry->group->link_sec->id].toc_off); + off = targ - off; if (off + 0x80008000 > 0xffffffff || (off & 7) != 0) { @@ -11473,15 +11472,6 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) return FALSE; } - if (htab->params->plt_stub_align != 0) - { - unsigned pad = plt_stub_pad (htab, stub_entry, off); - - stub_entry->group->stub_sec->size += pad; - stub_entry->stub_offset = stub_entry->group->stub_sec->size; - loc += pad; - } - r = NULL; if (info->emitrelocations) { @@ -11496,7 +11486,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) r[0].r_offset = loc - stub_entry->group->stub_sec->contents; if (bfd_big_endian (info->output_bfd)) r[0].r_offset += 2; - r[0].r_addend = dest; + r[0].r_addend = targ; } if (stub_entry->h != NULL && (stub_entry->h == htab->tls_get_addr_fd @@ -11515,7 +11505,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) return FALSE; } - stub_entry->group->stub_sec->size += p - loc; + stub_entry->group->stub_sec->size = stub_entry->stub_offset + (p - loc); if (htab->params->emit_stub_syms) { @@ -11567,7 +11557,7 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) struct ppc_stub_hash_entry *stub_entry; struct bfd_link_info *info; struct ppc_link_hash_table *htab; - bfd_vma off; + bfd_vma targ, off; int size; /* Massage our args to the form they really have. */ @@ -11578,6 +11568,9 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) if (htab == NULL) return FALSE; + /* Make a note of the offset within the stubs for this entry. */ + stub_entry->stub_offset = stub_entry->group->stub_sec->size; + if (stub_entry->h != NULL && stub_entry->h->save_res && stub_entry->h->elf.root.type == bfd_link_hash_defined @@ -11594,8 +11587,8 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) || stub_entry->stub_type == ppc_stub_plt_call_r2save) { asection *plt; - off = stub_entry->plt_ent->plt.offset & ~(bfd_vma) 1; - if (off >= (bfd_vma) -2) + targ = stub_entry->plt_ent->plt.offset & ~(bfd_vma) 1; + if (targ >= (bfd_vma) -2) abort (); plt = htab->elf.splt; if (!htab->elf.dynamic_sections_created @@ -11607,12 +11600,22 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) else plt = htab->pltlocal; } - off += (plt->output_offset - + plt->output_section->vma - - elf_gp (info->output_bfd) - - htab->sec_info[stub_entry->group->link_sec->id].toc_off); + targ += plt->output_offset + plt->output_section->vma; + + off = (elf_gp (info->output_bfd) + + htab->sec_info[stub_entry->group->link_sec->id].toc_off); + off = targ - off; + + if (htab->params->plt_stub_align != 0) + { + unsigned pad = plt_stub_pad (htab, stub_entry, off); + + stub_entry->group->stub_sec->size += pad; + stub_entry->stub_offset = stub_entry->group->stub_sec->size; + } size = plt_stub_size (htab, stub_entry, off); + if (stub_entry->h != NULL && (stub_entry->h == htab->tls_get_addr_fd || stub_entry->h == htab->tls_get_addr) @@ -11620,10 +11623,8 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) && (ALWAYS_EMIT_R2SAVE || stub_entry->stub_type == ppc_stub_plt_call_r2save)) stub_entry->group->tls_get_addr_opt_bctrl - = stub_entry->group->stub_sec->size + size - 5 * 4; + = stub_entry->stub_offset + size - 5 * 4; - if (htab->params->plt_stub_align) - size += plt_stub_pad (htab, stub_entry, off); if (info->emitrelocations) { stub_entry->group->stub_sec->reloc_count @@ -11642,12 +11643,12 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) bfd_vma r2off = 0; bfd_vma local_off = 0; - off = (stub_entry->target_value - + stub_entry->target_section->output_offset - + stub_entry->target_section->output_section->vma); - off -= (stub_entry->group->stub_sec->size - + stub_entry->group->stub_sec->output_offset - + stub_entry->group->stub_sec->output_section->vma); + targ = (stub_entry->target_value + + stub_entry->target_section->output_offset + + stub_entry->target_section->output_section->vma); + off = (stub_entry->stub_offset + + stub_entry->group->stub_sec->output_offset + + stub_entry->group->stub_sec->output_section->vma); /* Reset the stub type from the plt variant in case we now can reach with a shorter stub. */ @@ -11668,8 +11669,9 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) size += 4; if (PPC_LO (r2off) != 0) size += 4; - off -= size - 4; + off += size - 4; } + off = targ - off; local_off = PPC64_LOCAL_ENTRY_OFFSET (stub_entry->other); @@ -11709,11 +11711,12 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) } stub_entry->stub_type += ppc_stub_plt_branch - ppc_stub_long_branch; - off = (br_entry->offset - + htab->brlt->output_offset - + htab->brlt->output_section->vma - - elf_gp (info->output_bfd) - - htab->sec_info[stub_entry->group->link_sec->id].toc_off); + targ = (br_entry->offset + + htab->brlt->output_offset + + htab->brlt->output_section->vma); + off = (elf_gp (info->output_bfd) + + htab->sec_info[stub_entry->group->link_sec->id].toc_off); + off = targ - off; if (info->emitrelocations) { diff --git a/ld/ChangeLog b/ld/ChangeLog index 36b4bb7d14..73e57b30d0 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,10 @@ +2018-08-01 Alan Modra + + * testsuite/ld-powerpc/powerpc.exp: Run tlsopt5 with plt alignment. + * testsuite/ld-powerpc/tlsopt5.s: Add extra call. + * testsuite/ld-powerpc/tlsopt5.wf: Adjust expected output. + * testsuite/ld-powerpc/tlsopt5.d: Likewise. + 2018-08-01 Alan Modra * po/BLD-POTFILES.in: Regenerate. diff --git a/ld/testsuite/ld-powerpc/powerpc.exp b/ld/testsuite/ld-powerpc/powerpc.exp index cfeb277f04..ed7bc74cf4 100644 --- a/ld/testsuite/ld-powerpc/powerpc.exp +++ b/ld/testsuite/ld-powerpc/powerpc.exp @@ -224,7 +224,7 @@ set ppc64elftests { "tlsopt4"} {"TLS DLL" "-shared -melf64ppc --version-script tlsdll.ver" "" "-a64" {tlsdll.s} {} "tlsdll.so"} - {"TLS opt 5" "-melf64ppc --no-plt-align -shared --gc-sections --no-plt-localentry tmpdir/tlsdll.so" "" "-a64" {tlsopt5.s} + {"TLS opt 5" "-melf64ppc -shared --gc-sections --no-plt-localentry tmpdir/tlsdll.so" "" "-a64" {tlsopt5.s} {{objdump -dr tlsopt5.d} {readelf -wf tlsopt5.wf}} "tlsopt5"} {"sym@tocbase" "-shared -melf64ppc" "" "-a64" {symtocbase-1.s symtocbase-2.s} diff --git a/ld/testsuite/ld-powerpc/tlsopt5.d b/ld/testsuite/ld-powerpc/tlsopt5.d index 4521a9b427..4caf1832ea 100644 --- a/ld/testsuite/ld-powerpc/tlsopt5.d +++ b/ld/testsuite/ld-powerpc/tlsopt5.d @@ -8,6 +8,13 @@ Disassembly of section \.text: +.* <.*\.plt_call\.foo>: +.*: (18 00 41 f8|f8 41 00 18) std r2,24\(r1\) +.*: (28 80 82 e9|e9 82 80 28) ld r12,-32728\(r2\) +.*: (a6 03 89 7d|7d 89 03 a6) mtctr r12 +.*: (20 04 80 4e|4e 80 04 20) bctr + \.\.\. + .* <.*\.plt_call\.__tls_get_addr_opt@@GLIBC_2\.22>: .*: (00 00 63 e9|e9 63 00 00) ld r11,0\(r3\) .*: (08 00 83 e9|e9 83 00 08) ld r12,8\(r3\) @@ -19,17 +26,21 @@ Disassembly of section \.text: .*: (a6 02 68 7d|7d 68 02 a6) mflr r11 .*: (08 00 61 f9|f9 61 00 08) std r11,8\(r1\) .*: (18 00 41 f8|f8 41 00 18) std r2,24\(r1\) -.*: (28 80 82 e9|e9 82 80 28) ld r12,-32728\(r2\) +.*: (30 80 82 e9|e9 82 80 30) ld r12,-32720\(r2\) .*: (a6 03 89 7d|7d 89 03 a6) mtctr r12 .*: (21 04 80 4e|4e 80 04 21) bctrl .*: (18 00 41 e8|e8 41 00 18) ld r2,24\(r1\) .*: (08 00 61 e9|e9 61 00 08) ld r11,8\(r1\) .*: (a6 03 68 7d|7d 68 03 a6) mtlr r11 .*: (20 00 80 4e|4e 80 00 20) blr + \.\.\. .* <_start>: .*: (08 80 62 38|38 62 80 08) addi r3,r2,-32760 -.*: (b9 ff ff 4b|4b ff ff b9) bl .* +.*: (9d ff ff 4b|4b ff ff 9d) bl .* <.*\.plt_call\.__tls_get_addr_opt@@GLIBC_2\.22> +.*: (00 00 00 60|60 00 00 00) nop +.*: (75 ff ff 4b|4b ff ff 75) bl .* <.*\.plt_call\.foo> +.*: (18 00 41 e8|e8 41 00 18) ld r2,24\(r1\) .*: (00 00 00 60|60 00 00 00) nop .* .* @@ -50,5 +61,8 @@ Disassembly of section \.text: .*: (08 00 6b e9|e9 6b 00 08) ld r11,8\(r11\) .*: (20 04 80 4e|4e 80 04 20) bctr +.* : +.* (c8 ff ff 4b|4b ff ff c8) b .* + .* <__tls_get_addr_opt@plt>: -.*: (c8 ff ff 4b|4b ff ff c8) b .* +.*: (c4 ff ff 4b|4b ff ff c4) b .* diff --git a/ld/testsuite/ld-powerpc/tlsopt5.s b/ld/testsuite/ld-powerpc/tlsopt5.s index 70902ef96a..7cb82db1f6 100644 --- a/ld/testsuite/ld-powerpc/tlsopt5.s +++ b/ld/testsuite/ld-powerpc/tlsopt5.s @@ -1,7 +1,10 @@ .globl _start + .weak foo _start: .cfi_startproc addi 3,2,gd@got@tlsgd bl __tls_get_addr(gd@tlsgd) nop + bl foo + nop .cfi_endproc diff --git a/ld/testsuite/ld-powerpc/tlsopt5.wf b/ld/testsuite/ld-powerpc/tlsopt5.wf index af8cb76d1c..f0453610e0 100644 --- a/ld/testsuite/ld-powerpc/tlsopt5.wf +++ b/ld/testsuite/ld-powerpc/tlsopt5.wf @@ -7,11 +7,10 @@ Contents of the \.eh_frame section: Data alignment factor: -8 Return address column: 65 Augmentation data: 1b - DW_CFA_def_cfa: r1 ofs 0 0+14 0+14 0+18 FDE cie=0+ pc=.* - DW_CFA_advance_loc: 48 to .* + DW_CFA_advance_loc: 80 to .* DW_CFA_offset_extended_sf: r65 at cfa\+8 DW_CFA_advance_loc: 16 to .* DW_CFA_restore_extended: r65 -- 2.34.1