* 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> 2004-08-09 Alan Modra <amodra@bigpond.net.au>
* elf-bfd.h (_bfd_elf_gc_mark): Declare. * elf-bfd.h (_bfd_elf_gc_mark): Declare.
@ -10,6 +15,7 @@
(ppc64_elf_mark_entry_syms): Delete. (ppc64_elf_mark_entry_syms): Delete.
(ppc64_elf_gc_mark_hook): Mark entry syms here. Also mark opd (ppc64_elf_gc_mark_hook): Mark entry syms here. Also mark opd
sections. Use get_opd_info. sections. Use get_opd_info.
* elf64-ppc.h (ppc64_elf_mark_entry_syms): Delete. * elf64-ppc.h (ppc64_elf_mark_entry_syms): Delete.
2004-08-09 Alan Modra <amodra@bigpond.net.au> 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. */ /* Handle other relocations that tweak non-addend part of insn. */
insn = 0; insn = 0;
max_br_offset = 1 << 25;
addend = rel->r_addend;
switch (r_type) switch (r_type)
{ {
default: default:
@ -7879,31 +7881,11 @@ ppc64_elf_relocate_section (bfd *output_bfd,
case R_PPC64_REL14_BRNTAKEN: case R_PPC64_REL14_BRNTAKEN:
insn |= bfd_get_32 (output_bfd, insn |= bfd_get_32 (output_bfd,
contents + rel->r_offset) & ~(0x01 << 21); contents + rel->r_offset) & ~(0x01 << 21);
if (is_power4) /* Fall thru. */
{
/* 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);
/* Invert 'y' bit if not the default. */ case R_PPC64_REL14:
if ((bfd_signed_vma) (relocation + rel->r_addend - from) < 0) max_br_offset = 1 << 15;
insn ^= 0x01 << 21; /* Fall thru. */
}
bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
break;
case R_PPC64_REL24: case R_PPC64_REL24:
/* Calls to functions with a different TOC, such as calls to /* 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 linkage stubs needs to be followed by a nop, as the nop
will be replaced with an instruction to restore the TOC will be replaced with an instruction to restore the TOC
base pointer. */ base pointer. */
stub_entry = NULL;
if (((h != NULL if (((h != NULL
&& (fdh = &((struct ppc_link_hash_entry *) h)->oh->elf) != NULL && (fdh = &((struct ppc_link_hash_entry *) h)->oh->elf) != NULL
&& fdh->plt.plist != NULL) && fdh->plt.plist != NULL)
|| ((fdh = h, sec) != NULL || ((fdh = h, sec) != NULL
&& sec->output_section != NULL && sec->output_section != NULL
&& sec->id <= htab->top_id
&& (htab->stub_group[sec->id].toc_off && (htab->stub_group[sec->id].toc_off
!= htab->stub_group[input_section->id].toc_off))) != htab->stub_group[input_section->id].toc_off)))
&& (stub_entry = ppc_get_stub_entry (input_section, sec, fdh, && (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_plt_branch_r2off
|| stub_entry->stub_type == ppc_stub_long_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) if (rel->r_offset + 8 <= input_section->size)
{ {
insn = bfd_get_32 (input_bfd, contents + rel->r_offset + 4); unsigned long nop;
if (insn == NOP nop = bfd_get_32 (input_bfd, contents + rel->r_offset + 4);
|| insn == CROR_151515 || insn == CROR_313131) if (nop == NOP
|| nop == CROR_151515 || nop == CROR_313131)
{ {
bfd_put_32 (input_bfd, LD_R2_40R1, bfd_put_32 (input_bfd, LD_R2_40R1,
contents + rel->r_offset + 4); 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 /* If this is a plain branch rather than a branch
and link, don't require a nop. */ and link, don't require a nop. */
insn = bfd_get_32 (input_bfd, contents + rel->r_offset); unsigned long br;
if ((insn & 1) == 0) br = bfd_get_32 (input_bfd, contents + rel->r_offset);
can_plt_call = 1; if ((br & 1) == 0)
can_plt_call = TRUE;
} }
else if (h != NULL else if (h != NULL
&& strcmp (h->root.root.string, && strcmp (h->root.root.string,
".__libc_start_main") == 0) ".__libc_start_main") == 0)
{ {
/* Allow crt1 branch to go via a toc adjusting stub. */ /* Allow crt1 branch to go via a toc adjusting stub. */
can_plt_call = 1; can_plt_call = TRUE;
} }
else 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 /* Set 'a' bit. This is 0b00010 in BO field for branch
+ stub_entry->stub_sec->output_offset on CR(BI) insns (BO == 001at or 011at), and 0b01000
+ stub_entry->stub_sec->output_section->vma); for branch on CTR insns (BO == 1a00t or 1a01t). */
if (stub_entry->stub_type == ppc_stub_plt_call) if ((insn & (0x14 << 21)) == (0x04 << 21))
unresolved_reloc = FALSE; 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. /* NOP out calls to undefined weak functions.
We can thus call a weak function without first We can thus call a weak function without first
checking whether the function is defined. */ checking whether the function is defined. */
if (h != NULL else if (h != NULL
&& h->root.type == bfd_link_hash_undefweak && h->root.type == bfd_link_hash_undefweak
&& relocation == 0 && r_type == R_PPC64_REL24
&& rel->r_addend == 0) && relocation == 0
&& rel->r_addend == 0)
{ {
bfd_put_32 (output_bfd, NOP, contents + rel->r_offset); bfd_put_32 (output_bfd, NOP, contents + rel->r_offset);
continue; continue;
@ -8012,7 +8041,6 @@ ppc64_elf_relocate_section (bfd *output_bfd,
/* Set `addend'. */ /* Set `addend'. */
tls_type = 0; tls_type = 0;
addend = rel->r_addend;
switch (r_type) switch (r_type)
{ {
default: default:
@ -8645,40 +8673,6 @@ ppc64_elf_relocate_section (bfd *output_bfd,
continue; continue;
} }
break; 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 /* Dynamic relocs are not propagated for SEC_DEBUGGING sections