__tls_get_addr_opt stub eh_frame info

Since the __tls_get_addr_opt stub saves LR and makes a call, eh_frame
info should be generated to describe how to unwind through the stub.

The patch also changes the way the backend iterates over stubs, from
looking at all sections in stub_bfd to which all dynamic sections are
attached as well, to iterating over the group list, which gets just
the stub sections.  Most binaries will have just one or two stub
groups, so this is a little faster.

bfd/
	* elf64-ppc.c (struct map_stub): Add tls_get_addr_opt_bctrl.
	(stub_eh_frame_size): New function.
	(ppc_size_one_stub): Set group tls_get_addr_opt_bctrl.
	(group_sections): Init group tls_get_addr_opt_bctrl.
	(ppc64_elf_size_stubs): Update sizing and initialization of
	.eh_frame.  Iteration over stubs via group list.
	(ppc64_elf_build_stubs): Iterate over stubs via group list.
	(ppc64_elf_finish_dynamic_sections): Update finalization of
	.eh_frame.
ld/
	* testsuite/ld-powerpc/tlsopt5.s: Add cfi.
	* testsuite/ld-powerpc/tlsopt5.d: Update.
	* testsuite/ld-powerpc/tlsopt5.wf: New file.
	* testsuite/ld-powerpc/powerpc.exp: Perform new tlsopt5 test.
This commit is contained in:
Alan Modra 2017-07-25 13:52:32 +09:30
parent aafd38357a
commit d4aaa2a074
7 changed files with 165 additions and 83 deletions

View File

@ -1,3 +1,15 @@
2017-07-25 Alan Modra <amodra@gmail.com>
* elf64-ppc.c (struct map_stub): Add tls_get_addr_opt_bctrl.
(stub_eh_frame_size): New function.
(ppc_size_one_stub): Set group tls_get_addr_opt_bctrl.
(group_sections): Init group tls_get_addr_opt_bctrl.
(ppc64_elf_size_stubs): Update sizing and initialization of
.eh_frame. Iteration over stubs via group list.
(ppc64_elf_build_stubs): Iterate over stubs via group list.
(ppc64_elf_finish_dynamic_sections): Update finalization of
.eh_frame.
2017-07-24 Nick Clifton <nickc@redhat.com>
PR 21813

View File

