* 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:
Alan Modra 2004-08-09 06:02:03 +00:00
parent fed7ba43e0
commit 8387904def
5 changed files with 498 additions and 153 deletions

View File

@ -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>
* elf64-ppc.c (struct ppc_link_hash_entry): Expand adjust_done comment.
@ -21,7 +45,6 @@
(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>

View File

@ -579,11 +579,16 @@ struct elf_backend_data
bfd_boolean (*elf_backend_symbol_table_processing)
(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. */
int (*elf_backend_get_symbol_type)
(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.
NULL implies false. */
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
(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
(bfd *, struct bfd_link_info *);
extern bfd_boolean _bfd_elf_add_dynamic_entry

View File

@ -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_copy_indirect_symbol ppc64_elf_copy_indirect_symbol
#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_gc_mark_hook ppc64_elf_gc_mark_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
dynamic so that references to .foo are satisfied during the early
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
decides to copy as dynamic relocs in check_relocs for each symbol.
@ -2857,8 +2863,9 @@ struct ppc_link_hash_table
asection *brlt;
asection *relbrlt;
/* Shortcut to .__tls_get_addr. */
struct elf_link_hash_entry *tls_get_addr;
/* Shortcut to .__tls_get_addr and __tls_get_addr. */
struct ppc_link_hash_entry *tls_get_addr;
struct ppc_link_hash_entry *tls_get_addr_fd;
/* Statistics. */
unsigned long stub_count[ppc_stub_plt_call];
@ -3463,7 +3470,49 @@ ppc64_elf_copy_indirect_symbol
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
ppc64_elf_add_symbol_hook (bfd *ibfd ATTRIBUTE_UNUSED,
@ -3480,6 +3529,80 @@ ppc64_elf_add_symbol_hook (bfd *ibfd ATTRIBUTE_UNUSED,
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
update_local_sym_info (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
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;
}
/* 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
calculate needed space in the global offset table, procedure
linkage table, and dynamic reloc sections. */
@ -3815,23 +3913,30 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
/* Fall through. */
case R_PPC64_REL24:
if (h != NULL
&& h->root.root.string[0] == '.'
&& h->root.root.string[1] != 0)
if (h != NULL)
{
/* We may need a .plt entry if the function this reloc
refers to is in a shared lib. */
if (!update_plt_info (abfd, (struct ppc_link_hash_entry *) h,
rel->r_addend))
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;
else if ((strncmp (h->root.root.string, ".__tls_get_addr", 15)
== 0)
else if (htab->tls_get_addr == NULL
&& !strncmp (h->root.root.string, ".__tls_get_addr", 15)
&& (h->root.root.string[15] == 0
|| 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;
}
}
@ -3912,24 +4017,29 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
case R_PPC64_ADDR64:
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
&& 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,
r_symndx);
if (s == NULL)
return FALSE;
else if (s != sec)
opd_sym_map[rel->r_offset / 24] = s;
s = bfd_section_from_r_symndx (abfd, &htab->sym_sec, sec,
r_symndx);
if (s == NULL)
return FALSE;
else if (s != sec)
opd_sym_map[rel->r_offset / 24] = s;
}
}
/* Fall through. */
@ -4095,6 +4205,94 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
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
relocation. */
@ -4128,6 +4326,11 @@ ppc64_elf_gc_mark_hook (asection *sec,
if (eh->is_func_descriptor)
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
continue;
@ -4181,6 +4384,15 @@ ppc64_elf_gc_mark_hook (asection *sec,
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
rsec = h->root.u.def.section;
break;
@ -4445,7 +4657,11 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf)
| ELF_LINK_NON_GOT_REF));
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->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)
if (ent->plt.refcount > 0)
break;
if (!((struct ppc_link_hash_entry *) h)->is_func_descriptor
|| ent == NULL
if (ent == NULL
|| SYMBOL_CALLS_LOCAL (info, h)
|| (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
&& 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
code these will already have been done, but I suppose we have to
cater for all sorts of hand written assembly. */
code for the old ABI, these will already have been done. */
static bfd_boolean
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);
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
|| h->root.type == bfd_link_hash_warning)
h = (struct elf_link_hash_entry *) h->root.u.i.link;
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 = 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);
@ -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_REL24:
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
&& 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)
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
first entry. */
s = htab->plt;
@ -6164,14 +6393,18 @@ ppc_type_of_stub (asection *input_sec,
if (h != 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;
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
&& ent->plt.offset != (bfd_vma) -1)
{
*hash = h->oh;
*hash = h;
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
exporting ".foo" for each "foo". This can happen when symbol
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)
{
/* 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
&& !(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.u.def.section == stub_entry->stub_sec
&& 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;
enum ppc_stub_type stub_type;
struct ppc_stub_hash_entry *stub_entry;
asection *sym_sec;
asection *sym_sec, *code_sec;
bfd_vma sym_value;
bfd_vma destination;
bfd_boolean ok_dest;
struct ppc_link_hash_entry *hash;
struct ppc_link_hash_entry *fdh;
struct elf_link_hash_entry *h;
Elf_Internal_Sym *sym;
char *stub_name;
const asection *id_sec;
long *opd_adjust;
r_type = ELF64_R_TYPE (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;
ok_dest = FALSE;
fdh = NULL;
if (hash == NULL)
{
/* It's a local symbol. */
sym_value = sym->st_value;
ok_dest = TRUE;
}
else
{
/* It's an external symbol. */
sym_value = 0;
if (hash->elf.root.type == bfd_link_hash_defined
|| hash->elf.root.type == bfd_link_hash_defweak)
/* Recognise an old ABI func code entry sym by
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;
if (sym_sec->output_section != NULL)
@ -7013,6 +7267,34 @@ ppc64_elf_size_stubs (bfd *output_bfd,
+ 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. */
stub_type = ppc_type_of_stub (section, irela, &hash,
destination);
@ -7025,11 +7307,11 @@ ppc64_elf_size_stubs (bfd *output_bfd,
_init and _fini functions, it may be that a
call to what looks like a local sym is in
fact a call needing a TOC adjustment. */
if (sym_sec != NULL
&& sym_sec->output_section != NULL
&& (htab->stub_group[sym_sec->id].toc_off
if (code_sec != NULL
&& code_sec->output_section != NULL
&& (htab->stub_group[code_sec->id].toc_off
!= htab->stub_group[section->id].toc_off)
&& sym_sec->has_gp_reloc
&& code_sec->has_gp_reloc
&& section->has_gp_reloc)
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. */
if (stub_type != ppc_stub_plt_call
&& hash != NULL
&& &hash->elf == htab->tls_get_addr
&& (hash == htab->tls_get_addr
|| hash == htab->tls_get_addr_fd)
&& section->has_tls_reloc
&& irela != internal_relocs)
{
@ -7088,7 +7371,7 @@ ppc64_elf_size_stubs (bfd *output_bfd,
stub_entry->stub_type = stub_type;
stub_entry->target_value = sym_value;
stub_entry->target_section = sym_sec;
stub_entry->target_section = code_sec;
stub_entry->h = hash;
stub_entry->addend = irela->r_addend;
stub_changed = TRUE;
@ -7772,7 +8055,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
while (h2->root.type == bfd_link_hash_indirect
|| h2->root.type == bfd_link_hash_warning)
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;
/* 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
base pointer. */
stub_entry = NULL;
fdh = h;
if (((h != NULL
&& (fdh = &((struct ppc_link_hash_entry *) h)->oh->elf) != NULL
&& fdh->plt.plist != NULL)
|| ((fdh = h, sec) != NULL
&& (((fdh = &((struct ppc_link_hash_entry *) h)->oh->elf) != NULL
&& fdh->plt.plist != NULL)
|| (fdh = h)->plt.plist != NULL))
|| (sec != NULL
&& sec->output_section != NULL
&& sec->id <= htab->top_id
&& (htab->stub_group[sec->id].toc_off
@ -7990,6 +8276,20 @@ ppc64_elf_relocate_section (bfd *output_bfd,
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
branch stub. */
from = (rel->r_offset
@ -8799,41 +9099,37 @@ ppc64_elf_finish_dynamic_symbol (bfd *output_bfd,
{
struct ppc_link_hash_table *htab;
bfd *dynobj;
struct plt_entry *ent;
Elf_Internal_Rela rela;
bfd_byte *loc;
htab = ppc_hash_table (info);
dynobj = htab->elf.dynobj;
if (((struct ppc_link_hash_entry *) h)->is_func_descriptor)
{
struct plt_entry *ent;
Elf_Internal_Rela rela;
bfd_byte *loc;
for (ent = h->plt.plist; ent != NULL; ent = ent->next)
if (ent->plt.offset != (bfd_vma) -1)
{
/* This symbol has an entry in the procedure linkage
table. Set it up. */
for (ent = h->plt.plist; ent != NULL; ent = ent->next)
if (ent->plt.offset != (bfd_vma) -1)
{
/* This symbol has an entry in the procedure linkage
table. Set it up. */
if (htab->plt == NULL
|| htab->relplt == NULL
|| htab->glink == NULL)
abort ();
if (htab->plt == NULL
|| htab->relplt == NULL
|| htab->glink == NULL)
abort ();
/* Create a JMP_SLOT reloc to inform the dynamic linker to
fill in the PLT entry. */
rela.r_offset = (htab->plt->output_section->vma
+ 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
fill in the PLT entry. */
rela.r_offset = (htab->plt->output_section->vma
+ htab->plt->output_offset
+ 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);
}
}
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)
{

View File

@ -4194,6 +4194,55 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
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
don't use _bfd_generic_link_add_archive_symbols because of a
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;
bfd_boolean loop;
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))
{
@ -4252,6 +4304,8 @@ elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info)
goto error_return;
symdefs = bfd_ardata (abfd)->symdefs;
bed = get_elf_backend_data (abfd);
archive_symbol_lookup = bed->elf_backend_archive_symbol_lookup;
do
{
@ -4280,48 +4334,9 @@ elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info)
continue;
}
h = elf_link_hash_lookup (elf_hash_table (info), symdef->name,
FALSE, FALSE, FALSE);
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);
}
h = archive_symbol_lookup (abfd, info, symdef->name);
if (h == (struct elf_link_hash_entry *) 0 - 1)
goto error_return;
if (h == NULL)
continue;

View File

@ -299,6 +299,9 @@
#ifndef elf_backend_get_symbol_type
#define elf_backend_get_symbol_type 0
#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
#define elf_backend_name_local_section_symbols 0
#endif
@ -510,6 +513,7 @@ static const struct elf_backend_data elfNN_bed =
elf_backend_symbol_processing,
elf_backend_symbol_table_processing,
elf_backend_get_symbol_type,
elf_backend_archive_symbol_lookup,
elf_backend_name_local_section_symbols,
elf_backend_section_processing,
elf_backend_section_from_shdr,