* elf64-ppc.c (ppc64_elf_relocate_section): Combine handling of

long branch stubs with code handling plt and r2off branch stubs.
This commit is contained in:
Alan Modra 2004-08-09 05:12:14 +00:00
parent ccfa59eaa0
commit b25116a9c7
2 changed files with 78 additions and 78 deletions

View File

@ -1,3 +1,8 @@
2004-08-09 Alan Modra <amodra@bigpond.net.au>
* elf64-ppc.c (ppc64_elf_relocate_section): Combine handling of
long branch stubs with code handling plt and r2off branch stubs.
2004-08-09 Alan Modra <amodra@bigpond.net.au>
* elf-bfd.h (_bfd_elf_gc_mark): Declare.
@ -10,6 +15,7 @@
(ppc64_elf_mark_entry_syms): Delete.
(ppc64_elf_gc_mark_hook): Mark entry syms here. Also mark opd
sections. Use get_opd_info.
* elf64-ppc.h (ppc64_elf_mark_entry_syms): Delete.
2004-08-09 Alan Modra <amodra@bigpond.net.au>

View File

@ -7863,6 +7863,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
/* Handle other relocations that tweak non-addend part of insn. */
insn = 0;
max_br_offset = 1 << 25;
addend = rel->r_addend;
switch (r_type)
{
default:
@ -7879,31 +7881,11 @@ ppc64_elf_relocate_section (bfd *output_bfd,
case R_PPC64_REL14_BRNTAKEN:
insn |= bfd_get_32 (output_bfd,
contents + rel->r_offset) & ~(0x01 << 21);
if (is_power4)
{
/* Set 'a' bit. This is 0b00010 in BO field for branch
on CR(BI) insns (BO == 001at or 011at), and 0b01000
for branch on CTR insns (BO == 1a00t or 1a01t). */
if ((insn & (0x14 << 21)) == (0x04 << 21))
insn |= 0x02 << 21;
else if ((insn & (0x14 << 21)) == (0x10 << 21))
insn |= 0x08 << 21;
else
break;
}
else
{
from = (rel->r_offset
+ input_section->output_offset
+ input_section->output_section->vma);
/* Fall thru. */
/* Invert 'y' bit if not the default. */
if ((bfd_signed_vma) (relocation + rel->r_addend - from) < 0)
insn ^= 0x01 << 21;
}
bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
break;
case R_PPC64_REL14:
max_br_offset = 1 << 15;
/* Fall thru. */
case R_PPC64_REL24:
/* Calls to functions with a different TOC, such as calls to
@ -7912,11 +7894,13 @@ ppc64_elf_relocate_section (bfd *output_bfd,
linkage stubs needs to be followed by a nop, as the nop
will be replaced with an instruction to restore the TOC
base pointer. */
stub_entry = NULL;
if (((h != NULL
&& (fdh = &((struct ppc_link_hash_entry *) h)->oh->elf) != NULL
&& fdh->plt.plist != NULL)
|| ((fdh = h, sec) != NULL
&& sec->output_section != NULL
&& sec->id <= htab->top_id
&& (htab->stub_group[sec->id].toc_off
!= htab->stub_group[input_section->id].toc_off)))
&& (stub_entry = ppc_get_stub_entry (input_section, sec, fdh,
@ -7925,17 +7909,18 @@ ppc64_elf_relocate_section (bfd *output_bfd,
|| stub_entry->stub_type == ppc_stub_plt_branch_r2off
|| stub_entry->stub_type == ppc_stub_long_branch_r2off))
{
bfd_boolean can_plt_call = 0;
bfd_boolean can_plt_call = FALSE;
if (rel->r_offset + 8 <= input_section->size)
{
insn = bfd_get_32 (input_bfd, contents + rel->r_offset + 4);
if (insn == NOP
|| insn == CROR_151515 || insn == CROR_313131)
unsigned long nop;
nop = bfd_get_32 (input_bfd, contents + rel->r_offset + 4);
if (nop == NOP
|| nop == CROR_151515 || nop == CROR_313131)
{
bfd_put_32 (input_bfd, LD_R2_40R1,
contents + rel->r_offset + 4);
can_plt_call = 1;
can_plt_call = TRUE;
}
}
@ -7945,16 +7930,17 @@ ppc64_elf_relocate_section (bfd *output_bfd,
{
/* If this is a plain branch rather than a branch
and link, don't require a nop. */
insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
if ((insn & 1) == 0)
can_plt_call = 1;
unsigned long br;
br = bfd_get_32 (input_bfd, contents + rel->r_offset);
if ((br & 1) == 0)
can_plt_call = TRUE;
}
else if (h != NULL
&& strcmp (h->root.root.string,
".__libc_start_main") == 0)
{
/* Allow crt1 branch to go via a toc adjusting stub. */
can_plt_call = 1;
can_plt_call = TRUE;
}
else
{
@ -7986,23 +7972,66 @@ ppc64_elf_relocate_section (bfd *output_bfd,
}
}
if (can_plt_call)
if (can_plt_call
&& stub_entry->stub_type == ppc_stub_plt_call)
unresolved_reloc = FALSE;
}
/* If the branch is out of reach we ought to have a long
branch stub. */
from = (rel->r_offset
+ input_section->output_offset
+ input_section->output_section->vma);
if (stub_entry == NULL
&& (relocation + rel->r_addend - from + max_br_offset
>= 2 * max_br_offset)
&& r_type != R_PPC64_ADDR14_BRTAKEN
&& r_type != R_PPC64_ADDR14_BRNTAKEN)
stub_entry = ppc_get_stub_entry (input_section, sec, h, rel, htab);
if (stub_entry != NULL)
{
/* Munge up the value and addend so that we call the stub
rather than the procedure directly. */
relocation = (stub_entry->stub_offset
+ stub_entry->stub_sec->output_offset
+ stub_entry->stub_sec->output_section->vma);
addend = 0;
}
if (insn != 0)
{
if (is_power4)
{
relocation = (stub_entry->stub_offset
+ stub_entry->stub_sec->output_offset
+ stub_entry->stub_sec->output_section->vma);
if (stub_entry->stub_type == ppc_stub_plt_call)
unresolved_reloc = FALSE;
/* Set 'a' bit. This is 0b00010 in BO field for branch
on CR(BI) insns (BO == 001at or 011at), and 0b01000
for branch on CTR insns (BO == 1a00t or 1a01t). */
if ((insn & (0x14 << 21)) == (0x04 << 21))
insn |= 0x02 << 21;
else if ((insn & (0x14 << 21)) == (0x10 << 21))
insn |= 0x08 << 21;
else
break;
}
else
{
/* Invert 'y' bit if not the default. */
if ((bfd_signed_vma) (relocation + rel->r_addend - from) < 0)
insn ^= 0x01 << 21;
}
bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
}
/* NOP out calls to undefined weak functions.
We can thus call a weak function without first
checking whether the function is defined. */
if (h != NULL
&& h->root.type == bfd_link_hash_undefweak
&& relocation == 0
&& rel->r_addend == 0)
else if (h != NULL
&& h->root.type == bfd_link_hash_undefweak
&& r_type == R_PPC64_REL24
&& relocation == 0
&& rel->r_addend == 0)
{
bfd_put_32 (output_bfd, NOP, contents + rel->r_offset);
continue;
@ -8012,7 +8041,6 @@ ppc64_elf_relocate_section (bfd *output_bfd,
/* Set `addend'. */
tls_type = 0;
addend = rel->r_addend;
switch (r_type)
{
default:
@ -8645,40 +8673,6 @@ ppc64_elf_relocate_section (bfd *output_bfd,
continue;
}
break;
case R_PPC64_REL14:
case R_PPC64_REL14_BRNTAKEN:
case R_PPC64_REL14_BRTAKEN:
max_br_offset = 1 << 15;
goto branch_check;
case R_PPC64_REL24:
max_br_offset = 1 << 25;
branch_check:
/* If the branch is out of reach or the TOC register needs
adjusting, then redirect the call to the local stub for
this function. */
from = (rel->r_offset
+ input_section->output_offset
+ input_section->output_section->vma);
if ((relocation + addend - from + max_br_offset >= 2 * max_br_offset
|| (sec != NULL
&& sec->output_section != NULL
&& sec->id <= htab->top_id
&& (htab->stub_group[sec->id].toc_off
!= htab->stub_group[input_section->id].toc_off)))
&& (stub_entry = ppc_get_stub_entry (input_section, sec, h,
rel, htab)) != NULL)
{
/* Munge up the value and addend so that we call the stub
rather than the procedure directly. */
relocation = (stub_entry->stub_offset
+ stub_entry->stub_sec->output_offset
+ stub_entry->stub_sec->output_section->vma);
addend = 0;
}
break;
}
/* Dynamic relocs are not propagated for SEC_DEBUGGING sections