int tls_type;
struct _ppc64_elf_section_data *ppc64_sec;
struct plt_entry **ifunc, **plt_list;
- bfd_vma sym_addend;
r_symndx = ELF64_R_SYM (rel->r_info);
if (r_symndx < symtab_hdr->sh_info)
case R_PPC64_D28:
case R_PPC64_TPREL34:
case R_PPC64_DTPREL34:
- htab->powerxx_stubs = 1;
- /* Fall through. */
- default:
- /* Somewhat foolishly, because the ABIs don't specifically
- allow it, ppc64 gas and ld support GOT and PLT relocs
- with non-zero addends where the addend results in
- sym+addend being stored in the GOT or PLT entry. This
- can't be supported for pcrel relocs because the addend is
- used to specify the pcrel offset. */
- sym_addend = rel->r_addend;
- break;
-
case R_PPC64_PCREL34:
case R_PPC64_GOT_PCREL34:
case R_PPC64_GOT_TLSGD34:
case R_PPC64_PLT_PCREL34_NOTOC:
case R_PPC64_PCREL28:
htab->powerxx_stubs = 1;
- sym_addend = 0;
+ break;
+ default:
break;
}
if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
{
ifunc = update_local_sym_info (abfd, symtab_hdr, r_symndx,
- sym_addend,
+ rel->r_addend,
NON_GOT | PLT_IFUNC);
if (ifunc == NULL)
return FALSE;
((struct ppc_link_hash_entry *) h)->tls_mask |= TLS_TLS | TLS_MARK;
else
if (!update_local_sym_info (abfd, symtab_hdr, r_symndx,
- sym_addend,
+ rel->r_addend,
NON_GOT | TLS_TLS | TLS_MARK))
return FALSE;
sec->has_tls_reloc = 1;
eh = (struct ppc_link_hash_entry *) h;
for (ent = eh->elf.got.glist; ent != NULL; ent = ent->next)
- if (ent->addend == sym_addend
+ if (ent->addend == rel->r_addend
&& ent->owner == abfd
&& ent->tls_type == tls_type)
break;
if (ent == NULL)
return FALSE;
ent->next = eh->elf.got.glist;
- ent->addend = sym_addend;
+ ent->addend = rel->r_addend;
ent->owner = abfd;
ent->tls_type = tls_type;
ent->is_indirect = FALSE;
else
/* This is a global offset table entry for a local symbol. */
if (!update_local_sym_info (abfd, symtab_hdr, r_symndx,
- sym_addend, tls_type))
+ rel->r_addend, tls_type))
return FALSE;
/* We may also need a plt entry if the symbol turns out to be
an ifunc. */
if (h != NULL && !bfd_link_pic (info) && abiversion (abfd) != 1)
{
- if (!update_plt_info (abfd, &h->plt.plist, sym_addend))
+ if (!update_plt_info (abfd, &h->plt.plist, rel->r_addend))
return FALSE;
}
break;
}
if (plt_list == NULL)
plt_list = update_local_sym_info (abfd, symtab_hdr, r_symndx,
- sym_addend,
+ rel->r_addend,
NON_GOT | PLT_KEEP);
- if (!update_plt_info (abfd, plt_list, sym_addend))
+ if (!update_plt_info (abfd, plt_list, rel->r_addend))
return FALSE;
break;
/* We may need a .plt entry if the function this reloc
refers to is in a shared lib. */
if (plt_list
- && !update_plt_info (abfd, plt_list, sym_addend))
+ && !update_plt_info (abfd, plt_list, rel->r_addend))
return FALSE;
break;
}
else
if (!update_local_sym_info (abfd, symtab_hdr, r_symndx,
- sym_addend, tls_type))
+ rel->r_addend, tls_type))
return FALSE;
ppc64_sec = ppc64_elf_section_data (sec);
}
BFD_ASSERT (rel->r_offset % 8 == 0);
ppc64_sec->u.toc.symndx[rel->r_offset / 8] = r_symndx;
- ppc64_sec->u.toc.add[rel->r_offset / 8] = sym_addend;
+ ppc64_sec->u.toc.add[rel->r_offset / 8] = rel->r_addend;
/* Mark the second slot of a GD or LD entry.
-1 to indicate GD and -2 to indicate LD. */
/* PCREL_OPT in one instance flags to the linker that a pair of insns:
pld ra,symbol@got@pcrel
- load/store rt,0(ra)
+ load/store rt,off(ra)
or
pla ra,symbol@pcrel
- load/store rt,0(ra)
+ load/store rt,off(ra)
may be translated to
- pload/pstore rt,symbol@pcrel
+ pload/pstore rt,symbol+off@pcrel
nop.
This function returns true if the optimization is possible, placing
- the prefix insn in *PINSN1 and a NOP in *PINSN2.
+ the prefix insn in *PINSN1, a NOP in *PINSN2 and the offset in *POFF.
On entry to this function, the linker has already determined that
the pld can be replaced with pla: *PINSN1 is that pla insn,
while *PINSN2 is the second instruction. */
static bfd_boolean
-xlate_pcrel_opt (uint64_t *pinsn1, uint64_t *pinsn2)
+xlate_pcrel_opt (uint64_t *pinsn1, uint64_t *pinsn2, bfd_signed_vma *poff)
{
- uint32_t insn2 = *pinsn2 >> 32;
- uint64_t i1new;
+ uint64_t insn1 = *pinsn1;
+ uint64_t insn2 = *pinsn2;
+ bfd_signed_vma off;
+
+ if ((insn2 & (63ULL << 58)) == 1ULL << 58)
+ {
+ /* Check that regs match. */
+ if (((insn2 >> 16) & 31) != ((insn1 >> 21) & 31))
+ return FALSE;
+
+ /* P8LS or PMLS form, non-pcrel. */
+ if ((insn2 & (-1ULL << 50) & ~(1ULL << 56)) != (1ULL << 58))
+ return FALSE;
+
+ *pinsn1 = (insn2 & ~(31 << 16) & ~0x3ffff0000ffffULL) | (1ULL << 52);
+ *pinsn2 = PNOP;
+ off = ((insn2 >> 16) & 0x3ffff0000ULL) | (insn2 & 0xffff);
+ *poff = (off ^ 0x200000000ULL) - 0x200000000ULL;
+ return TRUE;
+ }
+
+ insn2 >>= 32;
/* Check that regs match. */
- if (((insn2 >> 16) & 31) != ((*pinsn1 >> 21) & 31))
+ if (((insn2 >> 16) & 31) != ((insn1 >> 21) & 31))
return FALSE;
switch ((insn2 >> 26) & 63)
case 52: /* stfs */
case 54: /* stfd */
/* These are the PMLS cases, where we just need to tack a prefix
- on the insn. Check that the D field is zero. */
- if ((insn2 & 0xffff) != 0)
- return FALSE;
- i1new = ((1ULL << 58) | (2ULL << 56) | (1ULL << 52)
+ on the insn. */
+ insn1 = ((1ULL << 58) | (2ULL << 56) | (1ULL << 52)
| (insn2 & ((63ULL << 26) | (31ULL << 21))));
+ off = insn2 & 0xffff;
break;
case 58: /* lwa, ld */
- if ((insn2 & 0xfffd) != 0)
+ if ((insn2 & 1) != 0)
return FALSE;
- i1new = ((1ULL << 58) | (1ULL << 52)
+ insn1 = ((1ULL << 58) | (1ULL << 52)
| (insn2 & 2 ? 41ULL << 26 : 57ULL << 26)
| (insn2 & (31ULL << 21)));
+ off = insn2 & 0xfffc;
break;
case 57: /* lxsd, lxssp */
- if ((insn2 & 0xfffc) != 0 || (insn2 & 3) < 2)
+ if ((insn2 & 3) < 2)
return FALSE;
- i1new = ((1ULL << 58) | (1ULL << 52)
+ insn1 = ((1ULL << 58) | (1ULL << 52)
| ((40ULL | (insn2 & 3)) << 26)
| (insn2 & (31ULL << 21)));
+ off = insn2 & 0xfffc;
break;
case 61: /* stxsd, stxssp, lxv, stxv */
return FALSE;
else if ((insn2 & 3) >= 2)
{
- if ((insn2 & 0xfffc) != 0)
- return FALSE;
- i1new = ((1ULL << 58) | (1ULL << 52)
+ insn1 = ((1ULL << 58) | (1ULL << 52)
| ((44ULL | (insn2 & 3)) << 26)
| (insn2 & (31ULL << 21)));
+ off = insn2 & 0xfffc;
}
else
{
- if ((insn2 & 0xfff0) != 0)
- return FALSE;
- i1new = ((1ULL << 58) | (1ULL << 52)
+ insn1 = ((1ULL << 58) | (1ULL << 52)
| ((50ULL | (insn2 & 4) | ((insn2 & 8) >> 3)) << 26)
| (insn2 & (31ULL << 21)));
+ off = insn2 & 0xfff0;
}
break;
case 56: /* lq */
- if ((insn2 & 0xffff) != 0)
- return FALSE;
- i1new = ((1ULL << 58) | (1ULL << 52)
+ insn1 = ((1ULL << 58) | (1ULL << 52)
| (insn2 & ((63ULL << 26) | (31ULL << 21))));
+ off = insn2 & 0xffff;
break;
case 62: /* std, stq */
- if ((insn2 & 0xfffd) != 0)
+ if ((insn2 & 1) != 0)
return FALSE;
- i1new = ((1ULL << 58) | (1ULL << 52)
+ insn1 = ((1ULL << 58) | (1ULL << 52)
| ((insn2 & 2) == 0 ? 61ULL << 26 : 60ULL << 26)
| (insn2 & (31ULL << 21)));
+ off = insn2 & 0xfffc;
break;
}
- *pinsn1 = i1new;
+ *pinsn1 = insn1;
*pinsn2 = (uint64_t) NOP << 32;
+ *poff = (off ^ 0x8000) - 0x8000;
return TRUE;
}
asection *sym_sec;
struct elf_link_hash_entry *h;
struct got_entry *ent;
- bfd_vma sym_addend, val, pc;
+ bfd_vma val, pc;
unsigned char buf[8];
unsigned int insn;
enum {no_check, check_lo, check_ha} insn_check;
case R_PPC64_GOT16_HA:
case R_PPC64_GOT16_LO_DS:
- sym_addend = rel->r_addend;
- break;
-
case R_PPC64_GOT_PCREL34:
- sym_addend = 0;
break;
}
r_symndx, ibfd))
goto got_error_ret;
+ if (sym_sec == NULL
+ || sym_sec->output_section == NULL
+ || discarded_section (sym_sec))
+ continue;
+
if (!SYMBOL_REFERENCES_LOCAL (info, h))
continue;
val = h->root.u.def.value;
else
val = sym->st_value;
- val += sym_addend;
+ val += rel->r_addend;
val += sym_sec->output_section->vma + sym_sec->output_offset;
/* Fudge factor to allow for the fact that the preliminary layout
ent = local_got_ents[r_symndx];
}
for (; ent != NULL; ent = ent->next)
- if (ent->addend == sym_addend
+ if (ent->addend == rel->r_addend
&& ent->owner == ibfd
&& ent->tls_type == 0)
break;
if (off2 + 4 <= input_section->size)
{
uint64_t pinsn2;
+ bfd_signed_vma addend_off;
pinsn2 = bfd_get_32 (input_bfd, contents + off2);
pinsn2 <<= 32;
if ((pinsn2 & (63ULL << 58)) == 1ULL << 58)
- break;
- if (xlate_pcrel_opt (&pinsn, &pinsn2))
{
+ if (off2 + 8 > input_section->size)
+ break;
+ pinsn2 |= bfd_get_32 (input_bfd,
+ contents + off2 + 4);
+ }
+ if (xlate_pcrel_opt (&pinsn, &pinsn2, &addend_off))
+ {
+ addend += addend_off;
+ rel->r_addend = addend;
bfd_put_32 (input_bfd, pinsn >> 32,
contents + offset);
bfd_put_32 (input_bfd, pinsn,
contents + offset + 4);
bfd_put_32 (input_bfd, pinsn2 >> 32,
contents + off2);
+ if ((pinsn2 & (63ULL << 58)) == 1ULL << 58)
+ bfd_put_32 (input_bfd, pinsn2,
+ contents + off2 + 4);
}
}
}
break;
}
- /* Set `addend'. */
tls_type = 0;
save_unresolved_reloc = unresolved_reloc;
switch (r_type)
bfd_vma off;
unsigned long indx = 0;
struct got_entry *ent;
- bfd_vma sym_addend = orig_rel.r_addend;
-
- if (r_type == R_PPC64_GOT_PCREL34
- || r_type == R_PPC64_GOT_TLSGD34
- || r_type == R_PPC64_GOT_TLSLD34
- || r_type == R_PPC64_GOT_TPREL34
- || r_type == R_PPC64_GOT_DTPREL34)
- sym_addend = 0;
if (tls_type == (TLS_TLS | TLS_LD)
&& (h == NULL
}
for (; ent != NULL; ent = ent->next)
- if (ent->addend == sym_addend
+ if (ent->addend == orig_rel.r_addend
&& ent->owner == input_bfd
&& ent->tls_type == tls_type)
break;
outrel.r_offset = (got->output_section->vma
+ got->output_offset
+ off);
- outrel.r_addend = sym_addend;
+ outrel.r_addend = orig_rel.r_addend;
if (tls_type & (TLS_LD | TLS_GD))
{
outrel.r_addend = 0;
bfd_elf64_swap_reloca_out (output_bfd,
&outrel, loc);
outrel.r_offset += 8;
- outrel.r_addend = sym_addend;
+ outrel.r_addend = orig_rel.r_addend;
outrel.r_info
= ELF64_R_INFO (indx, R_PPC64_DTPREL64);
}
emitting a reloc. */
else
{
- relocation += sym_addend;
+ relocation += orig_rel.r_addend;
if (tls_type != 0)
{
if (htab->elf.tls_sec == NULL)
abort ();
relocation = got->output_section->vma + got->output_offset + off;
+ addend = 0;
if (!(r_type == R_PPC64_GOT_PCREL34
|| r_type == R_PPC64_GOT_TLSGD34
|| r_type == R_PPC64_GOT_TLSLD34
if (plt_list)
{
struct plt_entry *ent;
- bfd_vma sym_addend = orig_rel.r_addend;
-
- if (r_type == R_PPC64_PLT_PCREL34
- || r_type == R_PPC64_PLT_PCREL34_NOTOC)
- sym_addend = 0;
for (ent = *plt_list; ent != NULL; ent = ent->next)
if (ent->plt.offset != (bfd_vma) -1
- && ent->addend == sym_addend)
+ && ent->addend == orig_rel.r_addend)
{
asection *plt;
bfd_vma got;
+ htab->sec_info[input_section->id].toc_off);
relocation -= got;
}
- if (r_type != R_PPC64_PLT_PCREL34
- && r_type != R_PPC64_PLT_PCREL34_NOTOC)
- addend = 0;
+ addend = 0;
unresolved_reloc = FALSE;
break;
}