aboutsummaryrefslogtreecommitdiff
path: root/bfd/elf32-ppc.c
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2008-02-23 01:56:21 +0000
committerAlan Modra <amodra@gmail.com>2008-02-23 01:56:21 +0000
commit0eb4a168d474b103ece58f499e34ae7e99962f2a (patch)
tree7a433b7e22eff7bf5ed2a3fb73aa7d07df369575 /bfd/elf32-ppc.c
parent3ae181ee8903e608d34e41dc92a28b22808bc495 (diff)
downloadfsf-binutils-gdb-0eb4a168d474b103ece58f499e34ae7e99962f2a.zip
fsf-binutils-gdb-0eb4a168d474b103ece58f499e34ae7e99962f2a.tar.gz
fsf-binutils-gdb-0eb4a168d474b103ece58f499e34ae7e99962f2a.tar.bz2
* elf32-ppc.c (ppc_elf_copy_indirect_symbol): Copy
pointer_equality_needed. (ppc_elf_check_relocs): Split out non-branch relocs from others that might emit dynamic relocs. Set pointer_equality_needed for their symbols. Don't set non_got_ref on branch reloc symbols. (ppc_elf_hash_symbol): New function. (elf_backend_hash_symbol): Define. (ppc_elf_finish_dynamic_symbol): Handle pointer_equality_needed. Error if pointer_equality_needed on weak plt symbol.
Diffstat (limited to 'bfd/elf32-ppc.c')
-rw-r--r--bfd/elf32-ppc.c73
1 files changed, 56 insertions, 17 deletions
diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c
index 0e21593..a859adf 100644
--- a/bfd/elf32-ppc.c
+++ b/bfd/elf32-ppc.c
@@ -2696,6 +2696,7 @@ ppc_elf_copy_indirect_symbol (struct bfd_link_info *info,
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)
@@ -3388,6 +3389,26 @@ ppc_elf_check_relocs (bfd *abfd,
info->flags |= DF_STATIC_TLS;
goto dodyn;
+ 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_REL32:
if (h == NULL
&& got2 != NULL
@@ -3432,17 +3453,10 @@ ppc_elf_check_relocs (bfd *abfd,
}
/* 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)
{
@@ -3450,9 +3464,6 @@ ppc_elf_check_relocs (bfd *abfd,
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;
}
dodyn:
@@ -5186,6 +5197,20 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
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);
+}
#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
@@ -7127,15 +7152,28 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
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)
+ {
+ /* Choose your poison. We must have either text
+ dynamic relocations, broken function pointer
+ comparisons, or broken tests for a NULL
+ function pointer. */
+ (*_bfd_error_handler)
+ (_("weak reference to %s in non-pic code"
+ " will break function pointer comparisons"),
+ h->root.root.string);
+ sym->st_value = 0;
+ }
}
doneone = TRUE;
}
@@ -7687,6 +7725,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
#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