@ -3919,6 +3919,9 @@ struct map_stub
/* Whether to emit a copy of register save/restore functions in this
group. */
int needs_save_res;
/* The offset of the __tls_get_addr_opt plt stub bctrl in this group,
or -1u if no such stub with bctrl exists. */
unsigned int tls_get_addr_opt_bctrl;
};
struct ppc_stub_hash_entry {
@ -11386,6 +11389,15 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
- htab->sec_info[stub_entry->group->link_sec->id].toc_off);
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)
&& htab->params->tls_get_addr_opt
&& (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;
if (htab->params->plt_stub_align)
size += plt_stub_pad (htab, stub_entry, off);
if (info->emitrelocations)
@ -12252,6 +12264,7 @@ group_sections (struct bfd_link_info *info,
group->link_sec = curr;
group->stub_sec = NULL;
group->needs_save_res = 0;
group->tls_get_addr_opt_bctrl = -1u;
group->next = htab->group;
htab->group = group;
do
@ -12302,6 +12315,27 @@ static const unsigned char glink_eh_frame_cie[] =
DW_CFA_def_cfa, 1, 0 /* def_cfa: r1 offset 0. */
};
static size_t
stub_eh_frame_size (struct map_stub *group, size_t align)
{
size_t this_size = 17;
if (group->tls_get_addr_opt_bctrl != -1u)
{
unsigned int to_bctrl = group->tls_get_addr_opt_bctrl / 4;
if (to_bctrl < 64)
this_size += 1;
else if (to_bctrl < 256)
this_size += 2;
else if (to_bctrl < 65536)
this_size += 3;
else
this_size += 5;
this_size += 6;
}
this_size = (this_size + align - 1) & -align;
return this_size;
}
/* Stripping output sections is normally done before dynamic section
symbols have been allocated. This function is called later, and
handles cases like htab->brlt which is mapped to its own output
@ -12404,7 +12438,6 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
bfd *input_bfd;
unsigned int bfd_indx;
struct map_stub *group;
asection *stub_sec;
htab->stub_iteration += 1;
@ -12722,11 +12755,11 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
/* We may have added some stubs. Find out the new size of the
stub sections. */
for (stub_sec = htab->params->stub_bfd->sections;
stub_sec != NULL;
stub_sec = stub_sec->next)
if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
for (group = htab->group; group != NULL; group = group->next)
if (group->stub_sec != NULL)
{
asection *stub_sec = group->stub_sec;
if (htab->stub_iteration <= STUB_SHRINK_ITER
|| stub_sec->rawsize < stub_sec->size)
/* Past STUB_SHRINK_ITER, rawsize is the max size seen. */
@ -12761,11 +12794,9 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
{
size_t size = 0, align = 4;
for (stub_sec = htab->params->stub_bfd->sections;
stub_sec != NULL;
stub_sec = stub_sec->next)
if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
size += (17 + align - 1) & -align;
for (group = htab->group; group != NULL; group = group->next)
if (group->stub_sec != NULL)
size += stub_eh_frame_size (group, align);
if (htab->glink != NULL && htab->glink->size != 0)
size += (24 + align - 1) & -align;
if (size != 0)
@ -12777,24 +12808,20 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
}
if (htab->params->plt_stub_align != 0)
for (stub_sec = htab->params->stub_bfd->sections;
stub_sec != NULL;
stub_sec = stub_sec->next)
if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
stub_sec->size = ((stub_sec->size
+ (1 << htab->params->plt_stub_align) - 1)
& -(1 << htab->params->plt_stub_align));
for (group = htab->group; group != NULL; group = group->next)
if (group->stub_sec != NULL)
group->stub_sec->size = ((group->stub_sec->size
+ (1 << htab->params->plt_stub_align) - 1)
& -(1 << htab->params->plt_stub_align));
for (stub_sec = htab->params->stub_bfd->sections;
stub_sec != NULL;
stub_sec = stub_sec->next)
if ((stub_sec->flags & SEC_LINKER_CREATED) == 0
&& stub_sec->rawsize != stub_sec->size
for (group = htab->group; group != NULL; group = group->next)
if (group->stub_sec != NULL
&& group->stub_sec->rawsize != group->stub_sec->size
&& (htab->stub_iteration <= STUB_SHRINK_ITER
|| stub_sec->rawsize < stub_sec->size))
|| group->stub_sec->rawsize < group->stub_sec->size))
break;
if (stub_sec == NULL
if (group == NULL
&& (htab->glink_eh_frame == NULL
|| htab->glink_eh_frame->rawsize == htab->glink_eh_frame->size))
break;
@ -12809,7 +12836,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
bfd_vma val;
bfd_byte *p, *last_fde;
size_t last_fde_len, size, align, pad;
asection *stub_sec;
struct map_stub *group;
p = bfd_zalloc (htab->glink_eh_frame->owner, htab->glink_eh_frame->size);
if (p == NULL)
@ -12824,13 +12851,11 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
bfd_put_32 (htab->elf.dynobj, last_fde_len, p);
p += last_fde_len + 4;
for (stub_sec = htab->params->stub_bfd->sections;
stub_sec != NULL;
stub_sec = stub_sec->next)
if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
for (group = htab->group; group != NULL; group = group->next)
if (group->stub_sec != NULL)
{
last_fde = p;
last_fde_len = ((17 + align - 1) & -align) - 4;
last_fde_len = stub_eh_frame_size (group, align) - 4;
/* FDE length. */
bfd_put_32 (htab->elf.dynobj, last_fde_len, p);
p += 4;
@ -12841,12 +12866,44 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
/* Offset to stub section, written later. */
p += 4;
/* stub section size. */
bfd_put_32 (htab->elf.dynobj, stub_sec->size, p);
bfd_put_32 (htab->elf.dynobj, group->stub_sec->size, p);
p += 4;
/* Augmentation. */
p += 1;
if (group->tls_get_addr_opt_bctrl != -1u)
{
unsigned int to_bctrl = group->tls_get_addr_opt_bctrl / 4;
/* This FDE needs more than just the default.
Describe __tls_get_addr_opt stub LR. */
if (to_bctrl < 64)
*p++ = DW_CFA_advance_loc + to_bctrl;
else if (to_bctrl < 256)
{
*p++ = DW_CFA_advance_loc1;
*p++ = to_bctrl;
}
else if (to_bctrl < 65536)
{
*p++ = DW_CFA_advance_loc2;
bfd_put_16 (htab->elf.dynobj, to_bctrl, p);
p += 2;
}
else
{
*p++ = DW_CFA_advance_loc4;
bfd_put_32 (htab->elf.dynobj, to_bctrl, p);
p += 4;
}
*p++ = DW_CFA_offset_extended_sf;
*p++ = 65;
*p++ = -(STK_LINKER (htab) / 8) & 0x7f;
*p++ = DW_CFA_advance_loc + 4;
*p++ = DW_CFA_restore_extended;
*p++ = 65;
}
/* Pad. */
p += ((17 + align - 1) & -align) - 17;
p = last_fde + last_fde_len + 4;
}
if (htab->glink != NULL && htab->glink->size != 0)
{
@ -13115,10 +13172,8 @@ ppc64_elf_build_stubs (struct bfd_link_info *info,
return FALSE;
/* Allocate memory to hold the linker stubs. */
for (stub_sec = htab->params->stub_bfd->sections;
stub_sec != NULL;
stub_sec = stub_sec->next)
if ((stub_sec->flags & SEC_LINKER_CREATED) == 0
for (group = htab->group; group != NULL; group = group->next)
if ((stub_sec = group->stub_sec) != NULL
&& stub_sec->size != 0)
{
stub_sec->contents = bfd_zalloc (htab->params->stub_bfd, stub_sec->size);
@ -13300,18 +13355,14 @@ ppc64_elf_build_stubs (struct bfd_link_info *info,
htab->relbrlt->reloc_count = 0;
if (htab->params->plt_stub_align != 0)
for (stub_sec = htab->params->stub_bfd->sections;
stub_sec != NULL;
stub_sec = stub_sec->next)
if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
for (group = htab->group; group != NULL; group = group->next)
if ((stub_sec = group->stub_sec) != NULL)
stub_sec->size = ((stub_sec->size
+ (1 << htab->params->plt_stub_align) - 1)
& -(1 << htab->params->plt_stub_align));
for (stub_sec = htab->params->stub_bfd->sections;
stub_sec != NULL;
stub_sec = stub_sec->next)
if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
for (group = htab->group; group != NULL; group = group->next)
if ((stub_sec = group->stub_sec) != NULL)
{
stub_sec_count += 1;
if (stub_sec->rawsize != stub_sec->size
@ -13323,7 +13374,7 @@ ppc64_elf_build_stubs (struct bfd_link_info *info,
/* Note that the glink_eh_frame check here is not only testing that
the generated size matched the calculated size but also that
bfd_elf_discard_info didn't make any changes to the section. */
if (stub_sec != NULL
if (group != NULL
|| (htab->glink_eh_frame != NULL
&& htab->glink_eh_frame->rawsize != htab->glink_eh_frame->size))
{
@ -15743,55 +15794,40 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd,
{
bfd_vma val;
bfd_byte *p;
asection *stub_sec;
struct map_stub *group;
size_t align = 4;
p = htab->glink_eh_frame->contents;
p += (sizeof (glink_eh_frame_cie) + align - 1) & -align;
for (stub_sec = htab->params->stub_bfd->sections;
stub_sec != NULL;
stub_sec = stub_sec->next)
if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
for (group = htab->group; group != NULL; group = group->next)
if (group->stub_sec != NULL)
{
/* FDE length. */
p += 4;
/* CIE pointer. */
p += 4;
/* Offset to stub section. */
val = (stub_sec->output_section->vma
+ stub_sec->output_offset);
val = (group->stub_sec->output_section->vma
+ group->stub_sec->output_offset);
val -= (htab->glink_eh_frame->output_section->vma
+ htab->glink_eh_frame->output_offset
+ (p - htab->glink_eh_frame->contents));
+ (p + 8 - htab->glink_eh_frame->contents));
if (val + 0x80000000 > 0xffffffff)
{
info->callbacks->einfo
(_("%P: %s offset too large for .eh_frame sdata4 encoding"),
stub_sec->name);
group->stub_sec->name);
return FALSE;
}
bfd_put_32 (dynobj, val, p);
p += 4;
/* stub section size. */
p += 4;
/* Augmentation. */
p += 1;
/* Pad. */
p += ((17 + align - 1) & -align) - 17;
bfd_put_32 (dynobj, val, p + 8);
p += stub_eh_frame_size (group, align);
}
if (htab->glink != NULL && htab->glink->size != 0)
{
/* FDE length. */
p += 4;
/* CIE pointer. */
p += 4;
/* Offset to .glink. */
val = (htab->glink->output_section->vma
+ htab->glink->output_offset
+ 8);
val -= (htab->glink_eh_frame->output_section->vma
+ htab->glink_eh_frame->output_offset
+ (p - htab->glink_eh_frame->contents));
+ (p + 8 - htab->glink_eh_frame->contents));
if (val + 0x80000000 > 0xffffffff)
{
info->callbacks->einfo
@ -15799,15 +15835,8 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd,
htab->glink->name);
return FALSE;
}
bfd_put_32 (dynobj, val, p);
p += 4;
/* .glink size. */
p += 4;
/* Augmentation. */
p += 1;
/* Ops. */
p += 7;
p += ((24 + align - 1) & -align) - 24;
bfd_put_32 (dynobj, val, p + 8);
p += (24 + align - 1) & -align;
}
if (htab->glink_eh_frame->sec_info_type == SEC_INFO_TYPE_EH_FRAME

View File

@ -1,3 +1,10 @@
2017-07-25 Alan Modra <amodra@gmail.com>
* testsuite/ld-powerpc/tlsopt5.s: Add cfi.
* testsuite/ld-powerpc/tlsopt5.d: Update.
* testsuite/ld-powerpc/tlsopt5.wf: New file.
* testsuite/ld-powerpc/powerpc.exp: Perform new tlsopt5 test.
2017-07-24 Claudiu Zissulescu <claziss@synopsys.com>
* testsuite/ld-arc/jli-overflow.d: Force testing for little

View File

@ -211,7 +211,7 @@ set ppc64elftests {
{"TLS DLL" "-shared -melf64ppc --version-script tlsdll.ver" "" "-a64" {tlsdll.s}
{} "tlsdll.so"}
{"TLS opt 5" "-melf64ppc -shared --gc-sections --no-plt-localentry tmpdir/tlsdll.so" "" "-a64" {tlsopt5.s}
{{objdump -dr tlsopt5.d}}
{{objdump -dr tlsopt5.d} {readelf -wf tlsopt5.wf}}
"tlsopt5"}
{"sym@tocbase" "-shared -melf64ppc" "" "-a64" {symtocbase-1.s symtocbase-2.s}
{{objdump -dj.data symtocbase.d}} "symtocbase.so"}

View File

@ -31,8 +31,8 @@ Disassembly of section \.text:
.*: (08 80 62 38|38 62 80 08) addi r3,r2,-32760
.*: (b9 ff ff 4b|4b ff ff b9) bl .*
.*: (00 00 00 60|60 00 00 00) nop
.*: (f8 01 01 00|00 00 00 00) .*
.*: (00 00 00 00|00 01 01 f8) .*
.*: (f8 02 01 00|00 00 00 00) .*
.*: (00 00 00 00|00 01 02 f8) .*
0+318 <__glink_PLTresolve>:
.*: (a6 02 08 7c|7c 08 02 a6) mflr r0

View File

@ -1,5 +1,7 @@
.globl _start
_start:
.cfi_startproc
addi 3,2,gd@got@tlsgd
bl __tls_get_addr(gd@tlsgd)
nop
.cfi_endproc

View File

@ -0,0 +1,32 @@
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+14 0+18 FDE cie=0+ pc=0+2c0\.\.0+304
DW_CFA_advance_loc: 48 to 0+2f0
DW_CFA_offset_extended_sf: r65 at cfa\+8
DW_CFA_advance_loc: 16 to 0+300
DW_CFA_restore_extended: r65
0+2c 0+18 0+30 FDE cie=0+ pc=0+318\.\.0+354
DW_CFA_advance_loc: 4 to 0+31c
DW_CFA_register: r65 in r0
DW_CFA_advance_loc: 28 to 0+338
DW_CFA_restore_extended: r65
DW_CFA_nop
DW_CFA_nop
DW_CFA_nop
DW_CFA_nop
0+48 0+10 0+4c FDE cie=0+ pc=0+304\.\.0+310
DW_CFA_nop
DW_CFA_nop
DW_CFA_nop