#define ADD_3_12_2 0x7c6c1214
#define ADD_11_0_11 0x7d605a14
#define B 0x48000000
+#define BA 0x48000002
#define BCL_20_31 0x429f0005
#define BCTR 0x4e800420
#define BEQLR 0x4d820020
ppc_elf_link_hash_table_create (bfd *abfd)
{
struct ppc_elf_link_hash_table *ret;
- static struct ppc_elf_params default_params = { PLT_OLD, 0, 1, 0, 0, 4096 };
+ static struct ppc_elf_params default_params = { PLT_OLD, 0, 1, 0, 0, 12 };
ret = bfd_zmalloc (sizeof (struct ppc_elf_link_hash_table));
if (ret == NULL)
p += 4;
bfd_put_32 (output_bfd, BCTR, p);
p += 4;
- bfd_put_32 (output_bfd, NOP, p);
+ bfd_put_32 (output_bfd, htab->params->ppc476_workaround ? BA : NOP, p);
p += 4;
}
else
p += htab->glink_pltresolve;
endp = htab->glink->contents;
endp += htab->glink->size - GLINK_PLTRESOLVE;
- while (p < endp - 8 * 4)
+ while (p < endp - (htab->params->ppc476_workaround ? 0 : 8 * 4))
{
bfd_put_32 (output_bfd, B + endp - p, p);
p += 4;
+ htab->glink->output_section->vma
+ htab->glink->output_offset);
+ if (htab->params->ppc476_workaround)
+ {
+ /* Ensure that a call stub at the end of a page doesn't
+ result in prefetch over the end of the page into the
+ glink branch table. */
+ bfd_vma pagesize = (bfd_vma) 1 << htab->params->pagesize_p2;
+ bfd_vma page_addr;
+ bfd_vma glink_start = (htab->glink->output_section->vma
+ + htab->glink->output_offset);
+
+ for (page_addr = res0 & -pagesize;
+ page_addr > glink_start;
+ page_addr -= pagesize)
+ {
+ /* We have a plt call stub that may need fixing. */
+ bfd_byte *loc;
+ unsigned int insn;
+
+ loc = htab->glink->contents + page_addr - 4 - glink_start;
+ insn = bfd_get_32 (output_bfd, loc);
+ if (insn == BCTR)
+ {
+ /* By alignment, we know that there must be at least
+ one other call stub before this one. */
+ insn = bfd_get_32 (output_bfd, loc - 16);
+ if (insn == BCTR)
+ bfd_put_32 (output_bfd, B | (-16 & 0x3fffffc), loc);
+ else
+ bfd_put_32 (output_bfd, B | (-20 & 0x3fffffc), loc);
+ }
+ }
+ }
+
/* Last comes the PLTresolve stub. */
if (info->shared)
{
for (i = 0; i < ARRAY_SIZE (pic_plt_resolve); i++)
{
- bfd_put_32 (output_bfd, pic_plt_resolve[i], p);
+ unsigned int insn = pic_plt_resolve[i];
+
+ if (htab->params->ppc476_workaround && insn == NOP)
+ insn = BA + 0;
+ bfd_put_32 (output_bfd, insn, p);
p += 4;
}
p -= 4 * ARRAY_SIZE (pic_plt_resolve);
{
for (i = 0; i < ARRAY_SIZE (plt_resolve); i++)
{
- bfd_put_32 (output_bfd, plt_resolve[i], p);
+ unsigned int insn = plt_resolve[i];
+
+ if (htab->params->ppc476_workaround && insn == NOP)
+ insn = BA + 0;
+ bfd_put_32 (output_bfd, insn, p);
p += 4;
}
p -= 4 * ARRAY_SIZE (plt_resolve);