mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2025-01-30 12:44:10 +08:00
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:
parent
c94053440e
commit
294338867c
@ -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
|
||||
|
424
bfd/elf64-ppc.c
424
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)
|
||||
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user