* 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:
parent
ccfa59eaa0
commit
b25116a9c7
|
@ -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>
|
||||
|
|
138
bfd/elf64-ppc.c
138
bfd/elf64-ppc.c
|
@ -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,21 +7972,64 @@ 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);
|
||||
if (stub_entry->stub_type == ppc_stub_plt_call)
|
||||
unresolved_reloc = FALSE;
|
||||
addend = 0;
|
||||
}
|
||||
|
||||
if (insn != 0)
|
||||
{
|
||||
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
|
||||
{
|
||||
/* 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
|
||||
else if (h != NULL
|
||||
&& h->root.type == bfd_link_hash_undefweak
|
||||
&& r_type == R_PPC64_REL24
|
||||
&& relocation == 0
|
||||
&& rel->r_addend == 0)
|
||||
{
|
||||
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue