aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfd/ChangeLog11
-rw-r--r--bfd/elf64-ppc.c138
-rw-r--r--ld/ChangeLog9
-rw-r--r--ld/testsuite/ld-powerpc/powerpc.exp6
-rw-r--r--ld/testsuite/ld-powerpc/tlsdesc3.d38
-rw-r--r--ld/testsuite/ld-powerpc/tlsdesc3.wf43
-rw-r--r--ld/testsuite/ld-powerpc/tlsdesc4.d46
-rw-r--r--ld/testsuite/ld-powerpc/tlsdesc4.s18
-rw-r--r--ld/testsuite/ld-powerpc/tlsdesc4.wf49
9 files changed, 357 insertions, 1 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 1bd9b5f..f20b2c0 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,5 +1,16 @@
2020-01-22 Alan Modra <amodra@gmail.com>
+ * 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 <amodra@gmail.com>
+
* elf64-ppc.h (struct ppc64_elf_params): Add no_tls_get_addr_regsave.
* elf64-ppc.c (struct ppc_link_hash_table): Add tga_desc and
tga_desc_fd.
diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
index 6b11a11..b3f8f6b 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 edfc090..b196d21 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -1,5 +1,14 @@
2020-01-22 Alan Modra <amodra@gmail.com>
+ * 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 <amodra@gmail.com>
+
* emultempl/ppc64elf.em (ppc64_opt, PARSE_AND_LIST_LONGOPTS),
(PARSE_AND_LIST_OPTIONS, PARSE_AND_LIST_ARGS_CASES): Support
--tls-get-addr-regsave and --no-tls-get-addr-regsave.
diff --git a/ld/testsuite/ld-powerpc/powerpc.exp b/ld/testsuite/ld-powerpc/powerpc.exp
index d50846c..94b2fac 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 0000000..360dcff
--- /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 0000000..af5a6b4
--- /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 0000000..eb162bb
--- /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 0000000..6dc3082
--- /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 0000000..8d24979
--- /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
+