* elf64-ppc.c (ha_reloc_match): Allow matches to other than r2.

(ppc64_elf_relocate_section): Nop out high part insn of large toc
	code sequence when the high part of offset is zero.
This commit is contained in:
Alan Modra 2010-08-05 14:37:30 +00:00
parent 50e8a0d53b
commit d983b7a0c3
2 changed files with 61 additions and 10 deletions

View File

@ -1,3 +1,9 @@
2010-08-06 Alan Modra <amodra@gmail.com>
* elf64-ppc.c (ha_reloc_match): Allow matches to other than r2.
(ppc64_elf_relocate_section): Nop out high part insn of large toc
code sequence when the high part of offset is zero.
2010-08-04 Tristan Gingold <gingold@adacore.com>
* vms-alpha.c (alpha_vms_build_fixups): Write the EICP.

View File

@ -11397,12 +11397,14 @@ ppc64_elf_action_discarded (asection *sec)
/* REL points to a low-part reloc on a largetoc instruction sequence.
Find the matching high-part reloc instruction and verify that it
is addis REG,r2,x. If so, return a pointer to the high-part reloc. */
is addis REG,x,imm. If so, set *REG to x and return a pointer to
the high-part reloc. */
static const Elf_Internal_Rela *
ha_reloc_match (const Elf_Internal_Rela *relocs,
const Elf_Internal_Rela *rel,
unsigned int reg,
unsigned int *reg,
bfd_boolean match_addend,
const bfd *input_bfd,
const bfd_byte *contents)
{
@ -11434,14 +11436,17 @@ ha_reloc_match (const Elf_Internal_Rela *relocs,
while (--rel >= relocs)
if (rel->r_info == r_info_ha
&& rel->r_addend == r_addend)
&& (!match_addend
|| rel->r_addend == r_addend))
{
const bfd_byte *p = contents + (rel->r_offset & ~3);
unsigned int insn = bfd_get_32 (input_bfd, p);
if ((insn & ((0x3f << 26) | (0x1f << 16)))
== ((15u << 26) | (2 << 16)) /* addis rt,r2,x */
&& (insn & (0x1f << 21)) == (reg << 21))
return rel;
if ((insn & (0x3f << 26)) == (15u << 26) /* addis rt,x,imm */
&& (insn & (0x1f << 21)) == (*reg << 21))
{
*reg = (insn >> 16) & 0x1f;
return rel;
}
break;
}
return NULL;
@ -11494,7 +11499,9 @@ ppc64_elf_relocate_section (bfd *output_bfd,
Elf_Internal_Rela outrel;
bfd_byte *loc;
struct got_entry **local_got_ents;
unsigned char *ha_opt;
bfd_vma TOCstart;
bfd_boolean no_ha_opt;
bfd_boolean ret = TRUE;
bfd_boolean is_opd;
/* Disabled until we sort out how ld should choose 'y' vs 'at'. */
@ -11520,6 +11527,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
symtab_hdr = &elf_symtab_hdr (input_bfd);
sym_hashes = elf_sym_hashes (input_bfd);
is_opd = ppc64_elf_section_data (input_section)->sec_type == sec_opd;
ha_opt = NULL;
no_ha_opt = FALSE;
rel = relocs;
relend = relocs + input_section->reloc_count;
@ -12945,7 +12954,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
case R_PPC64_GOT_DTPREL16_HA:
case R_PPC64_GOT16_HA:
case R_PPC64_TOC16_HA:
/* For now we don't nop out the first instruction. */
/* nop is done later. */
break;
case R_PPC64_GOT_TLSLD16_LO:
@ -12980,12 +12989,31 @@ ppc64_elf_relocate_section (bfd *output_bfd,
&& ((insn & 3) == 0 || (insn & 3) == 3)))
{
unsigned int reg = (insn >> 16) & 0x1f;
if (ha_reloc_match (relocs, rel, reg, input_bfd, contents))
const Elf_Internal_Rela *ha;
bfd_boolean match_addend;
match_addend = (sym != NULL
&& ELF_ST_TYPE (sym->st_info) == STT_SECTION);
ha = ha_reloc_match (relocs, rel, &reg, match_addend,
input_bfd, contents);
if (ha != NULL)
{
insn &= ~(0x1f << 16);
insn |= 2 << 16;
insn |= reg << 16;
bfd_put_32 (input_bfd, insn, p);
if (ha_opt == NULL)
{
ha_opt = bfd_zmalloc (input_section->reloc_count);
if (ha_opt == NULL)
return FALSE;
}
ha_opt[ha - relocs] = 1;
}
else
/* If we don't find a matching high part insn,
something is fishy. Refuse to nop any high
part insn in this section. */
no_ha_opt = TRUE;
}
}
break;
@ -13143,6 +13171,23 @@ ppc64_elf_relocate_section (bfd *output_bfd,
}
}
if (ha_opt != NULL)
{
if (!no_ha_opt)
{
unsigned char *opt = ha_opt;
rel = relocs;
relend = relocs + input_section->reloc_count;
for (; rel < relend; opt++, rel++)
if (*opt != 0)
{
bfd_byte *p = contents + (rel->r_offset & ~3);
bfd_put_32 (input_bfd, NOP, p);
}
}
free (ha_opt);
}
/* If we're emitting relocations, then shortly after this function
returns, reloc offsets and addends for this section will be
adjusted. Worse, reloc symbol indices will be for the output