aboutsummaryrefslogtreecommitdiff
path: root/bfd
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2020-09-22 22:51:42 +0930
committerAlan Modra <amodra@gmail.com>2020-09-24 07:54:05 +0930
commit294338867c268b6da43327b6cbe70e746bff1a04 (patch)
tree5a92aab3be8a1fcc30d2778739111b09d2146a2c /bfd
parentc94053440e29421dd8846530da73f09c9ede2e0f (diff)
downloadgdb-294338867c268b6da43327b6cbe70e746bff1a04.zip
gdb-294338867c268b6da43327b6cbe70e746bff1a04.tar.gz
gdb-294338867c268b6da43327b6cbe70e746bff1a04.tar.bz2
PR26656, power10 libstdc++.so segfault in __cxxabiv1::__cxa_throw
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.
Diffstat (limited to 'bfd')
-rw-r--r--bfd/ChangeLog20
-rw-r--r--bfd/elf64-ppc.c424
2 files changed, 259 insertions, 185 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 39e5ead..f642403 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,5 +1,25 @@
2020-09-24 Alan Modra <amodra@gmail.com>
+ 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.
+
+2020-09-24 Alan Modra <amodra@gmail.com>
+
PR 26655
* elf64-ppc.c (ppc64_elf_func_desc_adjust): Rename to..
(ppc64_elf_edit): Call params->edit.
diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
index 4d16dc3..320717c 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