diff options
author | Alan Modra <amodra@gmail.com> | 2017-07-25 13:52:32 +0930 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2017-07-25 15:14:39 +0930 |
commit | d4aaa2a0744a28143f0b923802b6d1fa8db15887 (patch) | |
tree | 29a6410366e5a99161ed99b3a8756c1f9d7e8d1b | |
parent | aafd38357af0c9c225f56afcb93cc3a4da763ccd (diff) | |
download | gdb-d4aaa2a0744a28143f0b923802b6d1fa8db15887.zip gdb-d4aaa2a0744a28143f0b923802b6d1fa8db15887.tar.gz gdb-d4aaa2a0744a28143f0b923802b6d1fa8db15887.tar.bz2 |
__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.
-rw-r--r-- | bfd/ChangeLog | 12 | ||||
-rw-r--r-- | bfd/elf64-ppc.c | 191 | ||||
-rw-r--r-- | ld/ChangeLog | 7 | ||||
-rw-r--r-- | ld/testsuite/ld-powerpc/powerpc.exp | 2 | ||||
-rw-r--r-- | ld/testsuite/ld-powerpc/tlsopt5.d | 4 | ||||
-rw-r--r-- | ld/testsuite/ld-powerpc/tlsopt5.s | 2 | ||||
-rw-r--r-- | ld/testsuite/ld-powerpc/tlsopt5.wf | 32 |
7 files changed, 166 insertions, 84 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 9ae5da9..d224022 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -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 diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index f399e35..cc0e8ee 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -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 (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->size = ((group->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->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 diff --git a/ld/ChangeLog b/ld/ChangeLog index 2d3b0eb..c44bc33 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -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 diff --git a/ld/testsuite/ld-powerpc/powerpc.exp b/ld/testsuite/ld-powerpc/powerpc.exp index 9816eff..6249ccb 100644 --- a/ld/testsuite/ld-powerpc/powerpc.exp +++ b/ld/testsuite/ld-powerpc/powerpc.exp @@ -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"} diff --git a/ld/testsuite/ld-powerpc/tlsopt5.d b/ld/testsuite/ld-powerpc/tlsopt5.d index 7a74679..3c85185 100644 --- a/ld/testsuite/ld-powerpc/tlsopt5.d +++ b/ld/testsuite/ld-powerpc/tlsopt5.d @@ -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 diff --git a/ld/testsuite/ld-powerpc/tlsopt5.s b/ld/testsuite/ld-powerpc/tlsopt5.s index 598bbd9..70902ef 100644 --- a/ld/testsuite/ld-powerpc/tlsopt5.s +++ b/ld/testsuite/ld-powerpc/tlsopt5.s @@ -1,5 +1,7 @@ .globl _start _start: + .cfi_startproc addi 3,2,gd@got@tlsgd bl __tls_get_addr(gd@tlsgd) nop + .cfi_endproc diff --git a/ld/testsuite/ld-powerpc/tlsopt5.wf b/ld/testsuite/ld-powerpc/tlsopt5.wf new file mode 100644 index 0000000..05ef7e0 --- /dev/null +++ b/ld/testsuite/ld-powerpc/tlsopt5.wf @@ -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 |