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.
This commit is contained in:
Alan Modra 2020-09-22 22:51:42 +09:30
parent c94053440e
commit 294338867c
2 changed files with 259 additions and 185 deletions

View File

@ -1,3 +1,23 @@
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

View File

@ -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)
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
{
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