mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-27 03:51:15 +08:00
* elf32-ppc.c (ppc_elf_check_relocs): Always add a plt ref count
for local ifunc symbols in non-pie executables, regardless of reloc type. Don't specially create ifunc dyn relocs. Tidy ifunc code so that it's obvious that we only do anything special for local ifunc syms. (ppc_elf_gc_sweep_hook): Adjust to suit check_relocs changes. (allocate_dynrelocs): Correct comment for syms defined in plt. Don't specially allocate ifunc dyn relocs. (ppc_elf_relax_section): Relax branches to ifunc plt entries too. (ppc_elf_relocate_section): Set "relocation" value for ifunc syms in non-pie executables. No specially allocated dyn relocs for ifunc to write. Allow for local sym on R_PPC_RELAX32_PLT. (ppc_elf_finish_dynamic_symbol): Set value of ifunc symbols in a non-pie executable.
This commit is contained in:
parent
0329406f62
commit
de972ffadd
@ -1,3 +1,20 @@
|
||||
2009-08-03 Alan Modra <amodra@bigpond.net.au>
|
||||
|
||||
* elf32-ppc.c (ppc_elf_check_relocs): Always add a plt ref count
|
||||
for local ifunc symbols in non-pie executables, regardless of
|
||||
reloc type. Don't specially create ifunc dyn relocs. Tidy ifunc
|
||||
code so that it's obvious that we only do anything special for
|
||||
local ifunc syms.
|
||||
(ppc_elf_gc_sweep_hook): Adjust to suit check_relocs changes.
|
||||
(allocate_dynrelocs): Correct comment for syms defined in plt.
|
||||
Don't specially allocate ifunc dyn relocs.
|
||||
(ppc_elf_relax_section): Relax branches to ifunc plt entries too.
|
||||
(ppc_elf_relocate_section): Set "relocation" value for ifunc
|
||||
syms in non-pie executables. No specially allocated dyn relocs
|
||||
for ifunc to write. Allow for local sym on R_PPC_RELAX32_PLT.
|
||||
(ppc_elf_finish_dynamic_symbol): Set value of ifunc symbols in
|
||||
a non-pie executable.
|
||||
|
||||
2009-08-02 H.J. Lu <hongjiu.lu@intel.com>
|
||||
Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
|
255
bfd/elf32-ppc.c
255
bfd/elf32-ppc.c
@ -3458,15 +3458,13 @@ ppc_elf_check_relocs (bfd *abfd,
|
||||
|
||||
tls_type = 0;
|
||||
ifunc = NULL;
|
||||
r_type = ELF32_R_TYPE (rel->r_info);
|
||||
if (!htab->is_vxworks)
|
||||
{
|
||||
if (h != NULL)
|
||||
{
|
||||
if (h->type == STT_GNU_IFUNC)
|
||||
{
|
||||
h->needs_plt = 1;
|
||||
ifunc = &h->plt.plist;
|
||||
}
|
||||
ifunc = &h->plt.plist;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -3475,46 +3473,47 @@ ppc_elf_check_relocs (bfd *abfd,
|
||||
if (isym == NULL)
|
||||
return FALSE;
|
||||
|
||||
if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
|
||||
if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC
|
||||
&& (!info->shared
|
||||
|| is_branch_reloc (r_type)))
|
||||
{
|
||||
bfd_vma addend;
|
||||
|
||||
ifunc = update_local_sym_info (abfd, symtab_hdr, r_symndx,
|
||||
PLT_IFUNC);
|
||||
if (ifunc == NULL)
|
||||
return FALSE;
|
||||
|
||||
/* STT_GNU_IFUNC symbols must have a PLT entry;
|
||||
In a non-pie executable even when there are
|
||||
no plt calls. */
|
||||
addend = 0;
|
||||
if (r_type == R_PPC_PLTREL24)
|
||||
{
|
||||
ppc_elf_tdata (abfd)->makes_plt_call = 1;
|
||||
addend = rel->r_addend;
|
||||
}
|
||||
if (!update_plt_info (abfd, ifunc,
|
||||
addend < 32768 ? NULL : got2, addend))
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
r_type = ELF32_R_TYPE (rel->r_info);
|
||||
if (!htab->is_vxworks && is_branch_reloc (r_type))
|
||||
if (!htab->is_vxworks
|
||||
&& is_branch_reloc (r_type)
|
||||
&& h != NULL
|
||||
&& h == tga)
|
||||
{
|
||||
if (h != NULL && h == tga)
|
||||
{
|
||||
if (rel != relocs
|
||||
&& (ELF32_R_TYPE (rel[-1].r_info) == R_PPC_TLSGD
|
||||
|| ELF32_R_TYPE (rel[-1].r_info) == R_PPC_TLSLD))
|
||||
/* We have a new-style __tls_get_addr call with a marker
|
||||
reloc. */
|
||||
;
|
||||
else
|
||||
/* Mark this section as having an old-style call. */
|
||||
sec->has_tls_get_addr_call = 1;
|
||||
}
|
||||
|
||||
/* STT_GNU_IFUNC symbols must have a PLT entry. */
|
||||
if (ifunc != NULL)
|
||||
{
|
||||
bfd_vma addend = 0;
|
||||
|
||||
if (r_type == R_PPC_PLTREL24)
|
||||
{
|
||||
ppc_elf_tdata (abfd)->makes_plt_call = 1;
|
||||
addend = rel->r_addend;
|
||||
}
|
||||
if (!update_plt_info (abfd, ifunc,
|
||||
addend < 32768 ? NULL : got2, addend))
|
||||
return FALSE;
|
||||
}
|
||||
if (rel != relocs
|
||||
&& (ELF32_R_TYPE (rel[-1].r_info) == R_PPC_TLSGD
|
||||
|| ELF32_R_TYPE (rel[-1].r_info) == R_PPC_TLSLD))
|
||||
/* We have a new-style __tls_get_addr call with a marker
|
||||
reloc. */
|
||||
;
|
||||
else
|
||||
/* Mark this section as having an old-style call. */
|
||||
sec->has_tls_get_addr_call = 1;
|
||||
}
|
||||
|
||||
switch (r_type)
|
||||
@ -3690,7 +3689,7 @@ ppc_elf_check_relocs (bfd *abfd,
|
||||
break;
|
||||
|
||||
case R_PPC_PLTREL24:
|
||||
if (h == NULL || ifunc != NULL)
|
||||
if (h == NULL)
|
||||
break;
|
||||
/* Fall through */
|
||||
case R_PPC_PLT32:
|
||||
@ -3903,8 +3902,7 @@ ppc_elf_check_relocs (bfd *abfd,
|
||||
/* We may need a plt entry if the symbol turns out to be
|
||||
a function defined in a dynamic object. */
|
||||
h->needs_plt = 1;
|
||||
if (ifunc == NULL
|
||||
&& !update_plt_info (abfd, &h->plt.plist, NULL, 0))
|
||||
if (!update_plt_info (abfd, &h->plt.plist, NULL, 0))
|
||||
return FALSE;
|
||||
break;
|
||||
}
|
||||
@ -3941,9 +3939,7 @@ ppc_elf_check_relocs (bfd *abfd,
|
||||
&& !info->shared
|
||||
&& h != NULL
|
||||
&& (h->root.type == bfd_link_hash_defweak
|
||||
|| !h->def_regular))
|
||||
|| (!info->shared
|
||||
&& ifunc != NULL))
|
||||
|| !h->def_regular)))
|
||||
{
|
||||
struct ppc_elf_dyn_relocs *p;
|
||||
struct ppc_elf_dyn_relocs **head;
|
||||
@ -4415,25 +4411,19 @@ ppc_elf_gc_sweep_hook (bfd *abfd,
|
||||
}
|
||||
|
||||
r_type = ELF32_R_TYPE (rel->r_info);
|
||||
if (!htab->is_vxworks && is_branch_reloc (r_type))
|
||||
if (!htab->is_vxworks
|
||||
&& h == NULL
|
||||
&& local_got_refcounts != NULL
|
||||
&& (!info->shared
|
||||
|| is_branch_reloc (r_type)))
|
||||
{
|
||||
struct plt_entry **ifunc = NULL;
|
||||
if (h != NULL)
|
||||
{
|
||||
if (h->type == STT_GNU_IFUNC)
|
||||
ifunc = &h->plt.plist;
|
||||
}
|
||||
else if (local_got_refcounts != NULL)
|
||||
{
|
||||
struct plt_entry **local_plt = (struct plt_entry **)
|
||||
(local_got_refcounts + symtab_hdr->sh_info);
|
||||
char *local_got_tls_masks = (char *)
|
||||
(local_plt + symtab_hdr->sh_info);
|
||||
if ((local_got_tls_masks[r_symndx] & PLT_IFUNC) != 0)
|
||||
ifunc = local_plt + r_symndx;
|
||||
}
|
||||
if (ifunc != NULL)
|
||||
struct plt_entry **local_plt = (struct plt_entry **)
|
||||
(local_got_refcounts + symtab_hdr->sh_info);
|
||||
char *local_got_tls_masks = (char *)
|
||||
(local_plt + symtab_hdr->sh_info);
|
||||
if ((local_got_tls_masks[r_symndx] & PLT_IFUNC) != 0)
|
||||
{
|
||||
struct plt_entry **ifunc = local_plt + r_symndx;
|
||||
bfd_vma addend = r_type == R_PPC_PLTREL24 ? rel->r_addend : 0;
|
||||
struct plt_entry *ent = find_plt_ent (ifunc, got2, addend);
|
||||
if (ent->plt.refcount > 0)
|
||||
@ -5166,8 +5156,9 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
|
||||
|
||||
/* If this symbol is not defined in a regular
|
||||
file, and we are not generating a shared
|
||||
library, then set the symbol to this location
|
||||
in the .plt. This is required to make
|
||||
library, then set the symbol to this location
|
||||
in the .plt. This is to avoid text
|
||||
relocations, and is required to make
|
||||
function pointers compare as equal between
|
||||
the normal executable and the shared library. */
|
||||
if (! info->shared
|
||||
@ -5313,8 +5304,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
|
||||
eh->elf.got.offset = (bfd_vma) -1;
|
||||
|
||||
if (eh->dyn_relocs == NULL
|
||||
|| (!htab->elf.dynamic_sections_created
|
||||
&& h->type != STT_GNU_IFUNC))
|
||||
|| !htab->elf.dynamic_sections_created)
|
||||
return TRUE;
|
||||
|
||||
/* In the shared -Bsymbolic case, discard space allocated for
|
||||
@ -5385,11 +5375,6 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (h->type == STT_GNU_IFUNC)
|
||||
{
|
||||
if (!h->non_got_ref)
|
||||
eh->dyn_relocs = NULL;
|
||||
}
|
||||
else if (ELIMINATE_COPY_RELOCS)
|
||||
{
|
||||
/* For the non-shared case, discard space for relocs against
|
||||
@ -5938,6 +5923,7 @@ ppc_elf_relax_section (bfd *abfd,
|
||||
bfd_vma max_branch_offset, val;
|
||||
bfd_byte *hit_addr;
|
||||
unsigned long t0;
|
||||
struct elf_link_hash_entry *h;
|
||||
unsigned char sym_type;
|
||||
|
||||
switch (r_type)
|
||||
@ -5959,6 +5945,7 @@ ppc_elf_relax_section (bfd *abfd,
|
||||
}
|
||||
|
||||
/* Get the value of the symbol referred to by the reloc. */
|
||||
h = NULL;
|
||||
if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
|
||||
{
|
||||
/* A local symbol. */
|
||||
@ -5992,7 +5979,6 @@ ppc_elf_relax_section (bfd *abfd,
|
||||
{
|
||||
/* Global symbol handling. */
|
||||
unsigned long indx;
|
||||
struct elf_link_hash_entry *h;
|
||||
|
||||
indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
|
||||
h = elf_sym_hashes (abfd)[indx];
|
||||
@ -6003,26 +5989,6 @@ ppc_elf_relax_section (bfd *abfd,
|
||||
|
||||
tsec = NULL;
|
||||
toff = 0;
|
||||
if (r_type == R_PPC_PLTREL24
|
||||
&& htab->plt != NULL)
|
||||
{
|
||||
struct plt_entry *ent = find_plt_ent (&h->plt.plist,
|
||||
got2, irel->r_addend);
|
||||
|
||||
if (ent != NULL)
|
||||
{
|
||||
if (htab->plt_type == PLT_NEW)
|
||||
{
|
||||
tsec = htab->glink;
|
||||
toff = ent->glink_offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
tsec = htab->plt;
|
||||
toff = ent->plt.offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tsec != NULL)
|
||||
;
|
||||
else if (h->root.type == bfd_link_hash_defined
|
||||
@ -6043,6 +6009,46 @@ ppc_elf_relax_section (bfd *abfd,
|
||||
sym_type = h->type;
|
||||
}
|
||||
|
||||
if (is_branch_reloc (r_type))
|
||||
{
|
||||
struct plt_entry **plist = NULL;
|
||||
|
||||
if (h != NULL)
|
||||
plist = &h->plt.plist;
|
||||
else if (sym_type == STT_GNU_IFUNC)
|
||||
{
|
||||
bfd_vma *local_got_offsets = elf_local_got_offsets (abfd);
|
||||
struct plt_entry **local_plt = (struct plt_entry **)
|
||||
(local_got_offsets + symtab_hdr->sh_info);
|
||||
plist = local_plt + ELF32_R_SYM (irel->r_info);
|
||||
}
|
||||
if (plist != NULL)
|
||||
{
|
||||
bfd_vma addend = 0;
|
||||
struct plt_entry *ent;
|
||||
|
||||
if (r_type == R_PPC_PLTREL24)
|
||||
addend = irel->r_addend;
|
||||
ent = find_plt_ent (plist, got2, addend);
|
||||
if (ent != NULL)
|
||||
{
|
||||
if (htab->plt_type == PLT_NEW
|
||||
|| h == NULL
|
||||
|| !htab->elf.dynamic_sections_created
|
||||
|| h->dynindx == -1)
|
||||
{
|
||||
tsec = htab->glink;
|
||||
toff = ent->glink_offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
tsec = htab->plt;
|
||||
toff = ent->plt.offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If the branch and target are in the same section, you have
|
||||
no hope of adding stubs. We'll error out later should the
|
||||
branch overflow. */
|
||||
@ -6940,25 +6946,35 @@ ppc_elf_relocate_section (bfd *output_bfd,
|
||||
ifunc = NULL;
|
||||
if (!htab->is_vxworks)
|
||||
{
|
||||
struct plt_entry *ent;
|
||||
|
||||
if (h != NULL)
|
||||
{
|
||||
if (h->type == STT_GNU_IFUNC)
|
||||
ifunc = &h->plt.plist;
|
||||
}
|
||||
else if (local_got_offsets != NULL)
|
||||
else if (local_got_offsets != NULL
|
||||
&& ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
|
||||
{
|
||||
if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
|
||||
{
|
||||
struct plt_entry **local_plt = (struct plt_entry **)
|
||||
(local_got_offsets + symtab_hdr->sh_info);
|
||||
struct plt_entry **local_plt;
|
||||
|
||||
ifunc = local_plt + r_symndx;
|
||||
}
|
||||
local_plt = (struct plt_entry **) (local_got_offsets
|
||||
+ symtab_hdr->sh_info);
|
||||
ifunc = local_plt + r_symndx;
|
||||
}
|
||||
if (ifunc != NULL && is_branch_reloc (r_type))
|
||||
{
|
||||
struct plt_entry *ent = find_plt_ent (ifunc, got2, rel->r_addend);
|
||||
|
||||
ent = NULL;
|
||||
if (ifunc != NULL
|
||||
&& (!info->shared
|
||||
|| is_branch_reloc (r_type)))
|
||||
{
|
||||
addend = 0;
|
||||
if (r_type == R_PPC_PLTREL24)
|
||||
addend = rel->r_addend;
|
||||
ent = find_plt_ent (ifunc, got2, addend);
|
||||
}
|
||||
if (ent != NULL)
|
||||
{
|
||||
if (h == NULL && (ent->plt.offset & 1) == 0)
|
||||
{
|
||||
Elf_Internal_Rela rela;
|
||||
@ -7385,9 +7401,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
|
||||
&& h != NULL
|
||||
&& h->dynindx != -1
|
||||
&& !h->non_got_ref
|
||||
&& !h->def_regular)
|
||||
|| (!info->shared
|
||||
&& ifunc != NULL))
|
||||
&& !h->def_regular))
|
||||
{
|
||||
int skip;
|
||||
|
||||
@ -7526,18 +7540,19 @@ ppc_elf_relocate_section (bfd *output_bfd,
|
||||
|
||||
case R_PPC_RELAX32PC_PLT:
|
||||
case R_PPC_RELAX32_PLT:
|
||||
{
|
||||
struct plt_entry *ent = find_plt_ent (&h->plt.plist, got2, addend);
|
||||
|
||||
if (htab->plt_type == PLT_NEW)
|
||||
relocation = (htab->glink->output_section->vma
|
||||
+ htab->glink->output_offset
|
||||
+ ent->glink_offset);
|
||||
else
|
||||
relocation = (htab->plt->output_section->vma
|
||||
+ htab->plt->output_offset
|
||||
+ ent->plt.offset);
|
||||
}
|
||||
if (h != NULL)
|
||||
{
|
||||
struct plt_entry *ent = find_plt_ent (&h->plt.plist, got2,
|
||||
addend);
|
||||
if (htab->plt_type == PLT_NEW)
|
||||
relocation = (htab->glink->output_section->vma
|
||||
+ htab->glink->output_offset
|
||||
+ ent->glink_offset);
|
||||
else
|
||||
relocation = (htab->plt->output_section->vma
|
||||
+ htab->plt->output_offset
|
||||
+ ent->plt.offset);
|
||||
}
|
||||
if (r_type == R_PPC_RELAX32_PLT)
|
||||
goto relax32;
|
||||
/* Fall thru */
|
||||
@ -8164,6 +8179,22 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
|
||||
sym->st_value = 0;
|
||||
}
|
||||
}
|
||||
else if (h->type == STT_GNU_IFUNC
|
||||
&& !info->shared)
|
||||
{
|
||||
/* Set the value of ifunc symbols in a non-pie
|
||||
executable to the glink entry. This is to avoid
|
||||
text relocations. We can't do this for ifunc in
|
||||
allocate_dynrelocs, as we do for normal dynamic
|
||||
function symbols with plt entries, because we need
|
||||
to keep the original value around for the ifunc
|
||||
relocation. */
|
||||
sym->st_shndx = (_bfd_elf_section_from_bfd_section
|
||||
(output_bfd, htab->glink->output_section));
|
||||
sym->st_value = (ent->glink_offset +
|
||||
htab->glink->output_offset
|
||||
+ htab->glink->output_section->vma);
|
||||
}
|
||||
doneone = TRUE;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user