/* PowerPC-specific support for 32-bit ELF
Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
- 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+ 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Cygnus Support.
This file is part of BFD, the Binary File Descriptor library.
#define elf_local_ptr_offsets(bfd) \
(ppc_elf_tdata (bfd)->linker_section_pointers)
+#define is_ppc_elf(bfd) \
+ (bfd_get_flavour (bfd) == bfd_target_elf_flavour \
+ && elf_object_id (bfd) == PPC32_ELF_TDATA)
+
/* Override the generic function because we store some extras. */
static bfd_boolean
ppc_elf_mkobject (bfd *abfd)
{
- if (abfd->tdata.any == NULL)
- {
- bfd_size_type amt = sizeof (struct ppc_elf_obj_tdata);
- abfd->tdata.any = bfd_zalloc (abfd, amt);
- if (abfd->tdata.any == NULL)
- return FALSE;
- }
- return bfd_elf_mkobject (abfd);
+ return bfd_elf_allocate_object (abfd, sizeof (struct ppc_elf_obj_tdata),
+ PPC32_ELF_TDATA);
}
/* Fix bad default arch selected for a 32 bit input bfd when the
edir->elf.ref_regular |= eind->elf.ref_regular;
edir->elf.ref_regular_nonweak |= eind->elf.ref_regular_nonweak;
edir->elf.needs_plt |= eind->elf.needs_plt;
+ edir->elf.pointer_equality_needed |= eind->elf.pointer_equality_needed;
/* If we were called to copy over info for a weak sym, that's all. */
if (eind->elf.root.type != bfd_link_hash_indirect)
}
}
-/* Return 1 if target is one of ours. */
-
-static bfd_boolean
-is_ppc_elf_target (const struct bfd_target *targ)
-{
- extern const bfd_target bfd_elf32_powerpc_vec;
- extern const bfd_target bfd_elf32_powerpc_vxworks_vec;
- extern const bfd_target bfd_elf32_powerpcle_vec;
-
- return (targ == &bfd_elf32_powerpc_vec
- || targ == &bfd_elf32_powerpc_vxworks_vec
- || targ == &bfd_elf32_powerpcle_vec);
-}
-
/* Hook called by the linker routine which adds symbols from an object
file. We use it to put .comm items in .sbss, and not .bss. */
{
if (sym->st_shndx == SHN_COMMON
&& !info->relocatable
- && sym->st_size <= elf_gp_size (abfd)
- && is_ppc_elf_target (info->hash->creator))
+ && is_ppc_elf (info->output_bfd)
+ && sym->st_size <= elf_gp_size (abfd))
{
/* Common symbols less than or equal to -G nn bytes are automatically
put into .sbss. */
}
else
{
+ BFD_ASSERT (is_ppc_elf (abfd));
+
/* Allocation of a pointer to a local symbol. */
elf_linker_section_pointers_t **ptr = elf_local_ptr_offsets (abfd);
/* Allocate a table to hold the local symbols if first time. */
if (!ptr)
{
- unsigned int num_symbols = elf_tdata (abfd)->symtab_hdr.sh_info;
+ unsigned int num_symbols = elf_symtab_hdr (abfd).sh_info;
amt = num_symbols;
amt *= sizeof (elf_linker_section_pointers_t *);
sec, abfd);
#endif
+ BFD_ASSERT (is_ppc_elf (abfd));
+
/* Initialize howto table if not already done. */
if (!ppc_elf_howto_table[R_PPC_ADDR32])
ppc_elf_howto_init ();
htab = ppc_elf_hash_table (info);
- symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+ symtab_hdr = &elf_symtab_hdr (abfd);
sym_hashes = elf_sym_hashes (abfd);
got2 = bfd_get_section_by_name (abfd, ".got2");
sreloc = NULL;
}
if (h == NULL || h == htab->elf.hgot)
break;
- goto dodyn1;
+ /* fall through */
+
+ case R_PPC_ADDR32:
+ case R_PPC_ADDR16:
+ case R_PPC_ADDR16_LO:
+ case R_PPC_ADDR16_HI:
+ case R_PPC_ADDR16_HA:
+ case R_PPC_UADDR32:
+ case R_PPC_UADDR16:
+ if (h != NULL && !info->shared)
+ {
+ /* We may need a plt entry if the symbol turns out to be
+ a function defined in a dynamic object. */
+ if (!update_plt_info (abfd, h, NULL, 0))
+ return FALSE;
+
+ /* We may need a copy reloc too. */
+ h->non_got_ref = 1;
+ h->pointer_equality_needed = 1;
+ }
+ goto dodyn;
case R_PPC_REL24:
case R_PPC_REL14:
}
/* fall through */
- case R_PPC_ADDR32:
case R_PPC_ADDR24:
- case R_PPC_ADDR16:
- case R_PPC_ADDR16_LO:
- case R_PPC_ADDR16_HI:
- case R_PPC_ADDR16_HA:
case R_PPC_ADDR14:
case R_PPC_ADDR14_BRTAKEN:
case R_PPC_ADDR14_BRNTAKEN:
- case R_PPC_UADDR32:
- case R_PPC_UADDR16:
- dodyn1:
if (h != NULL && !info->shared)
{
/* We may need a plt entry if the symbol turns out to be
a function defined in a dynamic object. */
if (!update_plt_info (abfd, h, NULL, 0))
return FALSE;
-
- /* We may need a copy reloc too. */
- h->non_got_ref = 1;
+ break;
}
dodyn:
flagword new_flags;
bfd_boolean error;
- if (!is_ppc_elf_target (ibfd->xvec)
- || !is_ppc_elf_target (obfd->xvec))
+ if (!is_ppc_elf (ibfd) || !is_ppc_elf (obfd))
return TRUE;
/* Check if we have the same endianess. */
if (plt_type == PLT_UNSET)
plt_type = PLT_OLD;
for (ibfd = info->input_bfds; ibfd; ibfd = ibfd->link_next)
- if (is_ppc_elf_target (ibfd->xvec))
+ if (is_ppc_elf (ibfd))
{
if (ppc_elf_tdata (ibfd)->has_rel16)
plt_type = PLT_NEW;
elf_section_data (sec)->local_dynrel = NULL;
htab = ppc_elf_hash_table (info);
- symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+ symtab_hdr = &elf_symtab_hdr (abfd);
sym_hashes = elf_sym_hashes (abfd);
local_got_refcounts = elf_local_got_refcounts (abfd);
got2 = bfd_get_section_by_name (abfd, ".got2");
for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
{
Elf_Internal_Sym *locsyms = NULL;
- Elf_Internal_Shdr *symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
+ Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (ibfd);
for (sec = ibfd->sections; sec != NULL; sec = sec->next)
if (sec->has_tls_reloc && !bfd_is_abs_section (sec->output_section))
return TRUE;
}
\f
+/* Return true if we have dynamic relocs that apply to read-only sections. */
+
+static bfd_boolean
+readonly_dynrelocs (struct elf_link_hash_entry *h)
+{
+ struct ppc_elf_dyn_relocs *p;
+
+ for (p = ppc_elf_hash_entry (h)->dyn_relocs; p != NULL; p = p->next)
+ {
+ asection *s = p->sec->output_section;
+
+ if (s != NULL
+ && ((s->flags & (SEC_READONLY | SEC_ALLOC))
+ == (SEC_READONLY | SEC_ALLOC)))
+ return TRUE;
+ }
+ return FALSE;
+}
+
/* Adjust a symbol defined by a dynamic object and referenced by a
regular object. The current definition is in some section of the
dynamic object, but we're not including those sections. We have to
h->plt.plist = NULL;
h->needs_plt = 0;
}
+ else
+ {
+ /* After adjust_dynamic_symbol, non_got_ref set means that
+ dyn_relocs for this symbol should be discarded.
+ If we get here we know we are making a PLT entry for this
+ symbol, and in an executable we'd normally resolve
+ relocations against this symbol to the PLT entry. Allow
+ dynamic relocs if the reference is weak, and the dynamic
+ relocs will not cause text relocation. */
+ if (!h->ref_regular_nonweak
+ && h->non_got_ref
+ && !htab->is_vxworks
+ && !ppc_elf_hash_entry (h)->has_sda_refs
+ && !readonly_dynrelocs (h))
+ h->non_got_ref = 0;
+ }
return TRUE;
}
else
executable. */
if (ELIMINATE_COPY_RELOCS
&& !ppc_elf_hash_entry (h)->has_sda_refs
- && !htab->is_vxworks)
+ && !htab->is_vxworks
+ && !h->def_regular
+ && !readonly_dynrelocs (h))
{
- struct ppc_elf_dyn_relocs *p;
- for (p = ppc_elf_hash_entry (h)->dyn_relocs; p != NULL; p = p->next)
- {
- s = p->sec->output_section;
- if (s != NULL && (s->flags & SEC_READONLY) != 0)
- break;
- }
-
- if (p == NULL)
- {
- h->non_got_ref = 0;
- return TRUE;
- }
+ h->non_got_ref = 0;
+ return TRUE;
}
if (h->size == 0)
}
if (!doneone
&& !info->shared
+ && h->def_dynamic
&& !h->def_regular)
{
h->root.u.def.section = s;
function pointers compare as equal between
the normal executable and the shared library. */
if (! info->shared
+ && h->def_dynamic
&& !h->def_regular)
{
h->root.u.def.section = s;
}
}
+ if (htab->is_vxworks)
+ {
+ struct ppc_elf_dyn_relocs **pp;
+
+ for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
+ {
+ if (strcmp (p->sec->output_section->name, ".tls_vars") == 0)
+ *pp = p->next;
+ else
+ pp = &p->next;
+ }
+ }
+
+ /* Discard relocs on undefined symbols that must be local. */
+ if (eh->dyn_relocs != NULL
+ && h->root.type == bfd_link_hash_undefined
+ && (ELF_ST_VISIBILITY (h->other) == STV_HIDDEN
+ || ELF_ST_VISIBILITY (h->other) == STV_INTERNAL))
+ eh->dyn_relocs = NULL;
+
/* Also discard relocs on undefined weak syms with non-default
visibility. */
if (eh->dyn_relocs != NULL
dynamic. */
if (!h->non_got_ref
- && h->def_dynamic
&& !h->def_regular)
{
/* Make sure this symbol is output as a dynamic symbol.
return TRUE;
}
-/* Find any dynamic relocs that apply to read-only sections. */
+/* Set DF_TEXTREL if we find any dynamic relocs that apply to
+ read-only sections. */
static bfd_boolean
-readonly_dynrelocs (struct elf_link_hash_entry *h, void *info)
+maybe_set_textrel (struct elf_link_hash_entry *h, void *info)
{
- struct ppc_elf_dyn_relocs *p;
-
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;
- for (p = ppc_elf_hash_entry (h)->dyn_relocs; p != NULL; p = p->next)
+ if (readonly_dynrelocs (h))
{
- asection *s = p->sec->output_section;
+ ((struct bfd_link_info *) info)->flags |= DF_TEXTREL;
- if (s != NULL
- && ((s->flags & (SEC_READONLY | SEC_ALLOC))
- == (SEC_READONLY | SEC_ALLOC)))
- {
- ((struct bfd_link_info *) info)->flags |= DF_TEXTREL;
-
- /* Not an error, just cut short the traversal. */
- return FALSE;
- }
+ /* Not an error, just cut short the traversal. */
+ return FALSE;
}
return TRUE;
}
bfd_size_type locsymcount;
Elf_Internal_Shdr *symtab_hdr;
- if (!is_ppc_elf_target (ibfd->xvec))
+ if (!is_ppc_elf (ibfd))
continue;
for (s = ibfd->sections; s != NULL; s = s->next)
linker script /DISCARD/, so we'll be discarding
the relocs too. */
}
+ else if (htab->is_vxworks
+ && strcmp (p->sec->output_section->name,
+ ".tls_vars") == 0)
+ {
+ /* Relocations in vxworks .tls_vars sections are
+ handled specially by the loader. */
+ }
else if (p->count != 0)
{
elf_section_data (p->sec)->sreloc->size
if (!local_got)
continue;
- symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
+ symtab_hdr = &elf_symtab_hdr (ibfd);
locsymcount = symtab_hdr->sh_info;
end_local_got = local_got + locsymcount;
lgot_masks = (char *) end_local_got;
/* If any dynamic relocs apply to a read-only section, then we
need a DT_TEXTREL entry. */
if ((info->flags & DF_TEXTREL) == 0)
- elf_link_hash_traverse (elf_hash_table (info), readonly_dynrelocs,
+ elf_link_hash_traverse (elf_hash_table (info), maybe_set_textrel,
info);
if ((info->flags & DF_TEXTREL) != 0)
return TRUE;
}
+
+/* Return TRUE if symbol should be hashed in the `.gnu.hash' section. */
+
+static bfd_boolean
+ppc_elf_hash_symbol (struct elf_link_hash_entry *h)
+{
+ if (h->plt.plist != NULL
+ && !h->def_regular
+ && (!h->pointer_equality_needed
+ || !h->ref_regular_nonweak))
+ return FALSE;
+
+ return _bfd_elf_hash_symbol (h);
+}
\f
#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
/* Space for a branch around any trampolines. */
trampoff += 4;
- symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+ symtab_hdr = &elf_symtab_hdr (abfd);
/* Get a copy of the native relocations. */
internal_relocs = _bfd_elf_link_read_relocs (abfd, isec, NULL, NULL,
}
while (fixups);
- contents = bfd_realloc (contents, trampoff);
+ contents = bfd_realloc_or_free (contents, trampoff);
if (contents == NULL)
goto error_return;
/* Handle local symbol. */
unsigned long r_symndx = ELF32_R_SYM (rel->r_info);
+ BFD_ASSERT (is_ppc_elf (input_bfd));
BFD_ASSERT (elf_local_ptr_offsets (input_bfd) != NULL);
linker_section_ptr = elf_local_ptr_offsets (input_bfd)[r_symndx];
}
bfd_vma *local_got_offsets;
bfd_boolean ret = TRUE;
bfd_vma d_offset = (bfd_big_endian (output_bfd) ? 2 : 0);
+ bfd_boolean is_vxworks_tls;
#ifdef DEBUG
_bfd_error_handler ("ppc_elf_relocate_section called for %B section %A, "
htab = ppc_elf_hash_table (info);
local_got_offsets = elf_local_got_offsets (input_bfd);
- symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+ symtab_hdr = &elf_symtab_hdr (input_bfd);
sym_hashes = elf_sym_hashes (input_bfd);
+ /* We have to handle relocations in vxworks .tls_vars sections
+ specially, because the dynamic loader is 'weird'. */
+ is_vxworks_tls = (htab->is_vxworks && info->shared
+ && !strcmp (input_section->output_section->name,
+ ".tls_vars"));
rel = relocs;
relend = relocs + input_section->reloc_count;
for (; rel < relend; rel++)
case R_PPC_REL16_HA:
break;
- case R_PPC_REL24:
case R_PPC_REL32:
+ if (h == NULL || h == htab->elf.hgot)
+ break;
+ /* fall through */
+
+ case R_PPC_ADDR32:
+ case R_PPC_ADDR16:
+ case R_PPC_ADDR16_LO:
+ case R_PPC_ADDR16_HI:
+ case R_PPC_ADDR16_HA:
+ case R_PPC_UADDR32:
+ case R_PPC_UADDR16:
+ goto dodyn;
+
+ case R_PPC_REL24:
case R_PPC_REL14:
case R_PPC_REL14_BRTAKEN:
case R_PPC_REL14_BRNTAKEN:
/* If these relocations are not to a named symbol, they can be
handled right here, no need to bother the dynamic linker. */
- if (SYMBOL_REFERENCES_LOCAL (info, h)
+ if (SYMBOL_CALLS_LOCAL (info, h)
|| h == htab->elf.hgot)
break;
/* fall through */
- /* Relocations that always need to be propagated if this is a shared
- object. */
- case R_PPC_ADDR32:
case R_PPC_ADDR24:
- case R_PPC_ADDR16:
- case R_PPC_ADDR16_LO:
- case R_PPC_ADDR16_HI:
- case R_PPC_ADDR16_HA:
case R_PPC_ADDR14:
case R_PPC_ADDR14_BRTAKEN:
case R_PPC_ADDR14_BRNTAKEN:
- case R_PPC_UADDR32:
- case R_PPC_UADDR16:
+ if (h != NULL && !info->shared)
+ break;
+ /* fall through */
+
dodyn:
- if ((input_section->flags & SEC_ALLOC) == 0)
+ if ((input_section->flags & SEC_ALLOC) == 0
+ || is_vxworks_tls)
break;
- /* Fall thru. */
if ((info->shared
- && (h == NULL
- || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
- || h->root.type != bfd_link_hash_undefweak)
+ && !(h != NULL
+ && ((h->root.type == bfd_link_hash_undefined
+ && (ELF_ST_VISIBILITY (h->other) == STV_HIDDEN
+ || ELF_ST_VISIBILITY (h->other) == STV_INTERNAL))
+ || (h->root.type == bfd_link_hash_undefweak
+ && ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)))
&& (MUST_BE_DYN_RELOC (r_type)
|| !SYMBOL_CALLS_LOCAL (info, h)))
|| (ELIMINATE_COPY_RELOCS
&& h != NULL
&& h->dynindx != -1
&& !h->non_got_ref
- && h->def_dynamic
&& !h->def_regular))
{
int skip;
}
skip = 0;
-
outrel.r_offset =
_bfd_elf_section_offset (output_bfd, info, input_section,
rel->r_offset);
if (skip)
memset (&outrel, 0, sizeof outrel);
- else if (!SYMBOL_REFERENCES_LOCAL (info, h))
+ else if ((h != NULL
+ && (h->root.type == bfd_link_hash_undefined
+ || h->root.type == bfd_link_hash_undefweak))
+ || !SYMBOL_REFERENCES_LOCAL (info, h))
{
unresolved_reloc = FALSE;
outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
outrel.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE);
else
{
- long indx;
+ long indx = 0;
if (bfd_is_abs_section (sec))
- indx = 0;
+ ;
else if (sec == NULL || sec->owner == NULL)
{
bfd_set_error (bfd_error_bad_value);
- return FALSE;
+ ret = FALSE;
}
else
{
if (!h->def_regular)
{
- /* Mark the symbol as undefined, rather than as defined in
- the .plt section. Leave the value alone. */
+ /* Mark the symbol as undefined, rather than as
+ defined in the .plt section. Leave the value if
+ there were any relocations where pointer equality
+ matters (this is a clue for the dynamic linker, to
+ make function pointer comparisons work between an
+ application and shared library), otherwise set it
+ to zero. */
sym->st_shndx = SHN_UNDEF;
- /* If the symbol is weak, we do need to clear the value.
- Otherwise, the PLT entry would provide a definition for
- the symbol even if the symbol wasn't defined anywhere,
- and so the symbol would never be NULL. */
- if (!h->ref_regular_nonweak)
+ if (!h->pointer_equality_needed)
sym->st_value = 0;
+ else if (!h->ref_regular_nonweak)
+ {
+ /* This breaks function pointer comparisons, but
+ that is better than breaking tests for a NULL
+ function pointer. */
+ sym->st_value = 0;
+ }
}
doneone = TRUE;
}
* bctr
*
* # A table of branches, one for each plt entry.
- * # The idea is that the plt call stub loads ctr (and r11) with these
+ * # The idea is that the plt call stub loads ctr and r11 with these
* # addresses, so (r11 - res_0) gives the plt index * 4.
* res_0: b PLTresolve
* res_1: b PLTresolve
NOP
};
+ /*
+ * Non-PIC glink code is a little simpler.
+ *
+ * # ith PLT code stub.
+ * lis 11,(plt+(i-1)*4)@ha
+ * lwz 11,(plt+(i-1)*4)@l(11)
+ * mtctr 11
+ * bctr
+ *
+ * The branch table is the same, then comes
+ *
+ * PLTresolve:
+ * lis 12,(got+4)@ha
+ * addis 11,11,(-res_0)@ha
+ * lwz 0,(got+4)@l(12) # got[1] address of dl_runtime_resolve
+ * addi 11,11,(-res_0)@l # r11 = index * 4
+ * mtctr 0
+ * add 0,11,11
+ * lwz 12,(got+8)@l(12) # got[2] contains the map address
+ * add 11,0,11 # r11 = index * 12 = reloc offset.
+ * bctr
+ */
static const unsigned int plt_resolve[] =
{
LIS_12,
#define elf_backend_adjust_dynamic_symbol ppc_elf_adjust_dynamic_symbol
#define elf_backend_add_symbol_hook ppc_elf_add_symbol_hook
#define elf_backend_size_dynamic_sections ppc_elf_size_dynamic_sections
+#define elf_backend_hash_symbol ppc_elf_hash_symbol
#define elf_backend_finish_dynamic_symbol ppc_elf_finish_dynamic_symbol
#define elf_backend_finish_dynamic_sections ppc_elf_finish_dynamic_sections
#define elf_backend_fake_sections ppc_elf_fake_sections