* elf64-ppc.c (struct ppc64_elf_obj_tdata): Rename
	ha_relocs_not_using_r2 to unexpected_toc_insn.
	(ok_lo_toc_insn): New function.
	(ppc64_elf_edit_toc): Check insn on lo toc reloc.  Emit warning.
	(ppc64_elf_relocate_section): Don't check insn on lo toc reloc here.
	Handle addic on lo toc reloc.
ld/testsuite/
	* ld-powerpc/powerpc.exp: Expect ld warnings for tocopt test.
	* ld-powerpc/tocopt.out: New file.
This commit is contained in:
Alan Modra 2011-11-08 13:06:03 +00:00
parent d3895d7d29
commit 560c8763d3
5 changed files with 100 additions and 39 deletions

View File

@ -1,3 +1,12 @@
2011-11-08 Alan Modra <amodra@gmail.com>
* elf64-ppc.c (struct ppc64_elf_obj_tdata): Rename
ha_relocs_not_using_r2 to unexpected_toc_insn.
(ok_lo_toc_insn): New function.
(ppc64_elf_edit_toc): Check insn on lo toc reloc. Emit warning.
(ppc64_elf_relocate_section): Don't check insn on lo toc reloc here.
Handle addic on lo toc reloc.
2011-11-06 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
PR ld/13387

View File

@ -2614,8 +2614,9 @@ struct ppc64_elf_obj_tdata
the reloc to be in the range -32768 to 32767. */
unsigned int has_small_toc_reloc : 1;
/* Set if toc/got ha relocs detected not using r2. */
unsigned int ha_relocs_not_using_r2 : 1;
/* Set if toc/got ha relocs detected not using r2, or lo reloc
instruction not one we handle. */
unsigned int unexpected_toc_insn : 1;
};
#define ppc64_elf_tdata(bfd) \
@ -8016,6 +8017,32 @@ adjust_toc_syms (struct elf_link_hash_entry *h, void *inf)
return TRUE;
}
/* Return TRUE iff INSN is one we expect on a _LO variety toc/got reloc. */
static bfd_boolean
ok_lo_toc_insn (unsigned int insn)
{
return ((insn & (0x3f << 26)) == 14u << 26 /* addi */
|| (insn & (0x3f << 26)) == 32u << 26 /* lwz */
|| (insn & (0x3f << 26)) == 34u << 26 /* lbz */
|| (insn & (0x3f << 26)) == 36u << 26 /* stw */
|| (insn & (0x3f << 26)) == 38u << 26 /* stb */
|| (insn & (0x3f << 26)) == 40u << 26 /* lhz */
|| (insn & (0x3f << 26)) == 42u << 26 /* lha */
|| (insn & (0x3f << 26)) == 44u << 26 /* sth */
|| (insn & (0x3f << 26)) == 46u << 26 /* lmw */
|| (insn & (0x3f << 26)) == 47u << 26 /* stmw */
|| (insn & (0x3f << 26)) == 48u << 26 /* lfs */
|| (insn & (0x3f << 26)) == 50u << 26 /* lfd */
|| (insn & (0x3f << 26)) == 52u << 26 /* stfs */
|| (insn & (0x3f << 26)) == 54u << 26 /* stfd */
|| ((insn & (0x3f << 26)) == 58u << 26 /* lwa,ld,lmd */
&& (insn & 3) != 1)
|| ((insn & (0x3f << 26)) == 62u << 26 /* std, stmd */
&& ((insn & 3) == 0 || (insn & 3) == 3))
|| (insn & (0x3f << 26)) == 12u << 26 /* addic */);
}
/* Examine all relocs referencing .toc sections in order to remove
unused .toc entries. */
@ -8270,11 +8297,13 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
struct elf_link_hash_entry *h;
Elf_Internal_Sym *sym;
bfd_vma val;
enum {no_check, check_lo, check_ha} insn_check;
r_type = ELF64_R_TYPE (rel->r_info);
switch (r_type)
{
default:
insn_check = no_check;
break;
case R_PPC64_GOT_TLSLD16_HA:
@ -8283,22 +8312,47 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
case R_PPC64_GOT_DTPREL16_HA:
case R_PPC64_GOT16_HA:
case R_PPC64_TOC16_HA:
{
bfd_vma off = rel->r_offset & ~3;
unsigned char buf[4];
unsigned int insn;
if (!bfd_get_section_contents (ibfd, sec, buf, off, 4))
{
free (used);
goto error_ret;
}
insn = bfd_get_32 (ibfd, buf);
if ((insn & ((0x3f << 26) | 0x1f << 16))
!= ((15u << 26) | (2 << 16)) /* addis rt,2,imm */)
ppc64_elf_tdata (ibfd)->ha_relocs_not_using_r2 = 1;
}
insn_check = check_ha;
break;
case R_PPC64_GOT_TLSLD16_LO:
case R_PPC64_GOT_TLSGD16_LO:
case R_PPC64_GOT_TPREL16_LO_DS:
case R_PPC64_GOT_DTPREL16_LO_DS:
case R_PPC64_GOT16_LO:
case R_PPC64_GOT16_LO_DS:
case R_PPC64_TOC16_LO:
case R_PPC64_TOC16_LO_DS:
insn_check = check_lo;
break;
}
if (insn_check != no_check)
{
bfd_vma off = rel->r_offset & ~3;
unsigned char buf[4];
unsigned int insn;
if (!bfd_get_section_contents (ibfd, sec, buf, off, 4))
{
free (used);
goto error_ret;
}
insn = bfd_get_32 (ibfd, buf);
if (insn_check == check_lo
? !ok_lo_toc_insn (insn)
: ((insn & ((0x3f << 26) | 0x1f << 16))
!= ((15u << 26) | (2 << 16)) /* addis rt,2,imm */))
{
char str[12];
ppc64_elf_tdata (ibfd)->unexpected_toc_insn = 1;
sprintf (str, "%#08x", insn);
info->callbacks->einfo
(_("%P: %H: toc optimization is not supported for"
" %s instruction.\n"),
ibfd, sec, rel->r_offset & ~3, str);
}
}
switch (r_type)
@ -13322,7 +13376,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
case R_PPC64_GOT16_HA:
case R_PPC64_TOC16_HA:
if (htab->do_toc_opt && relocation + addend + 0x8000 < 0x10000
&& !ppc64_elf_tdata (input_bfd)->ha_relocs_not_using_r2)
&& !ppc64_elf_tdata (input_bfd)->unexpected_toc_insn)
{
bfd_byte *p = contents + (rel->r_offset & ~3);
bfd_put_32 (input_bfd, NOP, p);
@ -13338,33 +13392,22 @@ ppc64_elf_relocate_section (bfd *output_bfd,
case R_PPC64_TOC16_LO:
case R_PPC64_TOC16_LO_DS:
if (htab->do_toc_opt && relocation + addend + 0x8000 < 0x10000
&& !ppc64_elf_tdata (input_bfd)->ha_relocs_not_using_r2)
&& !ppc64_elf_tdata (input_bfd)->unexpected_toc_insn)
{
bfd_byte *p = contents + (rel->r_offset & ~3);
insn = bfd_get_32 (input_bfd, p);
if ((insn & (0x3f << 26)) == 14u << 26 /* addi */
|| (insn & (0x3f << 26)) == 32u << 26 /* lwz */
|| (insn & (0x3f << 26)) == 34u << 26 /* lbz */
|| (insn & (0x3f << 26)) == 36u << 26 /* stw */
|| (insn & (0x3f << 26)) == 38u << 26 /* stb */
|| (insn & (0x3f << 26)) == 40u << 26 /* lhz */
|| (insn & (0x3f << 26)) == 42u << 26 /* lha */
|| (insn & (0x3f << 26)) == 44u << 26 /* sth */
|| (insn & (0x3f << 26)) == 46u << 26 /* lmw */
|| (insn & (0x3f << 26)) == 47u << 26 /* stmw */
|| (insn & (0x3f << 26)) == 48u << 26 /* lfs */
|| (insn & (0x3f << 26)) == 50u << 26 /* lfd */
|| (insn & (0x3f << 26)) == 52u << 26 /* stfs */
|| (insn & (0x3f << 26)) == 54u << 26 /* stfd */
|| ((insn & (0x3f << 26)) == 58u << 26 /* lwa,ld,lmd */
&& (insn & 3) != 1)
|| ((insn & (0x3f << 26)) == 62u << 26 /* std, stmd */
&& ((insn & 3) == 0 || (insn & 3) == 3)))
if ((insn & (0x3f << 26)) == 12u << 26 /* addic */)
{
/* Transform addic to addi when we change reg. */
insn &= ~((0x3f << 26) | (0x1f << 16));
insn |= (14u << 26) | (2 << 16);
}
else
{
insn &= ~(0x1f << 16);
insn |= 2 << 16;
bfd_put_32 (input_bfd, insn, p);
}
bfd_put_32 (input_bfd, insn, p);
}
break;
}

