mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-22 19:09:31 +08:00
PowerPC64 --emit-relocs support for notoc stubs
This patch uses the newly defined high-part REL16 relocs to emit relocations on the notoc stubs as we already do for other stubs. * elf64-ppc.c (num_relocs_for_offset): New function. (emit_relocs_for_offset): New function. (use_global_in_relocs): New function, split out from.. (ppc_build_one_stub): ..here. Output relocations for notoc stubs. (ppc_size_one_stub): Calculate reloc count for notoc stubs. (ppc64_elf_size_stubs): Don't count undefined syms in stub_globals.
This commit is contained in:
@ -1,3 +1,12 @@
|
|||||||
|
2018-08-31 Alan Modra <amodra@gmail.com>
|
||||||
|
|
||||||
|
* elf64-ppc.c (num_relocs_for_offset): New function.
|
||||||
|
(emit_relocs_for_offset): New function.
|
||||||
|
(use_global_in_relocs): New function, split out from..
|
||||||
|
(ppc_build_one_stub): ..here. Output relocations for notoc stubs.
|
||||||
|
(ppc_size_one_stub): Calculate reloc count for notoc stubs.
|
||||||
|
(ppc64_elf_size_stubs): Don't count undefined syms in stub_globals.
|
||||||
|
|
||||||
2018-08-31 Alan Modra <amodra@gmail.com>
|
2018-08-31 Alan Modra <amodra@gmail.com>
|
||||||
|
|
||||||
* reloc.c (BFD_RELOC_PPC64_REL16_HIGH, BFD_RELOC_PPC64_REL16_HIGHA),
|
* reloc.c (BFD_RELOC_PPC64_REL16_HIGH, BFD_RELOC_PPC64_REL16_HIGHA),
|
||||||
|
226
bfd/elf64-ppc.c
226
bfd/elf64-ppc.c
@ -9626,6 +9626,86 @@ size_offset (bfd_vma off)
|
|||||||
return size + 16;
|
return size + 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned int
|
||||||
|
num_relocs_for_offset (bfd_vma off)
|
||||||
|
{
|
||||||
|
unsigned int num_rel;
|
||||||
|
if (off + 0x8000 < 0x10000)
|
||||||
|
num_rel = 1;
|
||||||
|
else if (off + 0x80008000ULL < 0x100000000ULL)
|
||||||
|
num_rel = 2;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
num_rel = 1;
|
||||||
|
if (off + 0x800000000000ULL >= 0x1000000000000ULL
|
||||||
|
&& ((off >> 32) & 0xffff) != 0)
|
||||||
|
num_rel += 1;
|
||||||
|
if (PPC_HI (off) != 0)
|
||||||
|
num_rel += 1;
|
||||||
|
if (PPC_LO (off) != 0)
|
||||||
|
num_rel += 1;
|
||||||
|
}
|
||||||
|
return num_rel;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Elf_Internal_Rela *
|
||||||
|
emit_relocs_for_offset (struct bfd_link_info *info, Elf_Internal_Rela *r,
|
||||||
|
bfd_vma roff, bfd_vma targ, bfd_vma off)
|
||||||
|
{
|
||||||
|
bfd_vma relative_targ = targ - (roff - 8);
|
||||||
|
if (bfd_big_endian (info->output_bfd))
|
||||||
|
roff += 2;
|
||||||
|
r->r_offset = roff;
|
||||||
|
r->r_addend = relative_targ + roff;
|
||||||
|
if (off + 0x8000 < 0x10000)
|
||||||
|
r->r_info = ELF64_R_INFO (0, R_PPC64_REL16);
|
||||||
|
else if (off + 0x80008000ULL < 0x100000000ULL)
|
||||||
|
{
|
||||||
|
r->r_info = ELF64_R_INFO (0, R_PPC64_REL16_HA);
|
||||||
|
++r;
|
||||||
|
roff += 4;
|
||||||
|
r->r_offset = roff;
|
||||||
|
r->r_info = ELF64_R_INFO (0, R_PPC64_REL16_LO);
|
||||||
|
r->r_addend = relative_targ + roff;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (off + 0x800000000000ULL < 0x1000000000000ULL)
|
||||||
|
r->r_info = ELF64_R_INFO (0, R_PPC64_REL16_HIGHER);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
r->r_info = ELF64_R_INFO (0, R_PPC64_REL16_HIGHEST);
|
||||||
|
if (((off >> 32) & 0xffff) != 0)
|
||||||
|
{
|
||||||
|
++r;
|
||||||
|
roff += 4;
|
||||||
|
r->r_offset = roff;
|
||||||
|
r->r_info = ELF64_R_INFO (0, R_PPC64_REL16_HIGHER);
|
||||||
|
r->r_addend = relative_targ + roff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (((off >> 32) & 0xffffffffULL) != 0)
|
||||||
|
roff += 4;
|
||||||
|
if (PPC_HI (off) != 0)
|
||||||
|
{
|
||||||
|
++r;
|
||||||
|
roff += 4;
|
||||||
|
r->r_offset = roff;
|
||||||
|
r->r_info = ELF64_R_INFO (0, R_PPC64_REL16_HIGH);
|
||||||
|
r->r_addend = relative_targ + roff;
|
||||||
|
}
|
||||||
|
if (PPC_LO (off) != 0)
|
||||||
|
{
|
||||||
|
++r;
|
||||||
|
roff += 4;
|
||||||
|
r->r_offset = roff;
|
||||||
|
r->r_info = ELF64_R_INFO (0, R_PPC64_REL16_LO);
|
||||||
|
r->r_addend = relative_targ + roff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
/* Emit .eh_frame opcode to advance pc by DELTA. */
|
/* Emit .eh_frame opcode to advance pc by DELTA. */
|
||||||
|
|
||||||
static bfd_byte *
|
static bfd_byte *
|
||||||
@ -10049,6 +10129,65 @@ get_relocs (asection *sec, int count)
|
|||||||
return relocs;
|
return relocs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Convert the relocs R[0] thru R[-NUM_REL+1], which are all no-symbol
|
||||||
|
forms, to the equivalent relocs against the global symbol given by
|
||||||
|
STUB_ENTRY->H. */
|
||||||
|
|
||||||
|
static bfd_boolean
|
||||||
|
use_global_in_relocs (struct ppc_link_hash_table *htab,
|
||||||
|
struct ppc_stub_hash_entry *stub_entry,
|
||||||
|
Elf_Internal_Rela *r, unsigned int num_rel)
|
||||||
|
{
|
||||||
|
struct elf_link_hash_entry **hashes;
|
||||||
|
unsigned long symndx;
|
||||||
|
struct ppc_link_hash_entry *h;
|
||||||
|
bfd_vma symval;
|
||||||
|
|
||||||
|
/* Relocs are always against symbols in their own object file. Fake
|
||||||
|
up global sym hashes for the stub bfd (which has no symbols). */
|
||||||
|
hashes = elf_sym_hashes (htab->params->stub_bfd);
|
||||||
|
if (hashes == NULL)
|
||||||
|
{
|
||||||
|
bfd_size_type hsize;
|
||||||
|
|
||||||
|
/* When called the first time, stub_globals will contain the
|
||||||
|
total number of symbols seen during stub sizing. After
|
||||||
|
allocating, stub_globals is used as an index to fill the
|
||||||
|
hashes array. */
|
||||||
|
hsize = (htab->stub_globals + 1) * sizeof (*hashes);
|
||||||
|
hashes = bfd_zalloc (htab->params->stub_bfd, hsize);
|
||||||
|
if (hashes == NULL)
|
||||||
|
return FALSE;
|
||||||
|
elf_sym_hashes (htab->params->stub_bfd) = hashes;
|
||||||
|
htab->stub_globals = 1;
|
||||||
|
}
|
||||||
|
symndx = htab->stub_globals++;
|
||||||
|
h = stub_entry->h;
|
||||||
|
hashes[symndx] = &h->elf;
|
||||||
|
if (h->oh != NULL && h->oh->is_func)
|
||||||
|
h = ppc_follow_link (h->oh);
|
||||||
|
BFD_ASSERT (h->elf.root.type == bfd_link_hash_defined
|
||||||
|
|| h->elf.root.type == bfd_link_hash_defweak);
|
||||||
|
symval = (h->elf.root.u.def.value
|
||||||
|
+ h->elf.root.u.def.section->output_offset
|
||||||
|
+ h->elf.root.u.def.section->output_section->vma);
|
||||||
|
while (num_rel-- != 0)
|
||||||
|
{
|
||||||
|
r->r_info = ELF64_R_INFO (symndx, ELF64_R_TYPE (r->r_info));
|
||||||
|
if (h->elf.root.u.def.section != stub_entry->target_section)
|
||||||
|
{
|
||||||
|
/* H is an opd symbol. The addend must be zero, and the
|
||||||
|
branch reloc is the only one we can convert. */
|
||||||
|
r->r_addend = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
r->r_addend -= symval;
|
||||||
|
--r;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static bfd_vma
|
static bfd_vma
|
||||||
get_r2off (struct bfd_link_info *info,
|
get_r2off (struct bfd_link_info *info,
|
||||||
struct ppc_stub_hash_entry *stub_entry)
|
struct ppc_stub_hash_entry *stub_entry)
|
||||||
@ -10092,10 +10231,11 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
|
|||||||
struct bfd_link_info *info;
|
struct bfd_link_info *info;
|
||||||
struct ppc_link_hash_table *htab;
|
struct ppc_link_hash_table *htab;
|
||||||
bfd_byte *loc;
|
bfd_byte *loc;
|
||||||
bfd_byte *p;
|
bfd_byte *p, *relp;
|
||||||
bfd_vma targ, off;
|
bfd_vma targ, off;
|
||||||
Elf_Internal_Rela *r;
|
Elf_Internal_Rela *r;
|
||||||
asection *plt;
|
asection *plt;
|
||||||
|
int num_rel;
|
||||||
|
|
||||||
/* Massage our args to the form they really have. */
|
/* Massage our args to the form they really have. */
|
||||||
stub_entry = (struct ppc_stub_hash_entry *) gen_entry;
|
stub_entry = (struct ppc_stub_hash_entry *) gen_entry;
|
||||||
@ -10171,41 +10311,9 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
|
|||||||
r->r_offset = p - 4 - stub_entry->group->stub_sec->contents;
|
r->r_offset = p - 4 - stub_entry->group->stub_sec->contents;
|
||||||
r->r_info = ELF64_R_INFO (0, R_PPC64_REL24);
|
r->r_info = ELF64_R_INFO (0, R_PPC64_REL24);
|
||||||
r->r_addend = targ;
|
r->r_addend = targ;
|
||||||
if (stub_entry->h != NULL)
|
if (stub_entry->h != NULL
|
||||||
{
|
&& !use_global_in_relocs (htab, stub_entry, r, 1))
|
||||||
struct elf_link_hash_entry **hashes;
|
return FALSE;
|
||||||
unsigned long symndx;
|
|
||||||
struct ppc_link_hash_entry *h;
|
|
||||||
|
|
||||||
hashes = elf_sym_hashes (htab->params->stub_bfd);
|
|
||||||
if (hashes == NULL)
|
|
||||||
{
|
|
||||||
bfd_size_type hsize;
|
|
||||||
|
|
||||||
hsize = (htab->stub_globals + 1) * sizeof (*hashes);
|
|
||||||
hashes = bfd_zalloc (htab->params->stub_bfd, hsize);
|
|
||||||
if (hashes == NULL)
|
|
||||||
return FALSE;
|
|
||||||
elf_sym_hashes (htab->params->stub_bfd) = hashes;
|
|
||||||
htab->stub_globals = 1;
|
|
||||||
}
|
|
||||||
symndx = htab->stub_globals++;
|
|
||||||
h = stub_entry->h;
|
|
||||||
hashes[symndx] = &h->elf;
|
|
||||||
r->r_info = ELF64_R_INFO (symndx, R_PPC64_REL24);
|
|
||||||
if (h->oh != NULL && h->oh->is_func)
|
|
||||||
h = ppc_follow_link (h->oh);
|
|
||||||
if (h->elf.root.u.def.section != stub_entry->target_section)
|
|
||||||
/* H is an opd symbol. The addend must be zero. */
|
|
||||||
r->r_addend = 0;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
off = (h->elf.root.u.def.value
|
|
||||||
+ h->elf.root.u.def.section->output_offset
|
|
||||||
+ h->elf.root.u.def.section->output_section->vma);
|
|
||||||
r->r_addend -= off;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -10408,6 +10516,8 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
|
|||||||
+ stub_entry->target_section->output_section->vma);
|
+ stub_entry->target_section->output_section->vma);
|
||||||
off = targ - off;
|
off = targ - off;
|
||||||
|
|
||||||
|
relp = p;
|
||||||
|
num_rel = 0;
|
||||||
/* The notoc stubs calculate their target (either a PLT entry or
|
/* The notoc stubs calculate their target (either a PLT entry or
|
||||||
the global entry point of a function) relative to the PC
|
the global entry point of a function) relative to the PC
|
||||||
returned by the "bcl" two instructions past the start of the
|
returned by the "bcl" two instructions past the start of the
|
||||||
@ -10419,6 +10529,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
|
|||||||
if (stub_entry->stub_type <= ppc_stub_long_branch_both)
|
if (stub_entry->stub_type <= ppc_stub_long_branch_both)
|
||||||
{
|
{
|
||||||
bfd_vma from;
|
bfd_vma from;
|
||||||
|
num_rel = 1;
|
||||||
from = (stub_entry->stub_offset
|
from = (stub_entry->stub_offset
|
||||||
+ stub_entry->group->stub_sec->output_offset
|
+ stub_entry->group->stub_sec->output_offset
|
||||||
+ stub_entry->group->stub_sec->output_section->vma
|
+ stub_entry->group->stub_sec->output_section->vma
|
||||||
@ -10434,6 +10545,29 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
|
|||||||
}
|
}
|
||||||
p += 4;
|
p += 4;
|
||||||
|
|
||||||
|
if (info->emitrelocations)
|
||||||
|
{
|
||||||
|
bfd_vma roff;
|
||||||
|
num_rel += num_relocs_for_offset (off);
|
||||||
|
r = get_relocs (stub_entry->group->stub_sec, num_rel);
|
||||||
|
if (r == NULL)
|
||||||
|
return FALSE;
|
||||||
|
roff = relp + 16 - stub_entry->group->stub_sec->contents;
|
||||||
|
r = emit_relocs_for_offset (info, r, roff, targ, off);
|
||||||
|
if (stub_entry->stub_type == ppc_stub_long_branch_notoc
|
||||||
|
|| stub_entry->stub_type == ppc_stub_long_branch_both)
|
||||||
|
{
|
||||||
|
++r;
|
||||||
|
roff = p - 4 - stub_entry->group->stub_sec->contents;
|
||||||
|
r->r_offset = roff;
|
||||||
|
r->r_info = ELF64_R_INFO (0, R_PPC64_REL24);
|
||||||
|
r->r_addend = targ;
|
||||||
|
if (stub_entry->h != NULL
|
||||||
|
&& !use_global_in_relocs (htab, stub_entry, r, num_rel))
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (htab->glink_eh_frame != NULL
|
if (htab->glink_eh_frame != NULL
|
||||||
&& htab->glink_eh_frame->size != 0)
|
&& htab->glink_eh_frame->size != 0)
|
||||||
{
|
{
|
||||||
@ -10759,6 +10893,13 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
|
|||||||
+ stub_entry->target_section->output_section->vma);
|
+ stub_entry->target_section->output_section->vma);
|
||||||
off = targ - off;
|
off = targ - off;
|
||||||
|
|
||||||
|
if (info->emitrelocations)
|
||||||
|
{
|
||||||
|
stub_entry->group->stub_sec->reloc_count
|
||||||
|
+= num_relocs_for_offset (off);
|
||||||
|
stub_entry->group->stub_sec->flags |= SEC_RELOC;
|
||||||
|
}
|
||||||
|
|
||||||
extra = size_offset (off - 8);
|
extra = size_offset (off - 8);
|
||||||
/* Include branch insn plus those in the offset sequence. */
|
/* Include branch insn plus those in the offset sequence. */
|
||||||
size += 4 + extra;
|
size += 4 + extra;
|
||||||
@ -10786,6 +10927,8 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
|
|||||||
- ppc_stub_long_branch_notoc);
|
- ppc_stub_long_branch_notoc);
|
||||||
size += 4;
|
size += 4;
|
||||||
}
|
}
|
||||||
|
else if (info->emitrelocations)
|
||||||
|
stub_entry->group->stub_sec->reloc_count +=1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ppc_stub_plt_call_notoc:
|
case ppc_stub_plt_call_notoc:
|
||||||
@ -10821,6 +10964,13 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
|
|||||||
off -= pad;
|
off -= pad;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (info->emitrelocations)
|
||||||
|
{
|
||||||
|
stub_entry->group->stub_sec->reloc_count
|
||||||
|
+= num_relocs_for_offset (off - 8);
|
||||||
|
stub_entry->group->stub_sec->flags |= SEC_RELOC;
|
||||||
|
}
|
||||||
|
|
||||||
size = plt_stub_size (htab, stub_entry, off);
|
size = plt_stub_size (htab, stub_entry, off);
|
||||||
|
|
||||||
/* After the bcl, lr has been modified so we need to emit
|
/* After the bcl, lr has been modified so we need to emit
|
||||||
@ -12184,7 +12334,9 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
|
|||||||
= hash ? hash->elf.type : ELF_ST_TYPE (sym->st_info);
|
= hash ? hash->elf.type : ELF_ST_TYPE (sym->st_info);
|
||||||
stub_entry->other = hash ? hash->elf.other : sym->st_other;
|
stub_entry->other = hash ? hash->elf.other : sym->st_other;
|
||||||
|
|
||||||
if (stub_entry->h != NULL)
|
if (hash != NULL
|
||||||
|
&& (hash->elf.root.type == bfd_link_hash_defined
|
||||||
|
|| hash->elf.root.type == bfd_link_hash_defweak))
|
||||||
htab->stub_globals += 1;
|
htab->stub_globals += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user