aboutsummaryrefslogtreecommitdiff
path: root/bfd/elf32-ppc.c
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2014-04-14 11:48:06 +0930
committerAlan Modra <amodra@gmail.com>2014-04-14 18:17:13 +0930
commitda3a208854095a3e11d592aed2efdabe7c73ae11 (patch)
treece8dc467f3d0ed9a30272c6d16d0a63118af798f /bfd/elf32-ppc.c
parentf87121158599eb6f6463092ecad0a988d3e3cd75 (diff)
downloadgdb-da3a208854095a3e11d592aed2efdabe7c73ae11.zip
gdb-da3a208854095a3e11d592aed2efdabe7c73ae11.tar.gz
gdb-da3a208854095a3e11d592aed2efdabe7c73ae11.tar.bz2
ppc476 plt call stubs
Fuss over bctr in call stubs. * elf32-ppc.c (BA): Define (ppc_elf_link_hash_table_create): Correct default_params. (write_glink_stub): Pad small plt call stub with "ba 0" rather than "nop" for ppc476_workaround. (ppc_elf_finish_dynamic_sections): Likewise for branch table and __glink_PLTresolve. Ensure plt call stub at end of page doesn't allow fall-thru prefetch.
Diffstat (limited to 'bfd/elf32-ppc.c')
-rw-r--r--bfd/elf32-ppc.c52
1 files changed, 47 insertions, 5 deletions
diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c
index 61e94a0..8492732 100644
--- a/bfd/elf32-ppc.c
+++ b/bfd/elf32-ppc.c
@@ -147,6 +147,7 @@ static const bfd_vma ppc_elf_vxworks_pic_plt0_entry
#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
@@ -3249,7 +3250,7 @@ static struct bfd_link_hash_table *
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)
@@ -7336,7 +7337,7 @@ write_glink_stub (struct plt_entry *ent, asection *plt_sec, unsigned char *p,
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
@@ -10115,7 +10116,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
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;
@@ -10130,6 +10131,39 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
+ 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)
{
@@ -10137,7 +10171,11 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
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);
@@ -10171,7 +10209,11 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
{
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);