/* PowerPC64-specific support for 64-bit ELF.
- Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005
+ Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
Free Software Foundation, Inc.
Written by Linus Nordberg, Swox AB <info@swox.com>,
based on elf32-ppc.c by Ian Lance Taylor.
#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_dynamic_ref ppc64_elf_gc_mark_dynamic_ref
#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_adjust_dynamic_symbol ppc64_elf_adjust_dynamic_symbol
#define elf_backend_hide_symbol ppc64_elf_hide_symbol
#define elf_backend_always_size_sections ppc64_elf_func_desc_adjust
#define elf_backend_size_dynamic_sections ppc64_elf_size_dynamic_sections
+#define elf_backend_action_discarded ppc64_elf_action_discarded
#define elf_backend_relocate_section ppc64_elf_relocate_section
#define elf_backend_finish_dynamic_symbol ppc64_elf_finish_dynamic_symbol
#define elf_backend_reloc_type_class ppc64_elf_reloc_type_class
if (htab == NULL)
return NULL;
- if (! _bfd_elf_link_hash_table_init (&htab->elf, abfd, link_hash_newfunc))
+ if (!_bfd_elf_link_hash_table_init (&htab->elf, abfd, link_hash_newfunc,
+ sizeof (struct ppc_link_hash_entry)))
{
free (htab);
return NULL;
}
/* Init the stub hash table too. */
- if (!bfd_hash_table_init (&htab->stub_hash_table, stub_hash_newfunc))
+ if (!bfd_hash_table_init (&htab->stub_hash_table, stub_hash_newfunc,
+ sizeof (struct ppc_stub_hash_entry)))
return NULL;
/* And the branch hash table. */
- if (!bfd_hash_table_init (&htab->branch_hash_table, branch_hash_newfunc))
+ if (!bfd_hash_table_init (&htab->branch_hash_table, branch_hash_newfunc,
+ sizeof (struct ppc_branch_hash_entry)))
return NULL;
/* Initializing two fields of the union is just cosmetic. We really
/* Copy the extra info we tack onto an elf_link_hash_entry. */
static void
-ppc64_elf_copy_indirect_symbol
- (const struct elf_backend_data *bed ATTRIBUTE_UNUSED,
- struct elf_link_hash_entry *dir,
- struct elf_link_hash_entry *ind)
+ppc64_elf_copy_indirect_symbol (struct bfd_link_info *info,
+ struct elf_link_hash_entry *dir,
+ struct elf_link_hash_entry *ind)
{
struct ppc_link_hash_entry *edir, *eind;
struct ppc_dyn_relocs **pp;
struct ppc_dyn_relocs *p;
- if (eind->elf.root.type == bfd_link_hash_indirect)
- abort ();
-
- /* Add reloc counts against the weak sym to the strong sym
+ /* Add reloc counts against the indirect sym to the direct sym
list. Merge any entries against the same section. */
for (pp = &eind->dyn_relocs; (p = *pp) != NULL; )
{
/* And plt entries. */
move_plt_plist (eind, edir);
- if (edir->elf.dynindx == -1)
+ if (eind->elf.dynindx != -1)
{
+ if (edir->elf.dynindx != -1)
+ _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr,
+ edir->elf.dynstr_index);
edir->elf.dynindx = eind->elf.dynindx;
edir->elf.dynstr_index = eind->elf.dynstr_index;
eind->elf.dynindx = -1;
eind->elf.dynstr_index = 0;
}
- else
- BFD_ASSERT (eind->elf.dynindx == -1);
}
/* Find the function descriptor hash entry from the given function code
case R_PPC64_REL14:
case R_PPC64_REL14_BRTAKEN:
case R_PPC64_REL14_BRNTAKEN:
- htab->has_14bit_branch = 1;
+ {
+ asection *dest = NULL;
+
+ /* Heuristic: If jumping outside our section, chances are
+ we are going to need a stub. */
+ if (h != NULL)
+ {
+ /* If the sym is weak it may be overridden later, so
+ don't assume we know where a weak sym lives. */
+ if (h->root.type == bfd_link_hash_defined)
+ dest = h->root.u.def.section;
+ }
+ else
+ dest = bfd_section_from_r_symndx (abfd, &htab->sym_sec,
+ sec, r_symndx);
+ if (dest != sec)
+ htab->has_14bit_branch = 1;
+ }
/* Fall through. */
case R_PPC64_REL24:
easily. Oh well. */
asection *s;
+ void *vpp;
+
s = bfd_section_from_r_symndx (abfd, &htab->sym_sec,
sec, r_symndx);
if (s == NULL)
return FALSE;
- head = ((struct ppc_dyn_relocs **)
- &elf_section_data (s)->local_dynrel);
+ vpp = &elf_section_data (s)->local_dynrel;
+ head = (struct ppc_dyn_relocs **) vpp;
}
p = *head;
return val;
}
+/* Mark sections containing dynamically referenced symbols. When
+ building shared libraries, we must assume that any visible symbol is
+ referenced. */
+
+static bfd_boolean
+ppc64_elf_gc_mark_dynamic_ref (struct elf_link_hash_entry *h, void *inf)
+{
+ struct bfd_link_info *info = (struct bfd_link_info *) inf;
+ struct ppc_link_hash_entry *eh = (struct ppc_link_hash_entry *) h;
+
+ if (eh->elf.root.type == bfd_link_hash_warning)
+ eh = (struct ppc_link_hash_entry *) eh->elf.root.u.i.link;
+
+ /* Dynamic linking info is on the func descriptor sym. */
+ if (eh->oh != NULL
+ && eh->oh->is_func_descriptor
+ && (eh->oh->elf.root.type == bfd_link_hash_defined
+ || eh->oh->elf.root.type == bfd_link_hash_defweak))
+ eh = eh->oh;
+
+ if ((eh->elf.root.type == bfd_link_hash_defined
+ || eh->elf.root.type == bfd_link_hash_defweak)
+ && (eh->elf.ref_dynamic
+ || (!info->executable
+ && eh->elf.def_regular
+ && ELF_ST_VISIBILITY (eh->elf.other) != STV_INTERNAL
+ && ELF_ST_VISIBILITY (eh->elf.other) != STV_HIDDEN)))
+ {
+ asection *code_sec;
+
+ eh->elf.root.u.def.section->flags |= SEC_KEEP;
+
+ /* Function descriptor syms cause the associated
+ function code sym section to be marked. */
+ if (eh->is_func_descriptor
+ && (eh->oh->elf.root.type == bfd_link_hash_defined
+ || eh->oh->elf.root.type == bfd_link_hash_defweak))
+ eh->oh->elf.root.u.def.section->flags |= SEC_KEEP;
+ 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,
+ &code_sec, NULL) != (bfd_vma) -1)
+ code_sec->flags |= SEC_KEEP;
+ }
+
+ return TRUE;
+}
+
/* Return the section that should be marked against GC for a given
relocation. */
struct bfd_sym_chain *sym = info->gc_sym_list;
info->gc_sym_list = NULL;
- do
+ for (; sym != NULL; sym = sym->next)
{
struct ppc_link_hash_entry *eh;
rsec = eh->elf.root.u.def.section;
if (!rsec->gc_mark)
_bfd_elf_gc_mark (info, rsec, ppc64_elf_gc_mark_hook);
-
- sym = sym->next;
}
- while (sym != NULL);
}
/* Syms return NULL if we're marking .opd, so we avoid marking all
/* This is a reference to a symbol defined by a dynamic object which
is not a function. */
+ if (h->size == 0)
+ {
+ (*_bfd_error_handler) (_("dynamic variable `%s' is zero size"),
+ h->root.root.string);
+ return TRUE;
+ }
+
/* We must allocate the symbol in our .dynbss section, which will
become part of the .bss section of the executable. There will be
an entry for this symbol in the .dynsym section. The dynamic
if (h != NULL)
pp = &((struct ppc_link_hash_entry *) h)->dyn_relocs;
- else if (sym_sec != NULL)
- pp = (struct ppc_dyn_relocs **) &elf_section_data (sym_sec)->local_dynrel;
else
- pp = (struct ppc_dyn_relocs **) &elf_section_data (sec)->local_dynrel;
+ {
+ if (sym_sec != NULL)
+ {
+ void *vpp = &elf_section_data (sym_sec)->local_dynrel;
+ pp = (struct ppc_dyn_relocs **) vpp;
+ }
+ else
+ {
+ void *vpp = &elf_section_data (sec)->local_dynrel;
+ pp = (struct ppc_dyn_relocs **) vpp;
+ }
+
+ /* elf_gc_sweep may have already removed all dyn relocs associated
+ with local syms for a given section. Don't report a dynreloc
+ miscount. */
+ if (*pp == NULL)
+ return TRUE;
+ }
while ((p = *pp) != NULL)
{
if (skip)
{
- if (!info->relocatable
+ if (!NO_OPD_RELOCS
+ && !info->relocatable
&& !dec_dynrel_count (rel->r_info, sec, info,
NULL, h, sym_sec))
goto error_ret;
/* Also discard relocs on undefined weak syms with non-default
visibility. */
- if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
+ if (eh->dyn_relocs != NULL
&& h->root.type == bfd_link_hash_undefweak)
- eh->dyn_relocs = NULL;
+ {
+ if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
+ eh->dyn_relocs = NULL;
+
+ /* Make sure this symbol is output as a dynamic symbol.
+ Undefined weak syms won't yet be marked as dynamic. */
+ else if (h->dynindx == -1
+ && !h->forced_local)
+ {
+ if (! bfd_elf_link_record_dynamic_symbol (info, h))
+ return FALSE;
+ }
+ }
}
else if (ELIMINATE_COPY_RELOCS)
{
{
struct ppc_dyn_relocs *p;
- for (p = *((struct ppc_dyn_relocs **)
- &elf_section_data (s)->local_dynrel);
- p != NULL;
- p = p->next)
+ for (p = elf_section_data (s)->local_dynrel; p != NULL; p = p->next)
{
if (!bfd_is_abs_section (p->sec)
&& bfd_is_abs_section (p->sec->output_section))
if (h != NULL)
{
- if (h->oh != NULL
- && h->oh->is_func_descriptor)
- h = h->oh;
+ struct ppc_link_hash_entry *fdh = h;
+ if (fdh->oh != NULL
+ && fdh->oh->is_func_descriptor)
+ fdh = fdh->oh;
- if (h->elf.dynindx != -1)
+ if (fdh->elf.dynindx != -1)
{
struct plt_entry *ent;
- for (ent = h->elf.plt.plist; ent != NULL; ent = ent->next)
+ for (ent = fdh->elf.plt.plist; ent != NULL; ent = ent->next)
if (ent->addend == rel->r_addend
&& ent->plt.offset != (bfd_vma) -1)
{
- *hash = h;
+ *hash = fdh;
return ppc_stub_plt_call;
}
}
- if (!(h->elf.root.type == bfd_link_hash_defined
- || h->elf.root.type == bfd_link_hash_defweak)
- || h->elf.root.u.def.section->output_section == NULL)
+ /* Here, we know we don't have a plt entry. If we don't have a
+ either a defined function descriptor or a defined entry symbol
+ in a regular object file, then it is pointless trying to make
+ any other type of stub. */
+ if (!((fdh->elf.root.type == bfd_link_hash_defined
+ || fdh->elf.root.type == bfd_link_hash_defweak)
+ && fdh->elf.root.u.def.section->output_section != NULL)
+ && !((h->elf.root.type == bfd_link_hash_defined
+ || h->elf.root.type == bfd_link_hash_defweak)
+ && h->elf.root.u.def.section->output_section != NULL))
return ppc_stub_none;
}
}
bfd_put_32 (htab->stub_bfd, B_DOT | (off & 0x3fffffc), loc);
- BFD_ASSERT (off + (1 << 25) < (bfd_vma) (1 << 26));
+ if (off + (1 << 25) >= (bfd_vma) (1 << 26))
+ {
+ (*_bfd_error_handler) (_("long branch stub `%s' offset overflow"),
+ stub_entry->root.string);
+ htab->stub_error = TRUE;
+ return FALSE;
+ }
if (info->emitrelocations)
{
if (br_entry == NULL)
{
(*_bfd_error_handler) (_("can't find branch stub `%s'"),
- stub_entry->root.string + 9);
+ stub_entry->root.string);
htab->stub_error = TRUE;
return FALSE;
}
if (br_entry == NULL)
{
(*_bfd_error_handler) (_("can't build branch stub `%s'"),
- stub_entry->root.string + 9);
+ stub_entry->root.string);
htab->stub_error = TRUE;
return FALSE;
}
curr = tail;
total = tail->size;
- big_sec = total >= stub_group_size;
+ big_sec = total > stub_group_size;
+ if (big_sec)
+ (*_bfd_error_handler) (_("%B section %A exceeds stub group size"),
+ tail->owner, tail);
curr_toc = htab->stub_group[tail->id].toc_off;
while ((prev = PREV_SEC (curr)) != NULL
bfd *input_bfd;
unsigned int bfd_indx;
asection *stub_sec;
- bfd_boolean stub_changed;
htab->stub_iteration += 1;
- stub_changed = FALSE;
for (input_bfd = info->input_bfds, bfd_indx = 0;
input_bfd != NULL;
asection *section;
Elf_Internal_Sym *local_syms = NULL;
+ if (!is_ppc64_elf_target (input_bfd->xvec))
+ continue;
+
/* We'll need the symbol table in a second. */
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
if (symtab_hdr->sh_info == 0)
ok_dest = FALSE;
fdh = NULL;
+ sym_value = 0;
if (hash == NULL)
{
sym_value = sym->st_value;
ok_dest = TRUE;
}
- else
+ 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)
+ ok_dest = TRUE;
+ }
+ else if (hash->elf.root.type == bfd_link_hash_undefweak
+ || hash->elf.root.type == bfd_link_hash_undefined)
{
- sym_value = 0;
/* Recognise an old ABI func code entry sym, and
- use the func descriptor sym instead. */
+ use the func descriptor sym instead if it is
+ defined. */
if (hash->elf.root.root.string[0] == '.'
&& (fdh = get_fdh (hash, htab)) != NULL)
{
else
fdh = NULL;
}
- 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)
- ok_dest = TRUE;
- }
- else if (hash->elf.root.type == bfd_link_hash_undefweak)
- ;
- else if (hash->elf.root.type == bfd_link_hash_undefined)
- ;
- else
- {
- bfd_set_error (bfd_error_bad_value);
- goto error_ret_free_internal;
- }
+ }
+ else
+ {
+ bfd_set_error (bfd_error_bad_value);
+ goto error_ret_free_internal;
}
destination = 0;
if (stub_entry->h != NULL)
htab->stub_globals += 1;
-
- stub_changed = TRUE;
}
/* We're done with the internal relocs, free them. */
}
}
- if (!stub_changed)
- break;
-
- /* OK, we've added some stubs. Find out the new size of the
+ /* We may have added some stubs. Find out the new size of the
stub sections. */
for (stub_sec = htab->stub_bfd->sections;
stub_sec != NULL;
stub_sec = stub_sec->next)
if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
{
+ stub_sec->rawsize = stub_sec->size;
stub_sec->size = 0;
stub_sec->reloc_count = 0;
}
bfd_hash_traverse (&htab->stub_hash_table, ppc_size_one_stub, info);
+ for (stub_sec = htab->stub_bfd->sections;
+ stub_sec != NULL;
+ stub_sec = stub_sec->next)
+ if ((stub_sec->flags & SEC_LINKER_CREATED) == 0
+ && stub_sec->rawsize != stub_sec->size)
+ break;
+
+ /* Exit from this loop when no stubs have been added, and no stubs
+ have changed size. */
+ if (stub_sec == NULL)
+ break;
+
/* Ask the linker to do its stuff. */
(*htab->layout_sections_again) ();
}
elf_link_hash_traverse (&htab->elf, undo_symbol_twiddle, info);
}
+/* What to do when ld finds relocations against symbols defined in
+ discarded sections. */
+
+static unsigned int
+ppc64_elf_action_discarded (asection *sec)
+{
+ if (strcmp (".opd", sec->name) == 0)
+ return 0;
+
+ if (strcmp (".toc", sec->name) == 0)
+ return 0;
+
+ if (strcmp (".toc1", sec->name) == 0)
+ return 0;
+
+ return _bfd_elf_default_action_discarded (sec);
+}
+
/* The RELOCATE_SECTION function is called by the ELF backend linker
to handle the relocations for a section.
/* Disabled until we sort out how ld should choose 'y' vs 'at'. */
bfd_boolean is_power4 = FALSE;
- if (info->relocatable)
- return TRUE;
-
/* Initialize howto table if needed. */
if (!ppc64_elf_howto_table[R_PPC64_ADDR32])
ppc_howto_init ();
for (; rel < relend; rel++)
{
enum elf_ppc64_reloc_type r_type;
- bfd_vma addend;
+ bfd_vma addend, orig_addend;
bfd_reloc_status_type r;
Elf_Internal_Sym *sym;
asection *sec;
sym_name = NULL;
unresolved_reloc = FALSE;
warned = FALSE;
+ orig_addend = rel->r_addend;
if (r_symndx < symtab_hdr->sh_info)
{
if (adjust == -1)
relocation = 0;
else
- relocation += adjust;
+ {
+ /* If this is a relocation against the opd section sym
+ and we have edited .opd, adjust the reloc addend so
+ that ld -r and ld --emit-relocs output is correct.
+ If it is a reloc against some other .opd symbol,
+ then the symbol value will be adjusted later. */
+ if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
+ rel->r_addend += adjust;
+ else
+ relocation += adjust;
+ }
}
+ if (info->relocatable)
+ continue;
}
else
{
+ if (info->relocatable)
+ continue;
RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
r_symndx, symtab_hdr, sym_hashes,
h_elf, sec, relocation,
if (stub_entry->stub_type == ppc_stub_plt_call)
{
/* If this is a plain branch rather than a branch
- and link, don't require a nop. */
+ and link, don't require a nop. However, don't
+ allow tail calls in a shared library as they
+ will result in r2 being corrupted. */
unsigned long br;
br = bfd_get_32 (input_bfd, contents + rel->r_offset);
- if ((br & 1) == 0)
+ if (info->executable && (br & 1) == 0)
can_plt_call = TRUE;
else
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 off = (relocation + addend
+ - sec->output_section->vma
+ - sec->output_offset);
bfd_vma dest = opd_entry_value (sec, off, NULL, NULL);
if (dest != (bfd_vma) -1)
{
+ input_section->output_section->vma);
if (stub_entry == NULL
- && (relocation + rel->r_addend - from + max_br_offset
+ && (relocation + addend - from + max_br_offset
>= 2 * max_br_offset)
&& r_type != R_PPC64_ADDR14_BRTAKEN
&& r_type != R_PPC64_ADDR14_BRNTAKEN)
else
{
/* Invert 'y' bit if not the default. */
- if ((bfd_signed_vma) (relocation + rel->r_addend - from) < 0)
+ if ((bfd_signed_vma) (relocation + addend - from) < 0)
insn ^= 0x01 << 21;
}
&& h->elf.root.type == bfd_link_hash_undefweak
&& r_type == R_PPC64_REL24
&& relocation == 0
- && rel->r_addend == 0)
+ && addend == 0)
{
bfd_put_32 (output_bfd, NOP, contents + rel->r_offset);
continue;
}
for (; ent != NULL; ent = ent->next)
- if (ent->addend == rel->r_addend
+ if (ent->addend == orig_addend
&& ent->owner == input_bfd
&& ent->tls_type == tls_type)
break;
outrel.r_offset = (got->output_section->vma
+ got->output_offset
+ off);
- outrel.r_addend = rel->r_addend;
+ outrel.r_addend = addend;
if (tls_type & (TLS_LD | TLS_GD))
{
outrel.r_addend = 0;
bfd_elf64_swap_reloca_out (output_bfd,
&outrel, loc);
outrel.r_offset += 8;
- outrel.r_addend = rel->r_addend;
+ outrel.r_addend = addend;
outrel.r_info
= ELF64_R_INFO (indx, R_PPC64_DTPREL64);
}
emitting a reloc. */
else
{
- relocation += rel->r_addend;
+ relocation += addend;
if (tls_type == (TLS_TLS | TLS_LD))
relocation = 1;
else if (tls_type != 0)
{
struct plt_entry *ent;
for (ent = h->elf.plt.plist; ent != NULL; ent = ent->next)
- if (ent->addend == rel->r_addend
+ if (ent->addend == orig_addend
&& ent->plt.offset != (bfd_vma) -1)
{
relocation = (htab->plt->output_section->vma
if (sreloc == NULL)
abort ();
+ if (sreloc->reloc_count * sizeof (Elf64_External_Rela)
+ >= sreloc->size)
+ abort ();
loc = sreloc->contents;
loc += sreloc->reloc_count++ * sizeof (Elf64_External_Rela);
bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
if (!((*info->callbacks->reloc_overflow)
(info, (h ? &h->elf.root : NULL), sym_name,
ppc64_elf_howto_table[r_type]->name,
- rel->r_addend, input_bfd, input_section, rel->r_offset)))
+ orig_addend, input_bfd, input_section, rel->r_offset)))
return FALSE;
}
else
adjusted. Worse, reloc symbol indices will be for the output
file rather than the input. Save a copy of the relocs for
opd_entry_value. */
- if (is_opd && info->emitrelocations)
+ if (is_opd && (info->emitrelocations || info->relocatable))
{
bfd_size_type amt;
amt = input_section->reloc_count * sizeof (Elf_Internal_Rela);