View File

@ -1,3 +1,8 @@
2011-11-08 Alan Modra <amodra@gmail.com>
* ld-powerpc/powerpc.exp: Expect ld warnings for tocopt test.
* ld-powerpc/tocopt.out: New file.
2011-10-25 Joern Rennecke <joern.rennecke@embecosm.com>
* ld-srec/srec.exp: xfail epiphany.

View File

@ -204,7 +204,7 @@ set ppc64elftests {
{"sym@tocbase" "-shared -melf64ppc" "-a64" {symtocbase-1.s symtocbase-2.s}
{{objdump -dj.data symtocbase.d}} "symtocbase.so"}
{"TOC opt" "-melf64ppc" "-a64" {tocopt.s}
{{objdump -s tocopt.d}} "tocopt"}
{{ld tocopt.out} {objdump -s tocopt.d}} "tocopt"}
{"TOC opt2" "-melf64ppc --defsym x=2" "-a64" {tocopt2.s}
{{ld tocopt2.out} {objdump -s tocopt2.d}} "tocopt2"}
{"TOC opt3" "-melf64ppc -no-keep-memory --defsym x=2" "-a64" {tocopt3.s}

View File

@ -0,0 +1,4 @@
.*
\(\.text\+0x14\): .* 0x3fa00000 .*
.*
\(\.text\+0x34\): .* 0x3fa00010 .*