From a804e4760a9f05aeb61071f8caad3579e6a197a2 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Wed, 22 Jan 2020 12:24:56 +1030 Subject: [PATCH] PowerPC64 tls_get_addr_desc static support This provides a linker generated __tls_get_addr_desc wrapper function preserving registers around a __tls_get_addr call. The idea being to support __tls_get_addr_desc without requiring a glibc update. bfd/ * elf64-ppc.c (struct ppc_link_hash_table): Add tga_group. (ppc64_elf_archive_symbol_lookup): Extract __tls_get_addr_opt for __tls_get_addr_desc. (ppc64_elf_size_stubs): Add section for linker generated __tls_get_addr_desc wrapper function. Loop at least once if generating this function. (emit_tga_desc, emit_tga_desc_eh_frame): New functions. (ppc64_elf_build_stubs): Generate __tls_get_addr_desc. ld/ * testsuite/ld-powerpc/tlsdesc3.d, * testsuite/ld-powerpc/tlsdesc3.wf, * testsuite/ld-powerpc/tlsdesc4.d, * testsuite/ld-powerpc/tlsdesc4.s, * testsuite/ld-powerpc/tlsdesc4.wf: New tests. * testsuite/ld-powerpc/powerpc.exp: Run them. --- bfd/ChangeLog | 11 +++ bfd/elf64-ppc.c | 138 +++++++++++++++++++++++++++- ld/ChangeLog | 9 ++ ld/testsuite/ld-powerpc/powerpc.exp | 6 ++ ld/testsuite/ld-powerpc/tlsdesc3.d | 38 ++++++++ ld/testsuite/ld-powerpc/tlsdesc3.wf | 43 +++++++++ ld/testsuite/ld-powerpc/tlsdesc4.d | 46 ++++++++++ ld/testsuite/ld-powerpc/tlsdesc4.s | 18 ++++ ld/testsuite/ld-powerpc/tlsdesc4.wf | 49 ++++++++++ 9 files changed, 357 insertions(+), 1 deletion(-) create mode 100644 ld/testsuite/ld-powerpc/tlsdesc3.d create mode 100644 ld/testsuite/ld-powerpc/tlsdesc3.wf create mode 100644 ld/testsuite/ld-powerpc/tlsdesc4.d create mode 100644 ld/testsuite/ld-powerpc/tlsdesc4.s create mode 100644 ld/testsuite/ld-powerpc/tlsdesc4.wf diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 1bd9b5f979a..f20b2c0dac8 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,14 @@ +2020-01-22 Alan Modra + + * elf64-ppc.c (struct ppc_link_hash_table): Add tga_group. + (ppc64_elf_archive_symbol_lookup): Extract __tls_get_addr_opt for + __tls_get_addr_desc. + (ppc64_elf_size_stubs): Add section for linker generated + __tls_get_addr_desc wrapper function. Loop at least once if + generating this function. + (emit_tga_desc, emit_tga_desc_eh_frame): New functions. + (ppc64_elf_build_stubs): Generate __tls_get_addr_desc. + 2020-01-22 Alan Modra * elf64-ppc.h (struct ppc64_elf_params): Add no_tls_get_addr_regsave. diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index 6b11a11018d..b3f8f6b359e 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -3182,6 +3182,7 @@ struct ppc_link_hash_table struct ppc_link_hash_entry *tls_get_addr_fd; struct ppc_link_hash_entry *tga_desc; struct ppc_link_hash_entry *tga_desc_fd; + struct map_stub *tga_group; /* The size of reliplt used by got entry relocs. */ bfd_size_type got_reli_size; @@ -4150,6 +4151,11 @@ ppc64_elf_archive_symbol_lookup (bfd *abfd, memcpy (dot_name + 1, name, len + 1); h = _bfd_elf_archive_symbol_lookup (abfd, info, dot_name); bfd_release (abfd, dot_name); + if (h != NULL) + return h; + + if (strcmp (name, "__tls_get_addr_opt") == 0) + h = _bfd_elf_archive_symbol_lookup (abfd, info, "__tls_get_addr_desc"); return h; } @@ -13088,6 +13094,40 @@ ppc64_elf_size_stubs (struct bfd_link_info *info) if (!group_sections (info, stub_group_size, stubs_always_before_branch)) return FALSE; + htab->tga_group = NULL; + if (!htab->params->no_tls_get_addr_regsave + && htab->tga_desc_fd != NULL + && (htab->tga_desc_fd->elf.root.type == bfd_link_hash_undefined + || htab->tga_desc_fd->elf.root.type == bfd_link_hash_undefweak) + && htab->tls_get_addr_fd != NULL + && is_static_defined (&htab->tls_get_addr_fd->elf)) + { + asection *sym_sec, *code_sec, *stub_sec; + bfd_vma sym_value; + struct _opd_sec_data *opd; + + sym_sec = htab->tls_get_addr_fd->elf.root.u.def.section; + sym_value = defined_sym_val (&htab->tls_get_addr_fd->elf); + code_sec = sym_sec; + opd = get_opd_info (sym_sec); + if (opd != NULL) + opd_entry_value (sym_sec, sym_value, &code_sec, NULL, FALSE); + htab->tga_group = htab->sec_info[code_sec->id].u.group; + stub_sec = (*htab->params->add_stub_section) (".tga_desc.stub", + htab->tga_group->link_sec); + if (stub_sec == NULL) + return FALSE; + htab->tga_group->stub_sec = stub_sec; + + htab->tga_desc_fd->elf.root.type = bfd_link_hash_defined; + htab->tga_desc_fd->elf.root.u.def.section = stub_sec; + htab->tga_desc_fd->elf.root.u.def.value = 0; + htab->tga_desc_fd->elf.type = STT_FUNC; + htab->tga_desc_fd->elf.def_regular = 1; + htab->tga_desc_fd->elf.non_elf = 0; + _bfd_elf_link_hash_hide_symbol (info, &htab->tga_desc_fd->elf, TRUE); + } + #define STUB_SHRINK_ITER 20 /* Loop until no stubs added. After iteration 20 of this loop we may exit on a stub section shrinking. This is to break out of a @@ -13517,6 +13557,14 @@ ppc64_elf_size_stubs (struct bfd_link_info *info) stub_sec->flags &= ~SEC_RELOC; } } + if (htab->tga_group != NULL) + { + /* See emit_tga_desc and emit_tga_desc_eh_frame. */ + htab->tga_group->eh_size + = 1 + 2 + (htab->opd_abi != 0) + 3 + 8 * 2 + 3 + 8 + 3; + htab->tga_group->lr_restore = 23 * 4; + htab->tga_group->stub_sec->size = 24 * 4; + } if (htab->stub_iteration <= STUB_SHRINK_ITER || htab->brlt->rawsize < htab->brlt->size) @@ -13580,7 +13628,9 @@ ppc64_elf_size_stubs (struct bfd_link_info *info) || (htab->stub_iteration > STUB_SHRINK_ITER && htab->brlt->rawsize > htab->brlt->size)) && (htab->glink_eh_frame == NULL - || htab->glink_eh_frame->rawsize == htab->glink_eh_frame->size)) + || htab->glink_eh_frame->rawsize == htab->glink_eh_frame->size) + && (htab->tga_group == NULL + || htab->stub_iteration > 1)) break; /* Ask the linker to do its stuff. */ @@ -14086,6 +14136,74 @@ write_plt_relocs_for_local_syms (struct bfd_link_info *info) return TRUE; } +/* Emit the static wrapper function preserving registers around a + __tls_get_addr_opt call. */ + +static bfd_boolean +emit_tga_desc (struct ppc_link_hash_table *htab) +{ + asection *stub_sec = htab->tga_group->stub_sec; + unsigned int cfa_updt = 11 * 4; + bfd_byte *p; + bfd_vma to, from, delta; + + BFD_ASSERT (htab->tga_desc_fd->elf.root.type == bfd_link_hash_defined + && htab->tga_desc_fd->elf.root.u.def.section == stub_sec + && htab->tga_desc_fd->elf.root.u.def.value == 0); + to = defined_sym_val (&htab->tls_get_addr_fd->elf); + from = defined_sym_val (&htab->tga_desc_fd->elf) + cfa_updt; + delta = to - from; + if (delta + (1 << 25) >= 1 << 26) + { + _bfd_error_handler (_("__tls_get_addr call offset overflow")); + htab->stub_error = TRUE; + return FALSE; + } + + p = stub_sec->contents; + p = tls_get_addr_prologue (htab->elf.dynobj, p, htab); + bfd_put_32 (stub_sec->owner, B_DOT | 1 | (delta & 0x3fffffc), p); + p += 4; + p = tls_get_addr_epilogue (htab->elf.dynobj, p, htab); + return stub_sec->size == (bfd_size_type) (p - stub_sec->contents); +} + +/* Emit eh_frame describing the static wrapper function. */ + +static bfd_byte * +emit_tga_desc_eh_frame (struct ppc_link_hash_table *htab, bfd_byte *p) +{ + unsigned int cfa_updt = 11 * 4; + unsigned int i; + + *p++ = DW_CFA_advance_loc + cfa_updt / 4; + *p++ = DW_CFA_def_cfa_offset; + if (htab->opd_abi) + { + *p++ = 128; + *p++ = 1; + } + else + *p++ = 96; + *p++ = DW_CFA_offset_extended_sf; + *p++ = 65; + *p++ = (-16 / 8) & 0x7f; + for (i = 4; i < 12; i++) + { + *p++ = DW_CFA_offset + i; + *p++ = (htab->opd_abi ? 13 : 12) - i; + } + *p++ = DW_CFA_advance_loc + 10; + *p++ = DW_CFA_def_cfa_offset; + *p++ = 0; + for (i = 4; i < 12; i++) + *p++ = DW_CFA_restore + i; + *p++ = DW_CFA_advance_loc + 2; + *p++ = DW_CFA_restore_extended; + *p++ = 65; + return p; +} + /* Build all the stubs associated with the current output file. The stubs are kept in a hash table attached to the main linker hash table. This function is called via gldelf64ppc_finish. */ @@ -14245,6 +14363,24 @@ ppc64_elf_build_stubs (struct bfd_link_info *info, } } + if (htab->tga_group != NULL) + { + htab->tga_group->lr_restore = 23 * 4; + htab->tga_group->stub_sec->size = 24 * 4; + if (!emit_tga_desc (htab)) + return FALSE; + if (htab->glink_eh_frame != NULL + && htab->glink_eh_frame->size != 0) + { + size_t align = 4; + + p = htab->glink_eh_frame->contents; + p += (sizeof (glink_eh_frame_cie) + align - 1) & -align; + p += 17; + htab->tga_group->eh_size = emit_tga_desc_eh_frame (htab, p) - p; + } + } + /* Build .glink global entry stubs, and PLT relocs for globals. */ elf_link_hash_traverse (&htab->elf, build_global_entry_stubs_and_plt, info); diff --git a/ld/ChangeLog b/ld/ChangeLog index edfc0903921..b196d2167f1 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,12 @@ +2020-01-22 Alan Modra + + * testsuite/ld-powerpc/tlsdesc3.d, + * testsuite/ld-powerpc/tlsdesc3.wf, + * testsuite/ld-powerpc/tlsdesc4.d, + * testsuite/ld-powerpc/tlsdesc4.s, + * testsuite/ld-powerpc/tlsdesc4.wf: New tests. + * testsuite/ld-powerpc/powerpc.exp: Run them. + 2020-01-22 Alan Modra * emultempl/ppc64elf.em (ppc64_opt, PARSE_AND_LIST_LONGOPTS), diff --git a/ld/testsuite/ld-powerpc/powerpc.exp b/ld/testsuite/ld-powerpc/powerpc.exp index d50846c806a..94b2fac6fbe 100644 --- a/ld/testsuite/ld-powerpc/powerpc.exp +++ b/ld/testsuite/ld-powerpc/powerpc.exp @@ -280,6 +280,12 @@ set ppc64elftests { {"TLSdesc2" "-melf64ppc -shared --hash-style=both --no-plt-localentry tmpdir/tlsdll.so" "" "-a64" {tlsdesc.s} {{objdump -dr tlsdesc2.d} {readelf -wf tlsdesc2.wf}} "tlsdesc2"} + {"TLSdesc3" "-melf64ppc --no-tls-optimize tmpdir/tlsdll.o" "" "-a64" {tlsdesc.s} + {{objdump -dr tlsdesc3.d} {readelf -wf tlsdesc3.wf}} + "tlsdesc3"} + {"TLSdesc4" "-melf64ppc --no-tls-optimize tmpdir/tlsdll.o" "" "-a64" {tlsdesc4.s} + {{objdump -dr tlsdesc4.d} {readelf -wf tlsdesc4.wf}} + "tlsdesc4"} {"sym@tocbase" "-shared -melf64ppc" "" "-a64" {symtocbase-1.s symtocbase-2.s} {{objdump -dj.data symtocbase.d}} "symtocbase.so"} {"TOC opt" "-melf64ppc" "" "-a64" {tocopt.s} diff --git a/ld/testsuite/ld-powerpc/tlsdesc3.d b/ld/testsuite/ld-powerpc/tlsdesc3.d new file mode 100644 index 00000000000..360dcff37cb --- /dev/null +++ b/ld/testsuite/ld-powerpc/tlsdesc3.d @@ -0,0 +1,38 @@ + +.*: file format .* + +Disassembly of section \.text: + +0+10000100 <__tls_get_addr_desc>: +.*: (7c 08 02 a6|a6 02 08 7c) mflr r0 +.*: (f8 01 00 10|10 00 01 f8) std r0,16\(r1\) +.*: (f8 81 ff c0|c0 ff 81 f8) std r4,-64\(r1\) +.*: (f8 a1 ff c8|c8 ff a1 f8) std r5,-56\(r1\) +.*: (f8 c1 ff d0|d0 ff c1 f8) std r6,-48\(r1\) +.*: (f8 e1 ff d8|d8 ff e1 f8) std r7,-40\(r1\) +.*: (f9 01 ff e0|e0 ff 01 f9) std r8,-32\(r1\) +.*: (f9 21 ff e8|e8 ff 21 f9) std r9,-24\(r1\) +.*: (f9 41 ff f0|f0 ff 41 f9) std r10,-16\(r1\) +.*: (f9 61 ff f8|f8 ff 61 f9) std r11,-8\(r1\) +.*: (f8 21 ff a1|a1 ff 21 f8) stdu r1,-96\(r1\) +.*: (48 00 00 35|35 00 00 48) bl .* <__tls_get_addr> +.*: (e8 81 00 20|20 00 81 e8) ld r4,32\(r1\) +.*: (e8 a1 00 28|28 00 a1 e8) ld r5,40\(r1\) +.*: (e8 c1 00 30|30 00 c1 e8) ld r6,48\(r1\) +.*: (e8 e1 00 38|38 00 e1 e8) ld r7,56\(r1\) +.*: (e9 01 00 40|40 00 01 e9) ld r8,64\(r1\) +.*: (e9 21 00 48|48 00 21 e9) ld r9,72\(r1\) +.*: (e9 41 00 50|50 00 41 e9) ld r10,80\(r1\) +.*: (e9 61 00 58|58 00 61 e9) ld r11,88\(r1\) +.*: (38 21 00 60|60 00 21 38) addi r1,r1,96 +.*: (e8 01 00 10|10 00 01 e8) ld r0,16\(r1\) +.*: (7c 08 03 a6|a6 03 08 7c) mtlr r0 +.*: (4e 80 00 20|20 00 80 4e) blr + +0+10000160 <__tls_get_addr>: +.*: (4e 80 00 20|20 00 80 4e) blr + +0+10000164 <_start>: +.*: (38 62 80 08|08 80 62 38) addi r3,r2,-32760 +.*: (4b ff ff 99|99 ff ff 4b) bl .* <__tls_get_addr_desc> +.*: (60 00 00 00|00 00 00 60) nop diff --git a/ld/testsuite/ld-powerpc/tlsdesc3.wf b/ld/testsuite/ld-powerpc/tlsdesc3.wf new file mode 100644 index 00000000000..af5a6b494cd --- /dev/null +++ b/ld/testsuite/ld-powerpc/tlsdesc3.wf @@ -0,0 +1,43 @@ +Contents of the \.eh_frame section: + +0+ 0+10 0+ CIE + Version: 1 + Augmentation: "zR" + Code alignment factor: 4 + Data alignment factor: -8 + Return address column: 65 + Augmentation data: 1b + DW_CFA_def_cfa: r1 ofs 0 + +0+14 0+34 0+18 FDE cie=0+ pc=0+10000100\.\.0+10000160 + DW_CFA_advance_loc: 44 to 0+1000012c + DW_CFA_def_cfa_offset: 96 + DW_CFA_offset_extended_sf: r65 at cfa\+16 + DW_CFA_offset: r4 at cfa-64 + DW_CFA_offset: r5 at cfa-56 + DW_CFA_offset: r6 at cfa-48 + DW_CFA_offset: r7 at cfa-40 + DW_CFA_offset: r8 at cfa-32 + DW_CFA_offset: r9 at cfa-24 + DW_CFA_offset: r10 at cfa-16 + DW_CFA_offset: r11 at cfa-8 + DW_CFA_advance_loc: 40 to 0+10000154 + DW_CFA_def_cfa_offset: 0 + DW_CFA_restore: r4 + DW_CFA_restore: r5 + DW_CFA_restore: r6 + DW_CFA_restore: r7 + DW_CFA_restore: r8 + DW_CFA_restore: r9 + DW_CFA_restore: r10 + DW_CFA_restore: r11 + DW_CFA_advance_loc: 8 to 0+1000015c + DW_CFA_restore_extended: r65 + DW_CFA_nop + DW_CFA_nop + DW_CFA_nop + +0+4c 0+10 0+50 FDE cie=0+ pc=0+10000164\.\.0+10000170 + DW_CFA_nop + DW_CFA_nop + DW_CFA_nop diff --git a/ld/testsuite/ld-powerpc/tlsdesc4.d b/ld/testsuite/ld-powerpc/tlsdesc4.d new file mode 100644 index 00000000000..eb162bb7848 --- /dev/null +++ b/ld/testsuite/ld-powerpc/tlsdesc4.d @@ -0,0 +1,46 @@ + +.*: file format .* + +Disassembly of section \.text: + +0+10000100 <__tls_get_addr_desc>: +.*: (7c 08 02 a6|a6 02 08 7c) mflr r0 +.*: (f8 01 00 10|10 00 01 f8) std r0,16\(r1\) +.*: (f8 81 ff c0|c0 ff 81 f8) std r4,-64\(r1\) +.*: (f8 a1 ff c8|c8 ff a1 f8) std r5,-56\(r1\) +.*: (f8 c1 ff d0|d0 ff c1 f8) std r6,-48\(r1\) +.*: (f8 e1 ff d8|d8 ff e1 f8) std r7,-40\(r1\) +.*: (f9 01 ff e0|e0 ff 01 f9) std r8,-32\(r1\) +.*: (f9 21 ff e8|e8 ff 21 f9) std r9,-24\(r1\) +.*: (f9 41 ff f0|f0 ff 41 f9) std r10,-16\(r1\) +.*: (f9 61 ff f8|f8 ff 61 f9) std r11,-8\(r1\) +.*: (f8 21 ff a1|a1 ff 21 f8) stdu r1,-96\(r1\) +.*: (48 00 00 35|35 00 00 48) bl .* <__tls_get_addr> +.*: (e8 81 00 20|20 00 81 e8) ld r4,32\(r1\) +.*: (e8 a1 00 28|28 00 a1 e8) ld r5,40\(r1\) +.*: (e8 c1 00 30|30 00 c1 e8) ld r6,48\(r1\) +.*: (e8 e1 00 38|38 00 e1 e8) ld r7,56\(r1\) +.*: (e9 01 00 40|40 00 01 e9) ld r8,64\(r1\) +.*: (e9 21 00 48|48 00 21 e9) ld r9,72\(r1\) +.*: (e9 41 00 50|50 00 41 e9) ld r10,80\(r1\) +.*: (e9 61 00 58|58 00 61 e9) ld r11,88\(r1\) +.*: (38 21 00 60|60 00 21 38) addi r1,r1,96 +.*: (e8 01 00 10|10 00 01 e8) ld r0,16\(r1\) +.*: (7c 08 03 a6|a6 03 08 7c) mtlr r0 +.*: (4e 80 00 20|20 00 80 4e) blr + +0+10000160 <__tls_get_addr>: +.*: (4e 80 00 20|20 00 80 4e) blr + +0+10000164 <_start>: +.*: (38 62 80 08|08 80 62 38) addi r3,r2,-32760 +.*: (4b ff ff 99|99 ff ff 4b) bl .* <__tls_get_addr_desc> +.*: (60 00 00 00|00 00 00 60) nop + \.\.\. + +0+12000100 <.*\.long_branch\.__tls_get_addr_desc>: +.*: (4a 00 00 00|00 00 00 4a) b .* <__tls_get_addr_desc> + \.\.\. +.*: (38 62 80 08|08 80 62 38) addi r3,r2,-32760 +.*: (4b ff ff dd|dd ff ff 4b) bl .* <.*\.long_branch\.__tls_get_addr_desc> +.*: (60 00 00 00|00 00 00 60) nop diff --git a/ld/testsuite/ld-powerpc/tlsdesc4.s b/ld/testsuite/ld-powerpc/tlsdesc4.s new file mode 100644 index 00000000000..6dc3082724d --- /dev/null +++ b/ld/testsuite/ld-powerpc/tlsdesc4.s @@ -0,0 +1,18 @@ + .text + .globl _start +_start: + .cfi_startproc + addi 3,2,gd@got@tlsgd + bl __tls_get_addr_desc(gd@tlsgd) + nop + .cfi_endproc + + .section .text.pad1,"ax" + .space 0x1ffff90 + + .section .text.far,"ax" + .cfi_startproc + addi 3,2,gd@got@tlsgd + bl __tls_get_addr_desc(gd@tlsgd) + nop + .cfi_endproc diff --git a/ld/testsuite/ld-powerpc/tlsdesc4.wf b/ld/testsuite/ld-powerpc/tlsdesc4.wf new file mode 100644 index 00000000000..8d249798103 --- /dev/null +++ b/ld/testsuite/ld-powerpc/tlsdesc4.wf @@ -0,0 +1,49 @@ +Contents of the \.eh_frame section: + +0+ 0+10 0+ CIE + Version: 1 + Augmentation: "zR" + Code alignment factor: 4 + Data alignment factor: -8 + Return address column: 65 + Augmentation data: 1b + DW_CFA_def_cfa: r1 ofs 0 + +0+14 0+34 0+18 FDE cie=0+ pc=0+10000100..0+10000160 + DW_CFA_advance_loc: 44 to 0+1000012c + DW_CFA_def_cfa_offset: 96 + DW_CFA_offset_extended_sf: r65 at cfa\+16 + DW_CFA_offset: r4 at cfa-64 + DW_CFA_offset: r5 at cfa-56 + DW_CFA_offset: r6 at cfa-48 + DW_CFA_offset: r7 at cfa-40 + DW_CFA_offset: r8 at cfa-32 + DW_CFA_offset: r9 at cfa-24 + DW_CFA_offset: r10 at cfa-16 + DW_CFA_offset: r11 at cfa-8 + DW_CFA_advance_loc: 40 to 0+10000154 + DW_CFA_def_cfa_offset: 0 + DW_CFA_restore: r4 + DW_CFA_restore: r5 + DW_CFA_restore: r6 + DW_CFA_restore: r7 + DW_CFA_restore: r8 + DW_CFA_restore: r9 + DW_CFA_restore: r10 + DW_CFA_restore: r11 + DW_CFA_advance_loc: 8 to 0+1000015c + DW_CFA_restore_extended: r65 + DW_CFA_nop + DW_CFA_nop + DW_CFA_nop + +0+4c 0+10 0+50 FDE cie=0+ pc=0+10000164..0+10000170 + DW_CFA_nop + DW_CFA_nop + DW_CFA_nop + +0+60 0+10 0+64 FDE cie=0+ pc=0+12000120..0+1200012c + DW_CFA_nop + DW_CFA_nop + DW_CFA_nop + -- 2.39.2