* elf-bfd.h (struct elf_backend_data): Add
elf_backend_archive_symbol_lookup. (_bfd_elf_archive_symbol_lookup): Declare. * elflink.c (_bfd_elf_archive_symbol_lookup): New function.. (elf_link_add_archive_symbols): ..extracted from here. Call the backend version. * elfxx-target.h (elf_backend_archive_symbol_lookup): Provide default. (elfNN_bed): Init new field. * elf64-ppc.c (elf_backend_check_directives): Define. (elf_backend_archive_symbol_lookup): Define. (struct ppc_link_hash_table): Add tls_get_add_fd. Make tls_get_add a ppc_link_hash_entry pointer. (get_fdh): Move. (ppc64_elf_archive_symbol_lookup, opd_entry_value): New functions. (add_symbol_adjust, ppc64_elf_check_directives): New functions. (ppc64_elf_check_relocs, ppc64_elf_gc_mark_hook, func_desc_adjust, ppc64_elf_adjust_dynamic_symbol, ppc64_elf_tls_setup, ppc64_elf_tls_optimize, allocate_dynrelocs, ppc_type_of_stub, ppc_build_one_stub, ppc64_elf_size_stubs, ppc64_elf_relocate_section, ppc64_elf_finish_dynamic_symbol): Handle branch relocs to function descriptor symbols.
This commit is contained in:
parent
fed7ba43e0
commit
8387904def
5 changed files with 498 additions and 153 deletions
|
@ -1,3 +1,27 @@
|
||||||
|
2004-08-09 Alan Modra <amodra@bigpond.net.au>
|
||||||
|
|
||||||
|
* elf-bfd.h (struct elf_backend_data): Add
|
||||||
|
elf_backend_archive_symbol_lookup.
|
||||||
|
(_bfd_elf_archive_symbol_lookup): Declare.
|
||||||
|
* elflink.c (_bfd_elf_archive_symbol_lookup): New function..
|
||||||
|
(elf_link_add_archive_symbols): ..extracted from here. Call the
|
||||||
|
backend version.
|
||||||
|
* elfxx-target.h (elf_backend_archive_symbol_lookup): Provide default.
|
||||||
|
(elfNN_bed): Init new field.
|
||||||
|
* elf64-ppc.c (elf_backend_check_directives): Define.
|
||||||
|
(elf_backend_archive_symbol_lookup): Define.
|
||||||
|
(struct ppc_link_hash_table): Add tls_get_add_fd. Make tls_get_add
|
||||||
|
a ppc_link_hash_entry pointer.
|
||||||
|
(get_fdh): Move.
|
||||||
|
(ppc64_elf_archive_symbol_lookup, opd_entry_value): New functions.
|
||||||
|
(add_symbol_adjust, ppc64_elf_check_directives): New functions.
|
||||||
|
(ppc64_elf_check_relocs, ppc64_elf_gc_mark_hook, func_desc_adjust,
|
||||||
|
ppc64_elf_adjust_dynamic_symbol, ppc64_elf_tls_setup,
|
||||||
|
ppc64_elf_tls_optimize, allocate_dynrelocs, ppc_type_of_stub,
|
||||||
|
ppc_build_one_stub, ppc64_elf_size_stubs, ppc64_elf_relocate_section,
|
||||||
|
ppc64_elf_finish_dynamic_symbol): Handle branch relocs to function
|
||||||
|
descriptor symbols.
|
||||||
|
|
||||||
2004-08-09 Alan Modra <amodra@bigpond.net.au>
|
2004-08-09 Alan Modra <amodra@bigpond.net.au>
|
||||||
|
|
||||||
* elf64-ppc.c (struct ppc_link_hash_entry): Expand adjust_done comment.
|
* elf64-ppc.c (struct ppc_link_hash_entry): Expand adjust_done comment.
|
||||||
|
@ -21,7 +45,6 @@
|
||||||
(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>
|
||||||
|
|
|
@ -579,11 +579,16 @@ struct elf_backend_data
|
||||||
bfd_boolean (*elf_backend_symbol_table_processing)
|
bfd_boolean (*elf_backend_symbol_table_processing)
|
||||||
(bfd *, elf_symbol_type *, unsigned int);
|
(bfd *, elf_symbol_type *, unsigned int);
|
||||||
|
|
||||||
/* A function to set the type of the info field. Processor-specific
|
/* A function to set the type of the info field. Processor-specific
|
||||||
types should be handled here. */
|
types should be handled here. */
|
||||||
int (*elf_backend_get_symbol_type)
|
int (*elf_backend_get_symbol_type)
|
||||||
(Elf_Internal_Sym *, int);
|
(Elf_Internal_Sym *, int);
|
||||||
|
|
||||||
|
/* A function to return the linker hash table entry of a symbol that
|
||||||
|
might be satisfied by an archive symbol. */
|
||||||
|
struct elf_link_hash_entry * (*elf_backend_archive_symbol_lookup)
|
||||||
|
(bfd *, struct bfd_link_info *, const char *);
|
||||||
|
|
||||||
/* Return true if local section symbols should have a non-null st_name.
|
/* Return true if local section symbols should have a non-null st_name.
|
||||||
NULL implies false. */
|
NULL implies false. */
|
||||||
bfd_boolean (*elf_backend_name_local_section_symbols)
|
bfd_boolean (*elf_backend_name_local_section_symbols)
|
||||||
|
@ -1681,6 +1686,8 @@ extern void bfd_elf64_write_relocs
|
||||||
extern bfd_boolean bfd_elf64_slurp_reloc_table
|
extern bfd_boolean bfd_elf64_slurp_reloc_table
|
||||||
(bfd *, asection *, asymbol **, bfd_boolean);
|
(bfd *, asection *, asymbol **, bfd_boolean);
|
||||||
|
|
||||||
|
extern struct elf_link_hash_entry *_bfd_elf_archive_symbol_lookup
|
||||||
|
(bfd *, struct bfd_link_info *, const char *);
|
||||||
extern bfd_boolean bfd_elf_link_add_symbols
|
extern bfd_boolean bfd_elf_link_add_symbols
|
||||||
(bfd *, struct bfd_link_info *);
|
(bfd *, struct bfd_link_info *);
|
||||||
extern bfd_boolean _bfd_elf_add_dynamic_entry
|
extern bfd_boolean _bfd_elf_add_dynamic_entry
|
||||||
|
|
514
bfd/elf64-ppc.c
514
bfd/elf64-ppc.c
|
@ -83,6 +83,8 @@ static bfd_reloc_status_type ppc64_elf_unhandled_reloc
|
||||||
#define elf_backend_create_dynamic_sections ppc64_elf_create_dynamic_sections
|
#define elf_backend_create_dynamic_sections ppc64_elf_create_dynamic_sections
|
||||||
#define elf_backend_copy_indirect_symbol ppc64_elf_copy_indirect_symbol
|
#define elf_backend_copy_indirect_symbol ppc64_elf_copy_indirect_symbol
|
||||||
#define elf_backend_add_symbol_hook ppc64_elf_add_symbol_hook
|
#define elf_backend_add_symbol_hook ppc64_elf_add_symbol_hook
|
||||||
|
#define elf_backend_check_directives ppc64_elf_check_directives
|
||||||
|
#define elf_backend_archive_symbol_lookup ppc64_elf_archive_symbol_lookup
|
||||||
#define elf_backend_check_relocs ppc64_elf_check_relocs
|
#define elf_backend_check_relocs ppc64_elf_check_relocs
|
||||||
#define elf_backend_gc_mark_hook ppc64_elf_gc_mark_hook
|
#define elf_backend_gc_mark_hook ppc64_elf_gc_mark_hook
|
||||||
#define elf_backend_gc_sweep_hook ppc64_elf_gc_sweep_hook
|
#define elf_backend_gc_sweep_hook ppc64_elf_gc_sweep_hook
|
||||||
|
@ -2569,7 +2571,11 @@ get_opd_info (asection * sec)
|
||||||
creating a shared library containing foo, we need to have both symbols
|
creating a shared library containing foo, we need to have both symbols
|
||||||
dynamic so that references to .foo are satisfied during the early
|
dynamic so that references to .foo are satisfied during the early
|
||||||
stages of linking. Otherwise the linker might decide to pull in a
|
stages of linking. Otherwise the linker might decide to pull in a
|
||||||
definition from some other object, eg. a static library. */
|
definition from some other object, eg. a static library.
|
||||||
|
|
||||||
|
Update: As of August 2004, we support a new convention. Function
|
||||||
|
calls may use the function descriptor symbol, ie. "bl foo". This
|
||||||
|
behaves exactly as "bl .foo". */
|
||||||
|
|
||||||
/* The linker needs to keep track of the number of relocs that it
|
/* The linker needs to keep track of the number of relocs that it
|
||||||
decides to copy as dynamic relocs in check_relocs for each symbol.
|
decides to copy as dynamic relocs in check_relocs for each symbol.
|
||||||
|
@ -2857,8 +2863,9 @@ struct ppc_link_hash_table
|
||||||
asection *brlt;
|
asection *brlt;
|
||||||
asection *relbrlt;
|
asection *relbrlt;
|
||||||
|
|
||||||
/* Shortcut to .__tls_get_addr. */
|
/* Shortcut to .__tls_get_addr and __tls_get_addr. */
|
||||||
struct elf_link_hash_entry *tls_get_addr;
|
struct ppc_link_hash_entry *tls_get_addr;
|
||||||
|
struct ppc_link_hash_entry *tls_get_addr_fd;
|
||||||
|
|
||||||
/* Statistics. */
|
/* Statistics. */
|
||||||
unsigned long stub_count[ppc_stub_plt_call];
|
unsigned long stub_count[ppc_stub_plt_call];
|
||||||
|
@ -3463,7 +3470,49 @@ ppc64_elf_copy_indirect_symbol
|
||||||
BFD_ASSERT (eind->elf.dynindx == -1);
|
BFD_ASSERT (eind->elf.dynindx == -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Hack symbols defined in .opd sections to be function type. */
|
/* Find the function descriptor hash entry from the given function code
|
||||||
|
hash entry FH. Link the entries via their OH fields. */
|
||||||
|
|
||||||
|
static struct ppc_link_hash_entry *
|
||||||
|
get_fdh (struct ppc_link_hash_entry *fh, struct ppc_link_hash_table *htab)
|
||||||
|
{
|
||||||
|
struct ppc_link_hash_entry *fdh = fh->oh;
|
||||||
|
|
||||||
|
if (fdh == NULL)
|
||||||
|
{
|
||||||
|
const char *fd_name = fh->elf.root.root.string + 1;
|
||||||
|
|
||||||
|
fdh = (struct ppc_link_hash_entry *)
|
||||||
|
elf_link_hash_lookup (&htab->elf, fd_name, FALSE, FALSE, FALSE);
|
||||||
|
if (fdh != NULL)
|
||||||
|
{
|
||||||
|
fdh->is_func_descriptor = 1;
|
||||||
|
fdh->oh = fh;
|
||||||
|
fh->is_func = 1;
|
||||||
|
fh->oh = fdh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fdh;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hacks to support old ABI code.
|
||||||
|
When making function calls, old ABI code references function entry
|
||||||
|
points (dot symbols), while new ABI code references the function
|
||||||
|
descriptor symbol. We need to make any combination of reference and
|
||||||
|
definition work together, without breaking archive linking.
|
||||||
|
|
||||||
|
For a defined function "foo" and an undefined call to "bar":
|
||||||
|
An old object defines "foo" and ".foo", references ".bar" (possibly
|
||||||
|
"bar" too).
|
||||||
|
A new object defines "foo" and references "bar".
|
||||||
|
|
||||||
|
A new object thus has no problem with its undefined symbols being
|
||||||
|
satisfied by definitions in an old object. On the other hand, the
|
||||||
|
old object won't have ".bar" satisfied by a new object. */
|
||||||
|
|
||||||
|
/* Fix function descriptor symbols defined in .opd sections to be
|
||||||
|
function type. */
|
||||||
|
|
||||||
static bfd_boolean
|
static bfd_boolean
|
||||||
ppc64_elf_add_symbol_hook (bfd *ibfd ATTRIBUTE_UNUSED,
|
ppc64_elf_add_symbol_hook (bfd *ibfd ATTRIBUTE_UNUSED,
|
||||||
|
@ -3480,6 +3529,80 @@ ppc64_elf_add_symbol_hook (bfd *ibfd ATTRIBUTE_UNUSED,
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This function makes an old ABI object reference to ".bar" cause the
|
||||||
|
inclusion of a new ABI object archive that defines "bar". */
|
||||||
|
|
||||||
|
static struct elf_link_hash_entry *
|
||||||
|
ppc64_elf_archive_symbol_lookup (bfd *abfd,
|
||||||
|
struct bfd_link_info *info,
|
||||||
|
const char *name)
|
||||||
|
{
|
||||||
|
struct elf_link_hash_entry *h;
|
||||||
|
char *dot_name;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
h = _bfd_elf_archive_symbol_lookup (abfd, info, name);
|
||||||
|
if (h != NULL)
|
||||||
|
return h;
|
||||||
|
|
||||||
|
if (name[0] == '.')
|
||||||
|
return h;
|
||||||
|
|
||||||
|
len = strlen (name);
|
||||||
|
dot_name = bfd_alloc (abfd, len + 2);
|
||||||
|
if (dot_name == NULL)
|
||||||
|
return (struct elf_link_hash_entry *) 0 - 1;
|
||||||
|
dot_name[0] = '.';
|
||||||
|
memcpy (dot_name + 1, name, len + 1);
|
||||||
|
h = _bfd_elf_archive_symbol_lookup (abfd, info, dot_name);
|
||||||
|
bfd_release (abfd, dot_name);
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function satisfies all old ABI object references to ".bar" if a
|
||||||
|
new ABI object defines "bar". This stops later archive searches from
|
||||||
|
including an object if we already have a function descriptor
|
||||||
|
definition. It also prevents the linker complaining about undefined
|
||||||
|
symbols. */
|
||||||
|
|
||||||
|
static bfd_boolean
|
||||||
|
add_symbol_adjust (struct elf_link_hash_entry *h, void *inf)
|
||||||
|
{
|
||||||
|
struct bfd_link_info *info;
|
||||||
|
struct ppc_link_hash_table *htab;
|
||||||
|
struct ppc_link_hash_entry *fdh;
|
||||||
|
|
||||||
|
if (h->root.type == bfd_link_hash_indirect)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
if (h->root.type == bfd_link_hash_warning)
|
||||||
|
h = (struct elf_link_hash_entry *) h->root.u.i.link;
|
||||||
|
|
||||||
|
if (h->root.type != bfd_link_hash_undefined
|
||||||
|
|| h->root.root.string[0] != '.')
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
info = inf;
|
||||||
|
htab = ppc_hash_table (info);
|
||||||
|
fdh = get_fdh ((struct ppc_link_hash_entry *) h, htab);
|
||||||
|
if (fdh != NULL)
|
||||||
|
{
|
||||||
|
h->root.type = bfd_link_hash_defweak;
|
||||||
|
h->root.u.def.section = &bfd_und_section;
|
||||||
|
h->root.u.def.value = 0;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bfd_boolean
|
||||||
|
ppc64_elf_check_directives (bfd *abfd ATTRIBUTE_UNUSED,
|
||||||
|
struct bfd_link_info *info)
|
||||||
|
{
|
||||||
|
struct ppc_link_hash_table *htab = ppc_hash_table (info);
|
||||||
|
elf_link_hash_traverse (&htab->elf, add_symbol_adjust, info);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static bfd_boolean
|
static bfd_boolean
|
||||||
update_local_sym_info (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
|
update_local_sym_info (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
|
||||||
unsigned long r_symndx, bfd_vma r_addend, int tls_type)
|
unsigned long r_symndx, bfd_vma r_addend, int tls_type)
|
||||||
|
@ -3553,31 +3676,6 @@ update_plt_info (bfd *abfd, struct ppc_link_hash_entry *eh, bfd_vma addend)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find the function descriptor hash entry from the given function code
|
|
||||||
hash entry FH. Link the entries via their OH fields. */
|
|
||||||
static struct ppc_link_hash_entry *
|
|
||||||
get_fdh (struct ppc_link_hash_entry *fh, struct ppc_link_hash_table *htab)
|
|
||||||
{
|
|
||||||
struct ppc_link_hash_entry *fdh = fh->oh;
|
|
||||||
|
|
||||||
if (fdh == NULL)
|
|
||||||
{
|
|
||||||
const char *fd_name = fh->elf.root.root.string + 1;
|
|
||||||
|
|
||||||
fdh = (struct ppc_link_hash_entry *)
|
|
||||||
elf_link_hash_lookup (&htab->elf, fd_name, FALSE, FALSE, FALSE);
|
|
||||||
if (fdh != NULL)
|
|
||||||
{
|
|
||||||
fdh->is_func_descriptor = 1;
|
|
||||||
fdh->oh = fh;
|
|
||||||
fh->is_func = 1;
|
|
||||||
fh->oh = fdh;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return fdh;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Look through the relocs for a section during the first phase, and
|
/* Look through the relocs for a section during the first phase, and
|
||||||
calculate needed space in the global offset table, procedure
|
calculate needed space in the global offset table, procedure
|
||||||
linkage table, and dynamic reloc sections. */
|
linkage table, and dynamic reloc sections. */
|
||||||
|
@ -3815,23 +3913,30 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
||||||
/* Fall through. */
|
/* Fall through. */
|
||||||
|
|
||||||
case R_PPC64_REL24:
|
case R_PPC64_REL24:
|
||||||
if (h != NULL
|
if (h != NULL)
|
||||||
&& h->root.root.string[0] == '.'
|
|
||||||
&& h->root.root.string[1] != 0)
|
|
||||||
{
|
{
|
||||||
/* We may need a .plt entry if the function this reloc
|
/* We may need a .plt entry if the function this reloc
|
||||||
refers to is in a shared lib. */
|
refers to is in a shared lib. */
|
||||||
if (!update_plt_info (abfd, (struct ppc_link_hash_entry *) h,
|
if (!update_plt_info (abfd, (struct ppc_link_hash_entry *) h,
|
||||||
rel->r_addend))
|
rel->r_addend))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
if (h == htab->tls_get_addr)
|
if (h == &htab->tls_get_addr->elf
|
||||||
|
|| h == &htab->tls_get_addr_fd->elf)
|
||||||
sec->has_tls_reloc = 1;
|
sec->has_tls_reloc = 1;
|
||||||
else if ((strncmp (h->root.root.string, ".__tls_get_addr", 15)
|
else if (htab->tls_get_addr == NULL
|
||||||
== 0)
|
&& !strncmp (h->root.root.string, ".__tls_get_addr", 15)
|
||||||
&& (h->root.root.string[15] == 0
|
&& (h->root.root.string[15] == 0
|
||||||
|| h->root.root.string[15] == '@'))
|
|| h->root.root.string[15] == '@'))
|
||||||
{
|
{
|
||||||
htab->tls_get_addr = h;
|
htab->tls_get_addr = (struct ppc_link_hash_entry *) h;
|
||||||
|
sec->has_tls_reloc = 1;
|
||||||
|
}
|
||||||
|
else if (htab->tls_get_addr_fd == NULL
|
||||||
|
&& !strncmp (h->root.root.string, "__tls_get_addr", 14)
|
||||||
|
&& (h->root.root.string[14] == 0
|
||||||
|
|| h->root.root.string[14] == '@'))
|
||||||
|
{
|
||||||
|
htab->tls_get_addr_fd = (struct ppc_link_hash_entry *) h;
|
||||||
sec->has_tls_reloc = 1;
|
sec->has_tls_reloc = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3912,24 +4017,29 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
||||||
|
|
||||||
case R_PPC64_ADDR64:
|
case R_PPC64_ADDR64:
|
||||||
if (opd_sym_map != NULL
|
if (opd_sym_map != NULL
|
||||||
&& h != NULL
|
|
||||||
&& h->root.root.string[0] == '.'
|
|
||||||
&& h->root.root.string[1] != 0)
|
|
||||||
get_fdh ((struct ppc_link_hash_entry *) h, htab);
|
|
||||||
|
|
||||||
if (opd_sym_map != NULL
|
|
||||||
&& h == NULL
|
|
||||||
&& rel + 1 < rel_end
|
&& rel + 1 < rel_end
|
||||||
&& ELF64_R_TYPE ((rel + 1)->r_info) == R_PPC64_TOC)
|
&& ELF64_R_TYPE ((rel + 1)->r_info) == R_PPC64_TOC)
|
||||||
{
|
{
|
||||||
asection *s;
|
if (h != NULL)
|
||||||
|
{
|
||||||
|
if (h->root.root.string[0] == '.'
|
||||||
|
&& h->root.root.string[1] != 0
|
||||||
|
&& get_fdh ((struct ppc_link_hash_entry *) h, htab))
|
||||||
|
;
|
||||||
|
else
|
||||||
|
((struct ppc_link_hash_entry *) h)->is_func = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
asection *s;
|
||||||
|
|
||||||
s = bfd_section_from_r_symndx (abfd, &htab->sym_sec, sec,
|
s = bfd_section_from_r_symndx (abfd, &htab->sym_sec, sec,
|
||||||
r_symndx);
|
r_symndx);
|
||||||
if (s == NULL)
|
if (s == NULL)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
else if (s != sec)
|
else if (s != sec)
|
||||||
opd_sym_map[rel->r_offset / 24] = s;
|
opd_sym_map[rel->r_offset / 24] = s;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/* Fall through. */
|
/* Fall through. */
|
||||||
|
|
||||||
|
@ -4095,6 +4205,94 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* OFFSET in OPD_SEC specifies a function descriptor. Return the address
|
||||||
|
of the code entry point, and its section. */
|
||||||
|
|
||||||
|
static bfd_vma
|
||||||
|
opd_entry_value (asection *opd_sec,
|
||||||
|
bfd_vma offset,
|
||||||
|
asection **code_sec,
|
||||||
|
bfd_vma *code_off)
|
||||||
|
{
|
||||||
|
bfd *opd_bfd = opd_sec->owner;
|
||||||
|
Elf_Internal_Rela *lo, *hi, *look;
|
||||||
|
|
||||||
|
/* Go find the opd reloc at the sym address. */
|
||||||
|
lo = _bfd_elf_link_read_relocs (opd_bfd, opd_sec, NULL, NULL, TRUE);
|
||||||
|
BFD_ASSERT (lo != NULL);
|
||||||
|
hi = lo + opd_sec->reloc_count - 1; /* ignore last reloc */
|
||||||
|
|
||||||
|
while (lo < hi)
|
||||||
|
{
|
||||||
|
look = lo + (hi - lo) / 2;
|
||||||
|
if (look->r_offset < offset)
|
||||||
|
lo = look + 1;
|
||||||
|
else if (look->r_offset > offset)
|
||||||
|
hi = look;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Elf_Internal_Shdr *symtab_hdr = &elf_tdata (opd_bfd)->symtab_hdr;
|
||||||
|
if (ELF64_R_TYPE (look->r_info) == R_PPC64_ADDR64
|
||||||
|
&& ELF64_R_TYPE ((look + 1)->r_info) == R_PPC64_TOC)
|
||||||
|
{
|
||||||
|
unsigned long symndx = ELF64_R_SYM (look->r_info);
|
||||||
|
bfd_vma val;
|
||||||
|
asection *sec;
|
||||||
|
|
||||||
|
if (symndx < symtab_hdr->sh_info)
|
||||||
|
{
|
||||||
|
Elf_Internal_Sym *sym;
|
||||||
|
|
||||||
|
sym = (Elf_Internal_Sym *) symtab_hdr->contents;
|
||||||
|
if (sym == NULL)
|
||||||
|
{
|
||||||
|
sym = bfd_elf_get_elf_syms (opd_bfd, symtab_hdr,
|
||||||
|
symtab_hdr->sh_info,
|
||||||
|
0, NULL, NULL, NULL);
|
||||||
|
if (sym == NULL)
|
||||||
|
return (bfd_vma) -1;
|
||||||
|
symtab_hdr->contents = (bfd_byte *) sym;
|
||||||
|
}
|
||||||
|
|
||||||
|
sym += symndx;
|
||||||
|
val = sym->st_value;
|
||||||
|
sec = NULL;
|
||||||
|
if ((sym->st_shndx != SHN_UNDEF
|
||||||
|
&& sym->st_shndx < SHN_LORESERVE)
|
||||||
|
|| sym->st_shndx > SHN_HIRESERVE)
|
||||||
|
sec = bfd_section_from_elf_index (opd_bfd, sym->st_shndx);
|
||||||
|
BFD_ASSERT ((sec->flags & SEC_MERGE) == 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
struct elf_link_hash_entry **sym_hashes;
|
||||||
|
struct elf_link_hash_entry *rh;
|
||||||
|
|
||||||
|
sym_hashes = elf_sym_hashes (opd_bfd);
|
||||||
|
rh = sym_hashes[symndx - symtab_hdr->sh_info];
|
||||||
|
while (rh->root.type == bfd_link_hash_indirect
|
||||||
|
|| rh->root.type == bfd_link_hash_warning)
|
||||||
|
rh = ((struct elf_link_hash_entry *) rh->root.u.i.link);
|
||||||
|
BFD_ASSERT (rh->root.type == bfd_link_hash_defined
|
||||||
|
|| rh->root.type == bfd_link_hash_defweak);
|
||||||
|
val = rh->root.u.def.value;
|
||||||
|
sec = rh->root.u.def.section;
|
||||||
|
}
|
||||||
|
val += look->r_addend;
|
||||||
|
if (code_off != NULL)
|
||||||
|
*code_off = val;
|
||||||
|
if (code_sec != NULL)
|
||||||
|
*code_sec = sec;
|
||||||
|
if (sec != NULL && sec->output_section != NULL)
|
||||||
|
val += sec->output_section->vma + sec->output_offset;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (bfd_vma) -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Return the section that should be marked against GC for a given
|
/* Return the section that should be marked against GC for a given
|
||||||
relocation. */
|
relocation. */
|
||||||
|
|
||||||
|
@ -4128,6 +4326,11 @@ ppc64_elf_gc_mark_hook (asection *sec,
|
||||||
|
|
||||||
if (eh->is_func_descriptor)
|
if (eh->is_func_descriptor)
|
||||||
rsec = eh->oh->elf.root.u.def.section;
|
rsec = eh->oh->elf.root.u.def.section;
|
||||||
|
else if (get_opd_info (eh->elf.root.u.def.section) != NULL
|
||||||
|
&& opd_entry_value (eh->elf.root.u.def.section,
|
||||||
|
eh->elf.root.u.def.value,
|
||||||
|
&rsec, NULL) != (bfd_vma) -1)
|
||||||
|
;
|
||||||
else
|
else
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -4181,6 +4384,15 @@ ppc64_elf_gc_mark_hook (asection *sec,
|
||||||
|
|
||||||
rsec = eh->oh->elf.root.u.def.section;
|
rsec = eh->oh->elf.root.u.def.section;
|
||||||
}
|
}
|
||||||
|
else if (get_opd_info (eh->elf.root.u.def.section) != NULL
|
||||||
|
&& opd_entry_value (eh->elf.root.u.def.section,
|
||||||
|
eh->elf.root.u.def.value,
|
||||||
|
&rsec, NULL) != (bfd_vma) -1)
|
||||||
|
{
|
||||||
|
if (!eh->elf.root.u.def.section->gc_mark)
|
||||||
|
_bfd_elf_gc_mark (info, eh->elf.root.u.def.section,
|
||||||
|
ppc64_elf_gc_mark_hook);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
rsec = h->root.u.def.section;
|
rsec = h->root.u.def.section;
|
||||||
break;
|
break;
|
||||||
|
@ -4445,7 +4657,11 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf)
|
||||||
| ELF_LINK_NON_GOT_REF));
|
| ELF_LINK_NON_GOT_REF));
|
||||||
if (ELF_ST_VISIBILITY (fh->elf.other) == STV_DEFAULT)
|
if (ELF_ST_VISIBILITY (fh->elf.other) == STV_DEFAULT)
|
||||||
{
|
{
|
||||||
fdh->elf.plt.plist = fh->elf.plt.plist;
|
struct plt_entry **ep = &fdh->elf.plt.plist;
|
||||||
|
while (*ep != NULL)
|
||||||
|
ep = &(*ep)->next;
|
||||||
|
*ep = fh->elf.plt.plist;
|
||||||
|
fh->elf.plt.plist = NULL;
|
||||||
fdh->elf.elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
|
fdh->elf.elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
|
||||||
}
|
}
|
||||||
fdh->is_func_descriptor = 1;
|
fdh->is_func_descriptor = 1;
|
||||||
|
@ -4606,8 +4822,7 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
|
||||||
for (ent = h->plt.plist; ent != NULL; ent = ent->next)
|
for (ent = h->plt.plist; ent != NULL; ent = ent->next)
|
||||||
if (ent->plt.refcount > 0)
|
if (ent->plt.refcount > 0)
|
||||||
break;
|
break;
|
||||||
if (!((struct ppc_link_hash_entry *) h)->is_func_descriptor
|
if (ent == NULL
|
||||||
|| ent == NULL
|
|
||||||
|| SYMBOL_CALLS_LOCAL (info, h)
|
|| SYMBOL_CALLS_LOCAL (info, h)
|
||||||
|| (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
|
|| (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
|
||||||
&& h->root.type == bfd_link_hash_undefweak))
|
&& h->root.type == bfd_link_hash_undefweak))
|
||||||
|
@ -4939,8 +5154,7 @@ get_tls_mask (char **tls_maskp, unsigned long *toc_symndx,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Adjust all global syms defined in opd sections. In gcc generated
|
/* Adjust all global syms defined in opd sections. In gcc generated
|
||||||
code these will already have been done, but I suppose we have to
|
code for the old ABI, these will already have been done. */
|
||||||
cater for all sorts of hand written assembly. */
|
|
||||||
|
|
||||||
static bfd_boolean
|
static bfd_boolean
|
||||||
adjust_opd_syms (struct elf_link_hash_entry *h, void *inf ATTRIBUTE_UNUSED)
|
adjust_opd_syms (struct elf_link_hash_entry *h, void *inf ATTRIBUTE_UNUSED)
|
||||||
|
@ -5301,13 +5515,29 @@ ppc64_elf_tls_setup (bfd *obfd, struct bfd_link_info *info)
|
||||||
htab = ppc_hash_table (info);
|
htab = ppc_hash_table (info);
|
||||||
if (htab->tls_get_addr != NULL)
|
if (htab->tls_get_addr != NULL)
|
||||||
{
|
{
|
||||||
struct elf_link_hash_entry *h = htab->tls_get_addr;
|
struct ppc_link_hash_entry *h = htab->tls_get_addr;
|
||||||
|
|
||||||
while (h->root.type == bfd_link_hash_indirect
|
while (h->elf.root.type == bfd_link_hash_indirect
|
||||||
|| h->root.type == bfd_link_hash_warning)
|
|| h->elf.root.type == bfd_link_hash_warning)
|
||||||
h = (struct elf_link_hash_entry *) h->root.u.i.link;
|
h = (struct ppc_link_hash_entry *) h->elf.root.u.i.link;
|
||||||
|
|
||||||
htab->tls_get_addr = h;
|
htab->tls_get_addr = h;
|
||||||
|
|
||||||
|
if (htab->tls_get_addr_fd == NULL
|
||||||
|
&& h->oh != NULL
|
||||||
|
&& h->oh->is_func_descriptor)
|
||||||
|
htab->tls_get_addr_fd = h->oh;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (htab->tls_get_addr_fd != NULL)
|
||||||
|
{
|
||||||
|
struct ppc_link_hash_entry *h = htab->tls_get_addr_fd;
|
||||||
|
|
||||||
|
while (h->elf.root.type == bfd_link_hash_indirect
|
||||||
|
|| h->elf.root.type == bfd_link_hash_warning)
|
||||||
|
h = (struct ppc_link_hash_entry *) h->elf.root.u.i.link;
|
||||||
|
|
||||||
|
htab->tls_get_addr_fd = h;
|
||||||
}
|
}
|
||||||
|
|
||||||
return _bfd_elf_tls_setup (obfd, info);
|
return _bfd_elf_tls_setup (obfd, info);
|
||||||
|
@ -5457,7 +5687,8 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
|
||||||
case R_PPC64_REL14_BRNTAKEN:
|
case R_PPC64_REL14_BRNTAKEN:
|
||||||
case R_PPC64_REL24:
|
case R_PPC64_REL24:
|
||||||
if (h != NULL
|
if (h != NULL
|
||||||
&& h == htab->tls_get_addr)
|
&& (h == &htab->tls_get_addr->elf
|
||||||
|
|| h == &htab->tls_get_addr_fd->elf))
|
||||||
{
|
{
|
||||||
if (!expecting_tls_get_addr
|
if (!expecting_tls_get_addr
|
||||||
&& rel != relstart
|
&& rel != relstart
|
||||||
|
@ -5638,8 +5869,6 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
|
||||||
for (pent = h->plt.plist; pent != NULL; pent = pent->next)
|
for (pent = h->plt.plist; pent != NULL; pent = pent->next)
|
||||||
if (pent->plt.refcount > 0)
|
if (pent->plt.refcount > 0)
|
||||||
{
|
{
|
||||||
BFD_ASSERT (((struct ppc_link_hash_entry *) h)->is_func_descriptor);
|
|
||||||
|
|
||||||
/* If this is the first .plt entry, make room for the special
|
/* If this is the first .plt entry, make room for the special
|
||||||
first entry. */
|
first entry. */
|
||||||
s = htab->plt;
|
s = htab->plt;
|
||||||
|
@ -6164,14 +6393,18 @@ ppc_type_of_stub (asection *input_sec,
|
||||||
if (h != NULL)
|
if (h != NULL)
|
||||||
{
|
{
|
||||||
if (h->oh != NULL
|
if (h->oh != NULL
|
||||||
&& h->oh->elf.dynindx != -1)
|
&& h->oh->is_func_descriptor)
|
||||||
|
h = h->oh;
|
||||||
|
|
||||||
|
if (h->elf.dynindx != -1)
|
||||||
{
|
{
|
||||||
struct plt_entry *ent;
|
struct plt_entry *ent;
|
||||||
for (ent = h->oh->elf.plt.plist; ent != NULL; ent = ent->next)
|
|
||||||
|
for (ent = h->elf.plt.plist; ent != NULL; ent = ent->next)
|
||||||
if (ent->addend == rel->r_addend
|
if (ent->addend == rel->r_addend
|
||||||
&& ent->plt.offset != (bfd_vma) -1)
|
&& ent->plt.offset != (bfd_vma) -1)
|
||||||
{
|
{
|
||||||
*hash = h->oh;
|
*hash = h;
|
||||||
return ppc_stub_plt_call;
|
return ppc_stub_plt_call;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6377,7 +6610,8 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
|
||||||
/* Do the best we can for shared libraries built without
|
/* Do the best we can for shared libraries built without
|
||||||
exporting ".foo" for each "foo". This can happen when symbol
|
exporting ".foo" for each "foo". This can happen when symbol
|
||||||
versioning scripts strip all bar a subset of symbols. */
|
versioning scripts strip all bar a subset of symbols. */
|
||||||
if (stub_entry->h->oh->elf.root.type != bfd_link_hash_defined
|
if (stub_entry->h->oh != NULL
|
||||||
|
&& stub_entry->h->oh->elf.root.type != bfd_link_hash_defined
|
||||||
&& stub_entry->h->oh->elf.root.type != bfd_link_hash_defweak)
|
&& stub_entry->h->oh->elf.root.type != bfd_link_hash_defweak)
|
||||||
{
|
{
|
||||||
/* Point the symbol at the stub. There may be multiple stubs,
|
/* Point the symbol at the stub. There may be multiple stubs,
|
||||||
|
@ -6430,6 +6664,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
|
||||||
|
|
||||||
if (htab->emit_stub_syms
|
if (htab->emit_stub_syms
|
||||||
&& !(stub_entry->stub_type == ppc_stub_plt_call
|
&& !(stub_entry->stub_type == ppc_stub_plt_call
|
||||||
|
&& stub_entry->h->oh != NULL
|
||||||
&& stub_entry->h->oh->elf.root.type == bfd_link_hash_defined
|
&& stub_entry->h->oh->elf.root.type == bfd_link_hash_defined
|
||||||
&& stub_entry->h->oh->elf.root.u.def.section == stub_entry->stub_sec
|
&& stub_entry->h->oh->elf.root.u.def.section == stub_entry->stub_sec
|
||||||
&& stub_entry->h->oh->elf.root.u.def.value == stub_entry->stub_offset))
|
&& stub_entry->h->oh->elf.root.u.def.value == stub_entry->stub_offset))
|
||||||
|
@ -6942,15 +7177,17 @@ ppc64_elf_size_stubs (bfd *output_bfd,
|
||||||
unsigned int r_indx;
|
unsigned int r_indx;
|
||||||
enum ppc_stub_type stub_type;
|
enum ppc_stub_type stub_type;
|
||||||
struct ppc_stub_hash_entry *stub_entry;
|
struct ppc_stub_hash_entry *stub_entry;
|
||||||
asection *sym_sec;
|
asection *sym_sec, *code_sec;
|
||||||
bfd_vma sym_value;
|
bfd_vma sym_value;
|
||||||
bfd_vma destination;
|
bfd_vma destination;
|
||||||
bfd_boolean ok_dest;
|
bfd_boolean ok_dest;
|
||||||
struct ppc_link_hash_entry *hash;
|
struct ppc_link_hash_entry *hash;
|
||||||
|
struct ppc_link_hash_entry *fdh;
|
||||||
struct elf_link_hash_entry *h;
|
struct elf_link_hash_entry *h;
|
||||||
Elf_Internal_Sym *sym;
|
Elf_Internal_Sym *sym;
|
||||||
char *stub_name;
|
char *stub_name;
|
||||||
const asection *id_sec;
|
const asection *id_sec;
|
||||||
|
long *opd_adjust;
|
||||||
|
|
||||||
r_type = ELF64_R_TYPE (irela->r_info);
|
r_type = ELF64_R_TYPE (irela->r_info);
|
||||||
r_indx = ELF64_R_SYM (irela->r_info);
|
r_indx = ELF64_R_SYM (irela->r_info);
|
||||||
|
@ -6976,18 +7213,35 @@ ppc64_elf_size_stubs (bfd *output_bfd,
|
||||||
hash = (struct ppc_link_hash_entry *) h;
|
hash = (struct ppc_link_hash_entry *) h;
|
||||||
|
|
||||||
ok_dest = FALSE;
|
ok_dest = FALSE;
|
||||||
|
fdh = NULL;
|
||||||
if (hash == NULL)
|
if (hash == NULL)
|
||||||
{
|
{
|
||||||
/* It's a local symbol. */
|
|
||||||
sym_value = sym->st_value;
|
sym_value = sym->st_value;
|
||||||
ok_dest = TRUE;
|
ok_dest = TRUE;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* It's an external symbol. */
|
|
||||||
sym_value = 0;
|
sym_value = 0;
|
||||||
if (hash->elf.root.type == bfd_link_hash_defined
|
/* Recognise an old ABI func code entry sym by
|
||||||
|| hash->elf.root.type == bfd_link_hash_defweak)
|
the weird section for a defined sym, and use
|
||||||
|
the func descriptor sym instead. */
|
||||||
|
if (hash->elf.root.type == bfd_link_hash_defweak
|
||||||
|
&& hash->elf.root.u.def.section == &bfd_und_section
|
||||||
|
&& hash->elf.root.root.string[0] == '.'
|
||||||
|
&& (fdh = get_fdh (hash, htab)) != NULL)
|
||||||
|
{
|
||||||
|
sym_sec = NULL;
|
||||||
|
if (fdh->elf.root.type == bfd_link_hash_defined
|
||||||
|
|| fdh->elf.root.type == bfd_link_hash_defweak)
|
||||||
|
{
|
||||||
|
sym_sec = fdh->elf.root.u.def.section;
|
||||||
|
sym_value = fdh->elf.root.u.def.value;
|
||||||
|
if (sym_sec->output_section != NULL)
|
||||||
|
ok_dest = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (hash->elf.root.type == bfd_link_hash_defined
|
||||||
|
|| hash->elf.root.type == bfd_link_hash_defweak)
|
||||||
{
|
{
|
||||||
sym_value = hash->elf.root.u.def.value;
|
sym_value = hash->elf.root.u.def.value;
|
||||||
if (sym_sec->output_section != NULL)
|
if (sym_sec->output_section != NULL)
|
||||||
|
@ -7013,6 +7267,34 @@ ppc64_elf_size_stubs (bfd *output_bfd,
|
||||||
+ sym_sec->output_section->vma);
|
+ sym_sec->output_section->vma);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
code_sec = sym_sec;
|
||||||
|
opd_adjust = get_opd_info (sym_sec);
|
||||||
|
if (opd_adjust != NULL)
|
||||||
|
{
|
||||||
|
bfd_vma dest;
|
||||||
|
|
||||||
|
if (hash == NULL)
|
||||||
|
{
|
||||||
|
long adjust = opd_adjust[sym_value / 24];
|
||||||
|
if (adjust == -1)
|
||||||
|
continue;
|
||||||
|
sym_value += adjust;
|
||||||
|
}
|
||||||
|
dest = opd_entry_value (sym_sec, sym_value,
|
||||||
|
&code_sec, &sym_value);
|
||||||
|
if (dest != (bfd_vma) -1)
|
||||||
|
{
|
||||||
|
destination = dest;
|
||||||
|
if (fdh != NULL)
|
||||||
|
{
|
||||||
|
/* Fixup old ABI sym to point at code
|
||||||
|
entry. */
|
||||||
|
hash->elf.root.u.def.section = code_sec;
|
||||||
|
hash->elf.root.u.def.value = sym_value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Determine what (if any) linker stub is needed. */
|
/* Determine what (if any) linker stub is needed. */
|
||||||
stub_type = ppc_type_of_stub (section, irela, &hash,
|
stub_type = ppc_type_of_stub (section, irela, &hash,
|
||||||
destination);
|
destination);
|
||||||
|
@ -7025,11 +7307,11 @@ ppc64_elf_size_stubs (bfd *output_bfd,
|
||||||
_init and _fini functions, it may be that a
|
_init and _fini functions, it may be that a
|
||||||
call to what looks like a local sym is in
|
call to what looks like a local sym is in
|
||||||
fact a call needing a TOC adjustment. */
|
fact a call needing a TOC adjustment. */
|
||||||
if (sym_sec != NULL
|
if (code_sec != NULL
|
||||||
&& sym_sec->output_section != NULL
|
&& code_sec->output_section != NULL
|
||||||
&& (htab->stub_group[sym_sec->id].toc_off
|
&& (htab->stub_group[code_sec->id].toc_off
|
||||||
!= htab->stub_group[section->id].toc_off)
|
!= htab->stub_group[section->id].toc_off)
|
||||||
&& sym_sec->has_gp_reloc
|
&& code_sec->has_gp_reloc
|
||||||
&& section->has_gp_reloc)
|
&& section->has_gp_reloc)
|
||||||
stub_type = ppc_stub_long_branch_r2off;
|
stub_type = ppc_stub_long_branch_r2off;
|
||||||
}
|
}
|
||||||
|
@ -7040,7 +7322,8 @@ ppc64_elf_size_stubs (bfd *output_bfd,
|
||||||
/* __tls_get_addr calls might be eliminated. */
|
/* __tls_get_addr calls might be eliminated. */
|
||||||
if (stub_type != ppc_stub_plt_call
|
if (stub_type != ppc_stub_plt_call
|
||||||
&& hash != NULL
|
&& hash != NULL
|
||||||
&& &hash->elf == htab->tls_get_addr
|
&& (hash == htab->tls_get_addr
|
||||||
|
|| hash == htab->tls_get_addr_fd)
|
||||||
&& section->has_tls_reloc
|
&& section->has_tls_reloc
|
||||||
&& irela != internal_relocs)
|
&& irela != internal_relocs)
|
||||||
{
|
{
|
||||||
|
@ -7088,7 +7371,7 @@ ppc64_elf_size_stubs (bfd *output_bfd,
|
||||||
|
|
||||||
stub_entry->stub_type = stub_type;
|
stub_entry->stub_type = stub_type;
|
||||||
stub_entry->target_value = sym_value;
|
stub_entry->target_value = sym_value;
|
||||||
stub_entry->target_section = sym_sec;
|
stub_entry->target_section = code_sec;
|
||||||
stub_entry->h = hash;
|
stub_entry->h = hash;
|
||||||
stub_entry->addend = irela->r_addend;
|
stub_entry->addend = irela->r_addend;
|
||||||
stub_changed = TRUE;
|
stub_changed = TRUE;
|
||||||
|
@ -7772,7 +8055,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
|
||||||
while (h2->root.type == bfd_link_hash_indirect
|
while (h2->root.type == bfd_link_hash_indirect
|
||||||
|| h2->root.type == bfd_link_hash_warning)
|
|| h2->root.type == bfd_link_hash_warning)
|
||||||
h2 = (struct elf_link_hash_entry *) h2->root.u.i.link;
|
h2 = (struct elf_link_hash_entry *) h2->root.u.i.link;
|
||||||
if (h2 == NULL || h2 != htab->tls_get_addr)
|
if (h2 == NULL || (h2 != &htab->tls_get_addr->elf
|
||||||
|
&& h2 != &htab->tls_get_addr_fd->elf))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* OK, it checks out. Replace the call. */
|
/* OK, it checks out. Replace the call. */
|
||||||
|
@ -7908,10 +8192,12 @@ ppc64_elf_relocate_section (bfd *output_bfd,
|
||||||
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;
|
stub_entry = NULL;
|
||||||
|
fdh = h;
|
||||||
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)->plt.plist != NULL))
|
||||||
|
|| (sec != NULL
|
||||||
&& sec->output_section != NULL
|
&& sec->output_section != NULL
|
||||||
&& sec->id <= htab->top_id
|
&& sec->id <= htab->top_id
|
||||||
&& (htab->stub_group[sec->id].toc_off
|
&& (htab->stub_group[sec->id].toc_off
|
||||||
|
@ -7990,6 +8276,20 @@ ppc64_elf_relocate_section (bfd *output_bfd,
|
||||||
unresolved_reloc = FALSE;
|
unresolved_reloc = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (stub_entry == NULL
|
||||||
|
&& get_opd_info (sec) != NULL)
|
||||||
|
{
|
||||||
|
/* The branch destination is the value of the opd entry. */
|
||||||
|
bfd_vma off = (relocation - sec->output_section->vma
|
||||||
|
- sec->output_offset + rel->r_addend);
|
||||||
|
bfd_vma dest = opd_entry_value (sec, off, NULL, NULL);
|
||||||
|
if (dest != (bfd_vma) -1)
|
||||||
|
{
|
||||||
|
relocation = dest;
|
||||||
|
addend = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* If the branch is out of reach we ought to have a long
|
/* If the branch is out of reach we ought to have a long
|
||||||
branch stub. */
|
branch stub. */
|
||||||
from = (rel->r_offset
|
from = (rel->r_offset
|
||||||
|
@ -8799,41 +9099,37 @@ ppc64_elf_finish_dynamic_symbol (bfd *output_bfd,
|
||||||
{
|
{
|
||||||
struct ppc_link_hash_table *htab;
|
struct ppc_link_hash_table *htab;
|
||||||
bfd *dynobj;
|
bfd *dynobj;
|
||||||
|
struct plt_entry *ent;
|
||||||
|
Elf_Internal_Rela rela;
|
||||||
|
bfd_byte *loc;
|
||||||
|
|
||||||
htab = ppc_hash_table (info);
|
htab = ppc_hash_table (info);
|
||||||
dynobj = htab->elf.dynobj;
|
dynobj = htab->elf.dynobj;
|
||||||
|
|
||||||
if (((struct ppc_link_hash_entry *) h)->is_func_descriptor)
|
for (ent = h->plt.plist; ent != NULL; ent = ent->next)
|
||||||
{
|
if (ent->plt.offset != (bfd_vma) -1)
|
||||||
struct plt_entry *ent;
|
{
|
||||||
Elf_Internal_Rela rela;
|
/* This symbol has an entry in the procedure linkage
|
||||||
bfd_byte *loc;
|
table. Set it up. */
|
||||||
|
|
||||||
for (ent = h->plt.plist; ent != NULL; ent = ent->next)
|
if (htab->plt == NULL
|
||||||
if (ent->plt.offset != (bfd_vma) -1)
|
|| htab->relplt == NULL
|
||||||
{
|
|| htab->glink == NULL)
|
||||||
/* This symbol has an entry in the procedure linkage
|
abort ();
|
||||||
table. Set it up. */
|
|
||||||
|
|
||||||
if (htab->plt == NULL
|
/* Create a JMP_SLOT reloc to inform the dynamic linker to
|
||||||
|| htab->relplt == NULL
|
fill in the PLT entry. */
|
||||||
|| htab->glink == NULL)
|
rela.r_offset = (htab->plt->output_section->vma
|
||||||
abort ();
|
+ htab->plt->output_offset
|
||||||
|
+ ent->plt.offset);
|
||||||
|
rela.r_info = ELF64_R_INFO (h->dynindx, R_PPC64_JMP_SLOT);
|
||||||
|
rela.r_addend = ent->addend;
|
||||||
|
|
||||||
/* Create a JMP_SLOT reloc to inform the dynamic linker to
|
loc = htab->relplt->contents;
|
||||||
fill in the PLT entry. */
|
loc += ((ent->plt.offset - PLT_INITIAL_ENTRY_SIZE) / PLT_ENTRY_SIZE
|
||||||
rela.r_offset = (htab->plt->output_section->vma
|
* sizeof (Elf64_External_Rela));
|
||||||
+ htab->plt->output_offset
|
bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
|
||||||
+ ent->plt.offset);
|
}
|
||||||
rela.r_info = ELF64_R_INFO (h->dynindx, R_PPC64_JMP_SLOT);
|
|
||||||
rela.r_addend = ent->addend;
|
|
||||||
|
|
||||||
loc = htab->relplt->contents;
|
|
||||||
loc += ((ent->plt.offset - PLT_INITIAL_ENTRY_SIZE) / PLT_ENTRY_SIZE
|
|
||||||
* sizeof (Elf64_External_Rela));
|
|
||||||
bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_COPY) != 0)
|
if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_COPY) != 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -4194,6 +4194,55 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return the linker hash table entry of a symbol that might be
|
||||||
|
satisfied by an archive symbol. Return -1 on error. */
|
||||||
|
|
||||||
|
struct elf_link_hash_entry *
|
||||||
|
_bfd_elf_archive_symbol_lookup (bfd *abfd,
|
||||||
|
struct bfd_link_info *info,
|
||||||
|
const char *name)
|
||||||
|
{
|
||||||
|
struct elf_link_hash_entry *h;
|
||||||
|
char *p, *copy;
|
||||||
|
size_t len, first;
|
||||||
|
|
||||||
|
h = elf_link_hash_lookup (elf_hash_table (info), name, FALSE, FALSE, FALSE);
|
||||||
|
if (h != NULL)
|
||||||
|
return h;
|
||||||
|
|
||||||
|
/* If this is a default version (the name contains @@), look up the
|
||||||
|
symbol again with only one `@' as well as without the version.
|
||||||
|
The effect is that references to the symbol with and without the
|
||||||
|
version will be matched by the default symbol in the archive. */
|
||||||
|
|
||||||
|
p = strchr (name, ELF_VER_CHR);
|
||||||
|
if (p == NULL || p[1] != ELF_VER_CHR)
|
||||||
|
return h;
|
||||||
|
|
||||||
|
/* First check with only one `@'. */
|
||||||
|
len = strlen (name);
|
||||||
|
copy = bfd_alloc (abfd, len);
|
||||||
|
if (copy == NULL)
|
||||||
|
return (struct elf_link_hash_entry *) 0 - 1;
|
||||||
|
|
||||||
|
first = p - name + 1;
|
||||||
|
memcpy (copy, name, first);
|
||||||
|
memcpy (copy + first, name + first + 1, len - first);
|
||||||
|
|
||||||
|
h = elf_link_hash_lookup (elf_hash_table (info), copy, FALSE, FALSE, FALSE);
|
||||||
|
if (h == NULL)
|
||||||
|
{
|
||||||
|
/* We also need to check references to the symbol without the
|
||||||
|
version. */
|
||||||
|
copy[first - 1] = '\0';
|
||||||
|
h = elf_link_hash_lookup (elf_hash_table (info), copy,
|
||||||
|
FALSE, FALSE, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
bfd_release (abfd, copy);
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
/* Add symbols from an ELF archive file to the linker hash table. We
|
/* Add symbols from an ELF archive file to the linker hash table. We
|
||||||
don't use _bfd_generic_link_add_archive_symbols because of a
|
don't use _bfd_generic_link_add_archive_symbols because of a
|
||||||
problem which arises on UnixWare. The UnixWare libc.so is an
|
problem which arises on UnixWare. The UnixWare libc.so is an
|
||||||
|
@ -4228,6 +4277,9 @@ elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info)
|
||||||
carsym *symdefs;
|
carsym *symdefs;
|
||||||
bfd_boolean loop;
|
bfd_boolean loop;
|
||||||
bfd_size_type amt;
|
bfd_size_type amt;
|
||||||
|
const struct elf_backend_data *bed;
|
||||||
|
struct elf_link_hash_entry * (*archive_symbol_lookup)
|
||||||
|
(bfd *, struct bfd_link_info *, const char *);
|
||||||
|
|
||||||
if (! bfd_has_map (abfd))
|
if (! bfd_has_map (abfd))
|
||||||
{
|
{
|
||||||
|
@ -4252,6 +4304,8 @@ elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info)
|
||||||
goto error_return;
|
goto error_return;
|
||||||
|
|
||||||
symdefs = bfd_ardata (abfd)->symdefs;
|
symdefs = bfd_ardata (abfd)->symdefs;
|
||||||
|
bed = get_elf_backend_data (abfd);
|
||||||
|
archive_symbol_lookup = bed->elf_backend_archive_symbol_lookup;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
@ -4280,48 +4334,9 @@ elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
h = elf_link_hash_lookup (elf_hash_table (info), symdef->name,
|
h = archive_symbol_lookup (abfd, info, symdef->name);
|
||||||
FALSE, FALSE, FALSE);
|
if (h == (struct elf_link_hash_entry *) 0 - 1)
|
||||||
|
goto error_return;
|
||||||
if (h == NULL)
|
|
||||||
{
|
|
||||||
char *p, *copy;
|
|
||||||
size_t len, first;
|
|
||||||
|
|
||||||
/* If this is a default version (the name contains @@),
|
|
||||||
look up the symbol again with only one `@' as well
|
|
||||||
as without the version. The effect is that references
|
|
||||||
to the symbol with and without the version will be
|
|
||||||
matched by the default symbol in the archive. */
|
|
||||||
|
|
||||||
p = strchr (symdef->name, ELF_VER_CHR);
|
|
||||||
if (p == NULL || p[1] != ELF_VER_CHR)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* First check with only one `@'. */
|
|
||||||
len = strlen (symdef->name);
|
|
||||||
copy = bfd_alloc (abfd, len);
|
|
||||||
if (copy == NULL)
|
|
||||||
goto error_return;
|
|
||||||
first = p - symdef->name + 1;
|
|
||||||
memcpy (copy, symdef->name, first);
|
|
||||||
memcpy (copy + first, symdef->name + first + 1, len - first);
|
|
||||||
|
|
||||||
h = elf_link_hash_lookup (elf_hash_table (info), copy,
|
|
||||||
FALSE, FALSE, FALSE);
|
|
||||||
|
|
||||||
if (h == NULL)
|
|
||||||
{
|
|
||||||
/* We also need to check references to the symbol
|
|
||||||
without the version. */
|
|
||||||
|
|
||||||
copy[first - 1] = '\0';
|
|
||||||
h = elf_link_hash_lookup (elf_hash_table (info),
|
|
||||||
copy, FALSE, FALSE, FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
bfd_release (abfd, copy);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (h == NULL)
|
if (h == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -299,6 +299,9 @@
|
||||||
#ifndef elf_backend_get_symbol_type
|
#ifndef elf_backend_get_symbol_type
|
||||||
#define elf_backend_get_symbol_type 0
|
#define elf_backend_get_symbol_type 0
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef elf_backend_archive_symbol_lookup
|
||||||
|
#define elf_backend_archive_symbol_lookup _bfd_elf_archive_symbol_lookup
|
||||||
|
#endif
|
||||||
#ifndef elf_backend_name_local_section_symbols
|
#ifndef elf_backend_name_local_section_symbols
|
||||||
#define elf_backend_name_local_section_symbols 0
|
#define elf_backend_name_local_section_symbols 0
|
||||||
#endif
|
#endif
|
||||||
|
@ -510,6 +513,7 @@ static const struct elf_backend_data elfNN_bed =
|
||||||
elf_backend_symbol_processing,
|
elf_backend_symbol_processing,
|
||||||
elf_backend_symbol_table_processing,
|
elf_backend_symbol_table_processing,
|
||||||
elf_backend_get_symbol_type,
|
elf_backend_get_symbol_type,
|
||||||
|
elf_backend_archive_symbol_lookup,
|
||||||
elf_backend_name_local_section_symbols,
|
elf_backend_name_local_section_symbols,
|
||||||
elf_backend_section_processing,
|
elf_backend_section_processing,
|
||||||
elf_backend_section_from_shdr,
|
elf_backend_section_from_shdr,
|
||||||
|
|
Loading…
Add table
Reference in a new issue