diff options
-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 |