From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-pg1-x52f.google.com (mail-pg1-x52f.google.com [IPv6:2607:f8b0:4864:20::52f]) by sourceware.org (Postfix) with ESMTPS id B5A94386185D for ; Wed, 23 Sep 2020 22:41:43 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org B5A94386185D Received: by mail-pg1-x52f.google.com with SMTP id 34so596557pgo.13 for ; Wed, 23 Sep 2020 15:41:43 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:subject:message-id:mime-version :content-disposition:user-agent; bh=YE1xkPSx+UwPoGKNcI4iSllqjNst7ZV8gQmgSLx1ZSg=; b=YGk1AhQCzt4f0Ve+HyqxWRox6kKJEjj9GpTno3qrupy6Pl2YojH/taWSWXrYSZwviH 1rQCbbPPy2gxDL64a6Cv8xzTdllYC8v7cD9nFI9XaVZeTwL1EaZZb+M4SnTdbXVdXM8p 4pbQrcUscxem6wZrLD78prBR3KadYacXEFieC0W8/PU8ZataDtjrLtWc/o0pBLgu4xKe eWx8ABqhFlGbP/EyhGCdf/tKfhw2b0YeeGbJuJBLSLP2flnGbh7MAqEscX45BmWbo/aJ hsxbPswnLAgcl/irsF3Mk3E3PXxsTivR7IUdGS9HihT5YEQ8tF0WqAt8HZD1vlO9zwu5 wNwg== X-Gm-Message-State: AOAM530GYW0D1v6h+q3FigyTLYGJKakwFMFaS8cnhZEfvGctUUp2YInT xVhSQfEgO91+hX9x3JSkgz68mCOhPig= X-Google-Smtp-Source: ABdhPJyD9+fiaN8f0yRfJ2T/9rfjAUxzRIrx5APh4WOP/h4zZ3Yu8ICt6rGp9T72kRO9CPwWEotznw== X-Received: by 2002:a63:794f:: with SMTP id u76mr1584680pgc.315.1600900902024; Wed, 23 Sep 2020 15:41:42 -0700 (PDT) Received: from bubble.grove.modra.org ([2406:3400:51d:8cc0:9583:52e2:19a0:946d]) by smtp.gmail.com with ESMTPSA id g1sm420609pjl.21.2020.09.23.15.41.40 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 23 Sep 2020 15:41:41 -0700 (PDT) Received: by bubble.grove.modra.org (Postfix, from userid 1000) id C1CEE85B1A; Thu, 24 Sep 2020 08:11:37 +0930 (ACST) Date: Thu, 24 Sep 2020 08:11:37 +0930 From: Alan Modra To: binutils@sourceware.org Subject: PR26656, power10 libstdc++.so segfault in __cxxabiv1::__cxa_throw Message-ID: <20200923224137.GH5452@bubble.grove.modra.org> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.9.4 (2018-02-28) X-Spam-Status: No, score=-10.0 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: binutils@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Binutils mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 23 Sep 2020 22:41:46 -0000 This adds missing support for a power10 version of the __tls_get_addr call stub implementing DT_PPC64_OPT PPC64_OPT_TLS. Without this, power10 code using __tls_get_addr fails miserably at runtime unless the --no-tls-get-addr-optimize option is given. PR 26656 * elf64-ppc.c (plt_stub_size): Add "odd" param. Use it with size_power10_offset rather than calculating from start of stub. Add size for notoc tls_get_addr_opt stub. (plt_stub_pad): Add "odd" param, pass to plt_stub_size. (build_tls_get_addr_head, build_tls_get_addr_tail): New functions. (build_tls_get_addr_stub): Delete. (ppc_build_one_stub): Use a temp for htab->params->stub_bfd. Emit notoc tls_get_addr_opt stub. Move eh_frame code to suit. Adjust code to use bfd_tls_get_addr_head/tail in place of build_tls_get_addr_stub. (ppc_size_one_stub): Size notoc tls_get_addr_opt stub. Adjust plt_stub_size and plt_stub_pad calls. Correct "odd" when padding stub. Size eh_frame for notoc stub too. Correct lr_restore value. (ppc64_elf_relocate_section): Don't skip over first insn of notoc tls_get_addr_opt stub. diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index 4d16dc3cd4..320717cb45 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -10842,62 +10842,60 @@ eh_advance_size (unsigned int delta) static inline unsigned int plt_stub_size (struct ppc_link_hash_table *htab, struct ppc_stub_hash_entry *stub_entry, - bfd_vma off) + bfd_vma off, + unsigned int odd) { unsigned size; if (stub_entry->stub_type >= ppc_stub_plt_call_notoc) { if (htab->params->power10_stubs != 0) - { - bfd_vma start = (stub_entry->stub_offset - + stub_entry->group->stub_sec->output_offset - + stub_entry->group->stub_sec->output_section->vma); - if (stub_entry->stub_type > ppc_stub_plt_call_notoc) - start += 4; - size = 8 + size_power10_offset (off, start & 4); - } + size = 8 + size_power10_offset (off, odd); else size = 8 + size_offset (off - 8); if (stub_entry->stub_type > ppc_stub_plt_call_notoc) size += 4; - return size; } - - size = 12; - if (ALWAYS_EMIT_R2SAVE - || stub_entry->stub_type == ppc_stub_plt_call_r2save) - size += 4; - if (PPC_HA (off) != 0) - size += 4; - if (htab->opd_abi) + else { - size += 4; - if (htab->params->plt_static_chain) + size = 12; + if (ALWAYS_EMIT_R2SAVE + || stub_entry->stub_type == ppc_stub_plt_call_r2save) size += 4; - if (htab->params->plt_thread_safe - && htab->elf.dynamic_sections_created - && stub_entry->h != NULL - && stub_entry->h->elf.dynindx != -1) - size += 8; - if (PPC_HA (off + 8 + 8 * htab->params->plt_static_chain) != PPC_HA (off)) + if (PPC_HA (off) != 0) size += 4; + if (htab->opd_abi) + { + size += 4; + if (htab->params->plt_static_chain) + size += 4; + if (htab->params->plt_thread_safe + && htab->elf.dynamic_sections_created + && stub_entry->h != NULL + && stub_entry->h->elf.dynindx != -1) + size += 8; + if (PPC_HA (off + 8 + 8 * htab->params->plt_static_chain) + != PPC_HA (off)) + size += 4; + } } if (stub_entry->h != NULL && is_tls_get_addr (&stub_entry->h->elf, htab) && htab->params->tls_get_addr_opt) { - if (htab->params->no_tls_get_addr_regsave) + if (!htab->params->no_tls_get_addr_regsave) { - size += 7 * 4; - if (stub_entry->stub_type == ppc_stub_plt_call_r2save) - size += 6 * 4; + size += 30 * 4; + if (stub_entry->stub_type == ppc_stub_plt_call_r2save + || stub_entry->stub_type == ppc_stub_plt_call_both) + size += 4; } else { - size += 30 * 4; - if (stub_entry->stub_type == ppc_stub_plt_call_r2save) - size += 4; + size += 7 * 4; + if (stub_entry->stub_type == ppc_stub_plt_call_r2save + || stub_entry->stub_type == ppc_stub_plt_call_both) + size += 6 * 4; } } return size; @@ -10912,7 +10910,8 @@ plt_stub_size (struct ppc_link_hash_table *htab, static inline unsigned int plt_stub_pad (struct ppc_link_hash_table *htab, struct ppc_stub_hash_entry *stub_entry, - bfd_vma plt_off) + bfd_vma plt_off, + unsigned int odd) { int stub_align; unsigned stub_size; @@ -10927,7 +10926,7 @@ plt_stub_pad (struct ppc_link_hash_table *htab, } stub_align = 1 << -htab->params->plt_stub_align; - stub_size = plt_stub_size (htab, stub_entry, plt_off); + stub_size = plt_stub_size (htab, stub_entry, plt_off, odd); if (((stub_off + stub_size - 1) & -stub_align) - (stub_off & -stub_align) > ((stub_size - 1) & -stub_align)) return stub_align - (stub_off & (stub_align - 1)); @@ -11123,14 +11122,12 @@ build_plt_stub (struct ppc_link_hash_table *htab, #define MR_R3_R0 0x7c030378 #define BCTRL 0x4e800421 -static inline bfd_byte * -build_tls_get_addr_stub (struct ppc_link_hash_table *htab, +static bfd_byte * +build_tls_get_addr_head (struct ppc_link_hash_table *htab, struct ppc_stub_hash_entry *stub_entry, - bfd_byte *p, bfd_vma offset, Elf_Internal_Rela *r) + bfd_byte *p) { bfd *obfd = htab->params->stub_bfd; - bfd_byte *loc = p; - unsigned int i; bfd_put_32 (obfd, LD_R0_0R3 + 0, p), p += 4; bfd_put_32 (obfd, LD_R12_0R3 + 8, p), p += 4; @@ -11139,21 +11136,43 @@ build_tls_get_addr_stub (struct ppc_link_hash_table *htab, bfd_put_32 (obfd, ADD_R3_R12_R13, p), p += 4; bfd_put_32 (obfd, BEQLR, p), p += 4; bfd_put_32 (obfd, MR_R3_R0, p), p += 4; - if (htab->params->no_tls_get_addr_regsave) - { - if (r != NULL) - r[0].r_offset += 7 * 4; - if (stub_entry->stub_type != ppc_stub_plt_call_r2save) - return build_plt_stub (htab, stub_entry, p, offset, r); + if (!htab->params->no_tls_get_addr_regsave) + p = tls_get_addr_prologue (obfd, p, htab); + else if (stub_entry->stub_type == ppc_stub_plt_call_r2save + || stub_entry->stub_type == ppc_stub_plt_call_both) + { bfd_put_32 (obfd, MFLR_R0, p); p += 4; bfd_put_32 (obfd, STD_R0_0R1 + STK_LINKER (htab), p); p += 4; + } + return p; +} - if (r != NULL) - r[0].r_offset += 2 * 4; - p = build_plt_stub (htab, stub_entry, p, offset, r); +static bfd_byte * +build_tls_get_addr_tail (struct ppc_link_hash_table *htab, + struct ppc_stub_hash_entry *stub_entry, + bfd_byte *p, + bfd_byte *loc) +{ + bfd *obfd = htab->params->stub_bfd; + + if (!htab->params->no_tls_get_addr_regsave) + { + bfd_put_32 (obfd, BCTRL, p - 4); + + if (stub_entry->stub_type == ppc_stub_plt_call_r2save + || stub_entry->stub_type == ppc_stub_plt_call_both) + { + bfd_put_32 (obfd, LD_R2_0R1 + STK_TOC (htab), p); + p += 4; + } + p = tls_get_addr_epilogue (obfd, p, htab); + } + else if (stub_entry->stub_type == ppc_stub_plt_call_r2save + || stub_entry->stub_type == ppc_stub_plt_call_both) + { bfd_put_32 (obfd, BCTRL, p - 4); bfd_put_32 (obfd, LD_R2_0R1 + STK_TOC (htab), p); @@ -11165,24 +11184,6 @@ build_tls_get_addr_stub (struct ppc_link_hash_table *htab, bfd_put_32 (obfd, BLR, p); p += 4; } - else - { - p = tls_get_addr_prologue (obfd, p, htab); - - if (r != NULL) - r[0].r_offset += 18 * 4; - - p = build_plt_stub (htab, stub_entry, p, offset, r); - bfd_put_32 (obfd, BCTRL, p - 4); - - if (stub_entry->stub_type == ppc_stub_plt_call_r2save) - { - bfd_put_32 (obfd, LD_R2_0R1 + STK_TOC (htab), p); - p += 4; - } - - p = tls_get_addr_epilogue (obfd, p, htab); - } if (htab->glink_eh_frame != NULL && htab->glink_eh_frame->size != 0) @@ -11191,21 +11192,11 @@ build_tls_get_addr_stub (struct ppc_link_hash_table *htab, base = htab->glink_eh_frame->contents + stub_entry->group->eh_base + 17; eh = base + stub_entry->group->eh_size; - if (htab->params->no_tls_get_addr_regsave) - { - unsigned int lr_used, delta; - lr_used = stub_entry->stub_offset + (p - 20 - loc); - delta = lr_used - stub_entry->group->lr_restore; - stub_entry->group->lr_restore = lr_used + 16; - eh = eh_advance (htab->elf.dynobj, eh, delta); - *eh++ = DW_CFA_offset_extended_sf; - *eh++ = 65; - *eh++ = -(STK_LINKER (htab) / 8) & 0x7f; - *eh++ = DW_CFA_advance_loc + 4; - } - else + + if (!htab->params->no_tls_get_addr_regsave) { - unsigned int cfa_updt, delta; + unsigned int cfa_updt, delta, i; + /* After the bctrl, lr has been modified so we need to emit .eh_frame info saying the return address is on the stack. In fact we must put the EH info at or before the call rather @@ -11244,10 +11235,27 @@ build_tls_get_addr_stub (struct ppc_link_hash_table *htab, for (i = 4; i < 12; i++) *eh++ = DW_CFA_restore + i; *eh++ = DW_CFA_advance_loc + 2; + *eh++ = DW_CFA_restore_extended; + *eh++ = 65; + stub_entry->group->eh_size = eh - base; + } + else if (stub_entry->stub_type == ppc_stub_plt_call_r2save + || stub_entry->stub_type == ppc_stub_plt_call_both) + { + unsigned int lr_used, delta; + + lr_used = stub_entry->stub_offset + (p - 20 - loc); + delta = lr_used - stub_entry->group->lr_restore; + stub_entry->group->lr_restore = lr_used + 16; + eh = eh_advance (htab->elf.dynobj, eh, delta); + *eh++ = DW_CFA_offset_extended_sf; + *eh++ = 65; + *eh++ = -(STK_LINKER (htab) / 8) & 0x7f; + *eh++ = DW_CFA_advance_loc + 4; + *eh++ = DW_CFA_restore_extended; + *eh++ = 65; + stub_entry->group->eh_size = eh - base; } - *eh++ = DW_CFA_restore_extended; - *eh++ = 65; - stub_entry->group->eh_size = eh - base; } return p; } @@ -11381,6 +11389,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) struct ppc_branch_hash_entry *br_entry; struct bfd_link_info *info; struct ppc_link_hash_table *htab; + bfd *obfd; bfd_byte *loc; bfd_byte *p, *relp; bfd_vma targ, off; @@ -11388,6 +11397,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) asection *plt; int num_rel; int odd; + bfd_boolean is_tga; /* Massage our args to the form they really have. */ stub_entry = (struct ppc_stub_hash_entry *) gen_entry; @@ -11437,6 +11447,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) off = targ - off; p = loc; + obfd = htab->params->stub_bfd; if (stub_entry->stub_type == ppc_stub_long_branch_r2off) { bfd_vma r2off = get_r2off (info, stub_entry); @@ -11446,23 +11457,21 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) htab->stub_error = TRUE; return FALSE; } - bfd_put_32 (htab->params->stub_bfd, STD_R2_0R1 + STK_TOC (htab), p); + bfd_put_32 (obfd, STD_R2_0R1 + STK_TOC (htab), p); p += 4; if (PPC_HA (r2off) != 0) { - bfd_put_32 (htab->params->stub_bfd, - ADDIS_R2_R2 | PPC_HA (r2off), p); + bfd_put_32 (obfd, ADDIS_R2_R2 | PPC_HA (r2off), p); p += 4; } if (PPC_LO (r2off) != 0) { - bfd_put_32 (htab->params->stub_bfd, - ADDI_R2_R2 | PPC_LO (r2off), p); + bfd_put_32 (obfd, ADDI_R2_R2 | PPC_LO (r2off), p); p += 4; } off -= p - loc; } - bfd_put_32 (htab->params->stub_bfd, B_DOT | (off & 0x3fffffc), p); + bfd_put_32 (obfd, B_DOT | (off & 0x3fffffc), p); p += 4; if (off + (1 << 25) >= (bfd_vma) (1 << 26)) @@ -11588,19 +11597,17 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) } p = loc; + obfd = htab->params->stub_bfd; if (stub_entry->stub_type != ppc_stub_plt_branch_r2off) { if (PPC_HA (off) != 0) { - bfd_put_32 (htab->params->stub_bfd, - ADDIS_R12_R2 | PPC_HA (off), p); + bfd_put_32 (obfd, ADDIS_R12_R2 | PPC_HA (off), p); p += 4; - bfd_put_32 (htab->params->stub_bfd, - LD_R12_0R12 | PPC_LO (off), p); + bfd_put_32 (obfd, LD_R12_0R12 | PPC_LO (off), p); } else - bfd_put_32 (htab->params->stub_bfd, - LD_R12_0R2 | PPC_LO (off), p); + bfd_put_32 (obfd, LD_R12_0R2 | PPC_LO (off), p); } else { @@ -11612,36 +11619,32 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) return FALSE; } - bfd_put_32 (htab->params->stub_bfd, STD_R2_0R1 + STK_TOC (htab), p); + bfd_put_32 (obfd, STD_R2_0R1 + STK_TOC (htab), p); p += 4; if (PPC_HA (off) != 0) { - bfd_put_32 (htab->params->stub_bfd, - ADDIS_R12_R2 | PPC_HA (off), p); + bfd_put_32 (obfd, ADDIS_R12_R2 | PPC_HA (off), p); p += 4; - bfd_put_32 (htab->params->stub_bfd, - LD_R12_0R12 | PPC_LO (off), p); + bfd_put_32 (obfd, LD_R12_0R12 | PPC_LO (off), p); } else - bfd_put_32 (htab->params->stub_bfd, LD_R12_0R2 | PPC_LO (off), p); + bfd_put_32 (obfd, LD_R12_0R2 | PPC_LO (off), p); if (PPC_HA (r2off) != 0) { p += 4; - bfd_put_32 (htab->params->stub_bfd, - ADDIS_R2_R2 | PPC_HA (r2off), p); + bfd_put_32 (obfd, ADDIS_R2_R2 | PPC_HA (r2off), p); } if (PPC_LO (r2off) != 0) { p += 4; - bfd_put_32 (htab->params->stub_bfd, - ADDI_R2_R2 | PPC_LO (r2off), p); + bfd_put_32 (obfd, ADDI_R2_R2 | PPC_LO (r2off), p); } } p += 4; - bfd_put_32 (htab->params->stub_bfd, MTCTR_R12, p); + bfd_put_32 (obfd, MTCTR_R12, p); p += 4; - bfd_put_32 (htab->params->stub_bfd, BCTR, p); + bfd_put_32 (obfd, BCTR, p); p += 4; break; @@ -11655,12 +11658,22 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) off = (stub_entry->stub_offset + stub_entry->group->stub_sec->output_offset + stub_entry->group->stub_sec->output_section->vma); + obfd = htab->params->stub_bfd; + is_tga = ((stub_entry->stub_type == ppc_stub_plt_call_notoc + || stub_entry->stub_type == ppc_stub_plt_call_both) + && is_tls_get_addr (&stub_entry->h->elf, htab) + && htab->params->tls_get_addr_opt); + if (is_tga) + { + p = build_tls_get_addr_head (htab, stub_entry, p); + off += p - loc; + } if (stub_entry->stub_type == ppc_stub_long_branch_both || stub_entry->stub_type == ppc_stub_plt_branch_both || stub_entry->stub_type == ppc_stub_plt_call_both) { off += 4; - bfd_put_32 (htab->params->stub_bfd, STD_R2_0R1 + STK_TOC (htab), p); + bfd_put_32 (obfd, STD_R2_0R1 + STK_TOC (htab), p); p += 4; } if (stub_entry->stub_type >= ppc_stub_plt_call_notoc) @@ -11693,17 +11706,39 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) if (htab->params->power10_stubs != 0) { bfd_boolean load = stub_entry->stub_type >= ppc_stub_plt_call_notoc; - p = build_power10_offset (htab->params->stub_bfd, p, off, odd, load); + p = build_power10_offset (obfd, p, off, odd, load); } else { + if (htab->glink_eh_frame != NULL + && htab->glink_eh_frame->size != 0) + { + bfd_byte *base, *eh; + unsigned int lr_used, delta; + + base = (htab->glink_eh_frame->contents + + stub_entry->group->eh_base + 17); + eh = base + stub_entry->group->eh_size; + lr_used = stub_entry->stub_offset + (p - loc) + 8; + delta = lr_used - stub_entry->group->lr_restore; + stub_entry->group->lr_restore = lr_used + 8; + eh = eh_advance (htab->elf.dynobj, eh, delta); + *eh++ = DW_CFA_register; + *eh++ = 65; + *eh++ = 12; + *eh++ = DW_CFA_advance_loc + 2; + *eh++ = DW_CFA_restore_extended; + *eh++ = 65; + stub_entry->group->eh_size = eh - base; + } + /* The notoc stubs calculate their target (either a PLT entry or the global entry point of a function) relative to the PC returned by the "bcl" two instructions past the start of the sequence emitted by build_offset. The offset is therefore 8 less than calculated from the start of the sequence. */ off -= 8; - p = build_offset (htab->params->stub_bfd, p, off, + p = build_offset (obfd, p, off, stub_entry->stub_type >= ppc_stub_plt_call_notoc); } @@ -11715,17 +11750,19 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) + stub_entry->group->stub_sec->output_offset + stub_entry->group->stub_sec->output_section->vma + (p - loc)); - bfd_put_32 (htab->params->stub_bfd, - B_DOT | ((targ - from) & 0x3fffffc), p); + bfd_put_32 (obfd, B_DOT | ((targ - from) & 0x3fffffc), p); } else { - bfd_put_32 (htab->params->stub_bfd, MTCTR_R12, p); + bfd_put_32 (obfd, MTCTR_R12, p); p += 4; - bfd_put_32 (htab->params->stub_bfd, BCTR, p); + bfd_put_32 (obfd, BCTR, p); } p += 4; + if (is_tga) + p = build_tls_get_addr_tail (htab, stub_entry, p, loc); + if (info->emitrelocations) { bfd_vma roff = relp - stub_entry->group->stub_sec->contents; @@ -11756,33 +11793,6 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) return FALSE; } } - - if (htab->params->power10_stubs == 0 - && htab->glink_eh_frame != NULL - && htab->glink_eh_frame->size != 0) - { - bfd_byte *base, *eh; - unsigned int lr_used, delta; - - base = (htab->glink_eh_frame->contents - + stub_entry->group->eh_base + 17); - eh = base + stub_entry->group->eh_size; - lr_used = stub_entry->stub_offset + 8; - if (stub_entry->stub_type == ppc_stub_long_branch_both - || stub_entry->stub_type == ppc_stub_plt_branch_both - || stub_entry->stub_type == ppc_stub_plt_call_both) - lr_used += 4; - delta = lr_used - stub_entry->group->lr_restore; - stub_entry->group->lr_restore = lr_used + 8; - eh = eh_advance (htab->elf.dynobj, eh, delta); - *eh++ = DW_CFA_register; - *eh++ = 65; - *eh++ = 12; - *eh++ = DW_CFA_advance_loc + 2; - *eh++ = DW_CFA_restore_extended; - *eh++ = 65; - stub_entry->group->eh_size = eh - base; - } break; case ppc_stub_plt_call: @@ -11851,12 +11861,20 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) r[0].r_offset += 2; r[0].r_addend = targ; } - if (stub_entry->h != NULL - && is_tls_get_addr (&stub_entry->h->elf, htab) - && htab->params->tls_get_addr_opt) - p = build_tls_get_addr_stub (htab, stub_entry, loc, off, r); - else - p = build_plt_stub (htab, stub_entry, loc, off, r); + p = loc; + obfd = htab->params->stub_bfd; + is_tga = (stub_entry->h != NULL + && is_tls_get_addr (&stub_entry->h->elf, htab) + && htab->params->tls_get_addr_opt); + if (is_tga) + { + p = build_tls_get_addr_head (htab, stub_entry, p); + if (r != NULL) + r[0].r_offset += p - loc; + } + p = build_plt_stub (htab, stub_entry, p, off, r); + if (is_tga) + p = build_tls_get_addr_tail (htab, stub_entry, p, loc); break; case ppc_stub_save_res: @@ -12152,11 +12170,18 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) case ppc_stub_plt_call_notoc: case ppc_stub_plt_call_both: - off = (stub_entry->stub_offset - + stub_entry->group->stub_sec->output_offset - + stub_entry->group->stub_sec->output_section->vma); + lr_used = 0; + if (is_tls_get_addr (&stub_entry->h->elf, htab) + && htab->params->tls_get_addr_opt) + { + lr_used += 7 * 4; + if (!htab->params->no_tls_get_addr_regsave) + lr_used += 11 * 4; + else if (stub_entry->stub_type == ppc_stub_plt_call_both) + lr_used += 2 * 4; + } if (stub_entry->stub_type == ppc_stub_plt_call_both) - off += 4; + lr_used += 4; targ = stub_entry->plt_ent->plt.offset & ~1; if (targ >= (bfd_vma) -2) abort (); @@ -12172,16 +12197,21 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) plt = htab->pltlocal; } targ += plt->output_offset + plt->output_section->vma; + off = (stub_entry->stub_offset + + stub_entry->group->stub_sec->output_offset + + stub_entry->group->stub_sec->output_section->vma + + lr_used); odd = off & 4; off = targ - off; if (htab->params->plt_stub_align != 0) { - unsigned pad = plt_stub_pad (htab, stub_entry, off); + unsigned pad = plt_stub_pad (htab, stub_entry, off, odd); stub_entry->group->stub_sec->size += pad; stub_entry->stub_offset = stub_entry->group->stub_sec->size; off -= pad; + odd ^= pad & 4; } if (info->emitrelocations) @@ -12195,15 +12225,13 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) stub_entry->group->stub_sec->flags |= SEC_RELOC; } - size = plt_stub_size (htab, stub_entry, off); + size = plt_stub_size (htab, stub_entry, off, odd); if (htab->params->power10_stubs == 0) { /* After the bcl, lr has been modified so we need to emit .eh_frame info saying the return address is in r12. */ - lr_used = stub_entry->stub_offset + 8; - if (stub_entry->stub_type == ppc_stub_plt_call_both) - lr_used += 4; + lr_used += stub_entry->stub_offset + 8; /* The eh_frame info will consist of a DW_CFA_advance_loc or variant, DW_CFA_register, 65, 12, DW_CFA_advance_loc+2, DW_CFA_restore_extended 65. */ @@ -12211,6 +12239,29 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) stub_entry->group->eh_size += eh_advance_size (delta) + 6; stub_entry->group->lr_restore = lr_used + 8; } + if ((stub_entry->stub_type == ppc_stub_plt_call_notoc + || stub_entry->stub_type == ppc_stub_plt_call_both) + && is_tls_get_addr (&stub_entry->h->elf, htab) + && htab->params->tls_get_addr_opt) + { + if (!htab->params->no_tls_get_addr_regsave) + { + unsigned int cfa_updt = stub_entry->stub_offset + 18 * 4; + delta = cfa_updt - stub_entry->group->lr_restore; + stub_entry->group->eh_size += eh_advance_size (delta); + stub_entry->group->eh_size += htab->opd_abi ? 36 : 35; + stub_entry->group->lr_restore + = stub_entry->stub_offset + size - 4; + } + else if (stub_entry->stub_type == ppc_stub_plt_call_both) + { + lr_used = stub_entry->stub_offset + size - 20; + delta = lr_used - stub_entry->group->lr_restore; + stub_entry->group->eh_size += eh_advance_size (delta) + 6; + stub_entry->group->lr_restore + = stub_entry->stub_offset + size - 4; + } + } break; case ppc_stub_plt_call: @@ -12236,7 +12287,7 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) if (htab->params->plt_stub_align != 0) { - unsigned pad = plt_stub_pad (htab, stub_entry, off); + unsigned pad = plt_stub_pad (htab, stub_entry, off, 0); stub_entry->group->stub_sec->size += pad; stub_entry->stub_offset = stub_entry->group->stub_sec->size; @@ -12253,14 +12304,22 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) stub_entry->group->stub_sec->flags |= SEC_RELOC; } - size = plt_stub_size (htab, stub_entry, off); + size = plt_stub_size (htab, stub_entry, off, 0); if (stub_entry->h != NULL && is_tls_get_addr (&stub_entry->h->elf, htab) && htab->params->tls_get_addr_opt && stub_entry->stub_type == ppc_stub_plt_call_r2save) { - if (htab->params->no_tls_get_addr_regsave) + if (!htab->params->no_tls_get_addr_regsave) + { + /* Adjustments to r1 need to be described. */ + unsigned int cfa_updt = stub_entry->stub_offset + 18 * 4; + delta = cfa_updt - stub_entry->group->lr_restore; + stub_entry->group->eh_size += eh_advance_size (delta); + stub_entry->group->eh_size += htab->opd_abi ? 36 : 35; + } + else { lr_used = stub_entry->stub_offset + size - 20; /* The eh_frame info will consist of a DW_CFA_advance_loc @@ -12269,15 +12328,7 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) delta = lr_used - stub_entry->group->lr_restore; stub_entry->group->eh_size += eh_advance_size (delta) + 6; } - else - { - /* Adjustments to r1 need to be described. */ - unsigned int cfa_updt = stub_entry->stub_offset + 18 * 4; - delta = cfa_updt - stub_entry->group->lr_restore; - stub_entry->group->eh_size += eh_advance_size (delta); - stub_entry->group->eh_size += htab->opd_abi ? 36 : 35; - } - stub_entry->group->lr_restore = size - 4; + stub_entry->group->lr_restore = stub_entry->stub_offset + size - 4; } break; @@ -15890,22 +15941,25 @@ ppc64_elf_relocate_section (bfd *output_bfd, addend = 0; reloc_dest = DEST_STUB; - if (((stub_entry->stub_type == ppc_stub_plt_call - && ALWAYS_EMIT_R2SAVE) - || stub_entry->stub_type == ppc_stub_plt_call_r2save - || stub_entry->stub_type == ppc_stub_plt_call_both) - && !(h != NULL - && is_tls_get_addr (&h->elf, htab) - && htab->params->tls_get_addr_opt) - && rel + 1 < relend - && rel[1].r_offset == rel->r_offset + 4 - && ELF64_R_TYPE (rel[1].r_info) == R_PPC64_TOCSAVE) - relocation += 4; - else if ((stub_entry->stub_type == ppc_stub_long_branch_both - || stub_entry->stub_type == ppc_stub_plt_branch_both - || stub_entry->stub_type == ppc_stub_plt_call_both) - && r_type == R_PPC64_REL24_NOTOC) - relocation += 4; + if ((((stub_entry->stub_type == ppc_stub_plt_call + && ALWAYS_EMIT_R2SAVE) + || stub_entry->stub_type == ppc_stub_plt_call_r2save + || stub_entry->stub_type == ppc_stub_plt_call_both) + && rel + 1 < relend + && rel[1].r_offset == rel->r_offset + 4 + && ELF64_R_TYPE (rel[1].r_info) == R_PPC64_TOCSAVE) + || ((stub_entry->stub_type == ppc_stub_long_branch_both + || stub_entry->stub_type == ppc_stub_plt_branch_both + || stub_entry->stub_type == ppc_stub_plt_call_both) + && r_type == R_PPC64_REL24_NOTOC)) + { + /* Skip over the r2 store at the start of the stub. */ + if (!(stub_entry->stub_type >= ppc_stub_plt_call + && htab->params->tls_get_addr_opt + && h != NULL + && is_tls_get_addr (&h->elf, htab))) + relocation += 4; + } if (r_type == R_PPC64_REL24_NOTOC && (stub_entry->stub_type == ppc_stub_plt_call_notoc -- Alan Modra Australia Development Lab, IBM