* elf-bfd.h (_bfd_elf_dynamic_symbol_p): Declare it.
(SYMBOL_REFERENCES_LOCAL, SYMBOL_CALLS_LOCAL): Use it.
* elf32-xtensa.c (xtensa_elf_dynamic_symbol_p): Likewise.
* elf64-alpha.c (alpha_elf_dynamic_symbol_p): Likewise.
* elf64-hppa.c (elf64_hppa_dynamic_symbol_p): Likewise.
* elfxx-ia64.c (elfNN_ia64_dynamic_symbol_p): Likewise.
Update all callers to provide the relocation being resolved.
+2003-07-18 Richard Henderson <rth@redhat.com>
+
+ * elflink.c (_bfd_elf_dynamic_symbol_p): New.
+ * elf-bfd.h (_bfd_elf_dynamic_symbol_p): Declare it.
+ (SYMBOL_REFERENCES_LOCAL, SYMBOL_CALLS_LOCAL): Use it.
+ * elf32-xtensa.c (xtensa_elf_dynamic_symbol_p): Likewise.
+ * elf64-alpha.c (alpha_elf_dynamic_symbol_p): Likewise.
+ * elf64-hppa.c (elf64_hppa_dynamic_symbol_p): Likewise.
+ * elfxx-ia64.c (elfNN_ia64_dynamic_symbol_p): Likewise.
+ Update all callers to provide the relocation being resolved.
+
2003-07-17 Shaun Jackman <sjackman@pathwayconnect.com>
* config.bfd (arm-wince-pe): Add -DARM_COFF_BUGFIX to
function symbols not defined in an app are set to their .plt entry,
it's necessary for shared libs to also reference the .plt even
though the symbol is really local to the shared lib. */
-#define SYMBOL_REFERENCES_LOCAL(INFO, H) \
- (((INFO)->executable \
- || (INFO)->symbolic \
- || (H)->dynindx == -1 \
- || ELF_ST_VISIBILITY ((H)->other) == STV_INTERNAL \
- || ELF_ST_VISIBILITY ((H)->other) == STV_HIDDEN \
- || ((H)->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0) \
- && ((H)->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0)
+#define SYMBOL_REFERENCES_LOCAL(INFO, H) \
+ _bfd_elf_dynamic_symbol_p (H, INFO, 1)
/* Will _calls_ to this symbol always call the version in this object? */
-#define SYMBOL_CALLS_LOCAL(INFO, H) \
- (((INFO)->executable \
- || (INFO)->symbolic \
- || (H)->dynindx == -1 \
- || ELF_ST_VISIBILITY ((H)->other) != STV_DEFAULT \
- || ((H)->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0) \
- && ((H)->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0)
+#define SYMBOL_CALLS_LOCAL(INFO, H) \
+ _bfd_elf_dynamic_symbol_p (H, INFO, 0)
/* Records local symbols to be emitted in the dynamic symbol table. */
extern bfd_boolean _bfd_elf_link_sec_merge_syms
PARAMS ((struct elf_link_hash_entry *, PTR));
+extern bfd_boolean _bfd_elf_dynamic_symbol_p
+ PARAMS ((struct elf_link_hash_entry *, struct bfd_link_info *, bfd_boolean));
+
extern const bfd_target *bfd_elf32_object_p
PARAMS ((bfd *));
extern const bfd_target *bfd_elf32_core_file_p
struct bfd_link_info *info;
struct elf_link_hash_entry *h;
{
- if (h == NULL)
- return FALSE;
-
- 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;
-
- if (h->dynindx == -1)
- return FALSE;
-
- if (h->root.type == bfd_link_hash_undefweak
- || h->root.type == bfd_link_hash_defweak)
- return TRUE;
-
- switch (ELF_ST_VISIBILITY (h->other))
- {
- case STV_DEFAULT:
- break;
- case STV_HIDDEN:
- case STV_INTERNAL:
- return FALSE;
- case STV_PROTECTED:
- if (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)
- return FALSE;
- break;
- }
-
- if ((info->shared && !info->symbolic)
- || (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
- return TRUE;
-
- return FALSE;
+ /* ??? What, if anything, needs to happen wrt STV_PROTECTED and PLT
+ entries? For now assume the worst. */
+ return _bfd_elf_dynamic_symbol_p (h, info, 1);
}
#define ECOFF_64
#include "ecoffswap.h"
-static int alpha_elf_dynamic_symbol_p
+static bfd_boolean alpha_elf_dynamic_symbol_p
PARAMS ((struct elf_link_hash_entry *, struct bfd_link_info *));
static struct bfd_hash_entry * elf64_alpha_link_hash_newfunc
PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
#define alpha_elf_sym_hashes(abfd) \
((struct alpha_elf_link_hash_entry **)elf_sym_hashes(abfd))
-/* Should we do dynamic things to this symbol? */
+/* Should we do dynamic things to this symbol? This differs from the
+ generic version in that we never need to consider function pointer
+ equality wrt PLT entries -- we don't create a PLT entry if a symbol's
+ address is ever taken. */
-static int
+static inline bfd_boolean
alpha_elf_dynamic_symbol_p (h, info)
struct elf_link_hash_entry *h;
struct bfd_link_info *info;
{
- if (h == NULL)
- return FALSE;
-
- 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;
-
- if (h->dynindx == -1)
- return FALSE;
-
- if (h->root.type == bfd_link_hash_undefweak
- || h->root.type == bfd_link_hash_defweak)
- return TRUE;
-
- switch (ELF_ST_VISIBILITY (h->other))
- {
- case STV_DEFAULT:
- break;
- case STV_HIDDEN:
- case STV_INTERNAL:
- return FALSE;
- case STV_PROTECTED:
- if (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)
- return FALSE;
- break;
- }
-
- if ((info->shared && !info->symbolic)
- || ((h->elf_link_hash_flags
- & (ELF_LINK_HASH_DEF_DYNAMIC
- | ELF_LINK_HASH_DEF_REGULAR
- | ELF_LINK_HASH_REF_REGULAR))
- == (ELF_LINK_HASH_DEF_DYNAMIC | ELF_LINK_HASH_REF_REGULAR)))
- return TRUE;
-
- return FALSE;
+ return _bfd_elf_dynamic_symbol_p (h, info, 0);
}
/* Create an entry in a Alpha ELF linker hash table. */
struct elf_link_hash_entry *h;
struct bfd_link_info *info;
{
- if (h == NULL)
- return FALSE;
-
- 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;
-
- if (h->dynindx == -1)
- return FALSE;
-
- if (h->root.type == bfd_link_hash_undefweak
- || h->root.type == bfd_link_hash_defweak)
- return TRUE;
+ /* ??? What, if anything, needs to happen wrt STV_PROTECTED symbols
+ and relocations that retrieve a function descriptor? Assume the
+ worst for now. */
+ if (_bfd_elf_dynamic_symbol_p (h, info, 1))
+ {
+ /* ??? Why is this here and not elsewhere is_local_label_name. */
+ if (h->root.root.string[0] == '$' && h->root.root.string[1] == '$')
+ return FALSE;
- if (h->root.root.string[0] == '$' && h->root.root.string[1] == '$')
+ return TRUE;
+ }
+ else
return FALSE;
-
- if ((info->shared && (!info->symbolic || info->allow_shlib_undefined))
- || ((h->elf_link_hash_flags
- & (ELF_LINK_HASH_DEF_DYNAMIC | ELF_LINK_HASH_REF_REGULAR))
- == (ELF_LINK_HASH_DEF_DYNAMIC | ELF_LINK_HASH_REF_REGULAR)))
- return TRUE;
-
- return FALSE;
}
/* Mark all funtions exported by this file so that we can later allocate
return TRUE;
}
+
+/* Returns false if the symbol referred to by H should be considered
+ to resolve local to the current module, and true if it should be
+ considered to bind dynamically. */
+
+bfd_boolean
+_bfd_elf_dynamic_symbol_p (h, info, ignore_protected)
+ struct elf_link_hash_entry *h;
+ struct bfd_link_info *info;
+ bfd_boolean ignore_protected;
+{
+ bfd_boolean binding_stays_local_p;
+
+ if (h == NULL)
+ return FALSE;
+
+ 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;
+
+ /* If it was forced local, then clearly it's not dynamic. */
+ if (h->dynindx == -1)
+ return FALSE;
+ if (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL)
+ return FALSE;
+
+ /* Identify the cases where name binding rules say that a
+ visible symbol resolves locally. */
+ binding_stays_local_p = info->executable || info->symbolic;
+
+ switch (ELF_ST_VISIBILITY (h->other))
+ {
+ case STV_INTERNAL:
+ case STV_HIDDEN:
+ return FALSE;
+
+ case STV_PROTECTED:
+ /* Proper resolution for function pointer equality may require
+ that these symbols perhaps be resolved dynamically, even though
+ we should be resolving them to the current module. */
+ if (!ignore_protected)
+ binding_stays_local_p = TRUE;
+ break;
+
+ default:
+ /* With STV_DEFAULT, weak symbols do not bind locally. */
+ if (h->root.type == bfd_link_hash_undefweak
+ || h->root.type == bfd_link_hash_defweak)
+ return TRUE;
+ break;
+ }
+
+ /* If it isn't defined locally, then clearly it's dynamic. */
+ if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+ return TRUE;
+
+ /* Otherwise, the symbol is dynamic if binding rules don't tell
+ us that it remains local. */
+ return !binding_stays_local_p;
+}
static bfd_boolean elfNN_ia64_is_local_label_name
PARAMS ((bfd *abfd, const char *name));
static bfd_boolean elfNN_ia64_dynamic_symbol_p
- PARAMS ((struct elf_link_hash_entry *h, struct bfd_link_info *info));
+ PARAMS ((struct elf_link_hash_entry *h, struct bfd_link_info *info, int));
static bfd_boolean elfNN_ia64_local_hash_table_init
PARAMS ((struct elfNN_ia64_local_hash_table *ht, bfd *abfd,
new_hash_entry_func new));
}
/* Can't do anything else with dynamic symbols. */
- else if (elfNN_ia64_dynamic_symbol_p (h, link_info))
+ else if (elfNN_ia64_dynamic_symbol_p (h, link_info, r_type))
continue;
else
/* Should we do dynamic things to this symbol? */
static bfd_boolean
-elfNN_ia64_dynamic_symbol_p (h, info)
+elfNN_ia64_dynamic_symbol_p (h, info, r_type)
struct elf_link_hash_entry *h;
struct bfd_link_info *info;
+ int r_type;
{
- if (h == NULL)
- return FALSE;
-
- 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;
+ bfd_boolean ignore_protected
+ = ((r_type & 0xf8) == 0x40 /* FPTR relocs */
+ || (r_type & 0xf8) == 0x50); /* LTOFF_FPTR relocs */
- if (h->dynindx == -1)
- return FALSE;
- switch (ELF_ST_VISIBILITY (h->other))
- {
- case STV_INTERNAL:
- case STV_HIDDEN:
- return FALSE;
- default:
- break;
- }
-
- if (h->root.type == bfd_link_hash_undefweak
- || h->root.type == bfd_link_hash_defweak)
- return TRUE;
-
- /* If it isn't defined locally, then clearly it's dynamic. */
- if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
- return TRUE;
-
- /* Identify the cases where name binding rules say it resolves local. */
- return !(info->executable || info->symbolic);
+ return _bfd_elf_dynamic_symbol_p (h, info, ignore_protected);
}
\f
static bfd_boolean
if ((dyn_i->want_got || dyn_i->want_gotx)
&& ! dyn_i->want_fptr
- && elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info))
+ && elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info, 0))
{
dyn_i->got_offset = x->ofs;
x->ofs += 8;
}
if (dyn_i->want_dtpmod)
{
- if (elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info))
+ if (elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info, 0))
{
dyn_i->dtpmod_offset = x->ofs;
x->ofs += 8;
if (dyn_i->want_got
&& dyn_i->want_fptr
- && elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info))
+ && elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info, R_IA64_FPTR64LSB))
{
dyn_i->got_offset = x->ofs;
x->ofs += 8;
struct elfNN_ia64_allocate_data *x = (struct elfNN_ia64_allocate_data *)data;
if ((dyn_i->want_got || dyn_i->want_gotx)
- && !elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info))
+ && !elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info, 0))
{
dyn_i->got_offset = x->ofs;
x->ofs += 8;
h = (struct elf_link_hash_entry *) h->root.u.i.link;
/* ??? Versioned symbols seem to lose ELF_LINK_HASH_NEEDS_PLT. */
- if (elfNN_ia64_dynamic_symbol_p (h, x->info))
+ if (elfNN_ia64_dynamic_symbol_p (h, x->info, 0))
{
bfd_size_type offset = x->ofs;
if (offset == 0)
bfd_boolean dynamic_symbol, shared, resolved_zero;
ia64_info = elfNN_ia64_hash_table (x->info);
- dynamic_symbol = elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info);
+
+ /* Note that this can't be used in relation to FPTR relocs below. */
+ dynamic_symbol = elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info, 0);
+
shared = x->info->shared;
resolved_zero = (dyn_i->h
&& ELF_ST_VISIBILITY (dyn_i->h->other)
|| ELF_ST_VISIBILITY (dyn_i->h->other) == STV_DEFAULT
|| dyn_i->h->root.type != bfd_link_hash_undefweak)
&& dyn_r_type != R_IA64_DTPREL64LSB)
- || elfNN_ia64_dynamic_symbol_p (dyn_i->h, info)
+ || elfNN_ia64_dynamic_symbol_p (dyn_i->h, info, dyn_r_type)
|| (dynindx != -1 && dyn_r_type == R_IA64_FPTR64LSB))
&& (!dyn_i->want_ltoff_fptr
|| !info->pie
asection *sym_sec;
bfd_byte *hit_addr;
bfd_boolean dynamic_symbol_p;
- bfd_boolean local_symbol_p;
bfd_boolean undef_weak_ref;
r_type = ELFNN_R_TYPE (rel->r_info);
hit_addr = contents + rel->r_offset;
value += rel->r_addend;
- dynamic_symbol_p = elfNN_ia64_dynamic_symbol_p (h, info);
- /* Is this symbol locally defined? A protected symbol is locallly
- defined. But its function descriptor may not. Use it with
- caution. */
- local_symbol_p = (! dynamic_symbol_p
- || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT);
+ dynamic_symbol_p = elfNN_ia64_dynamic_symbol_p (h, info, r_type);
switch (r_type)
{
/* If we don't need dynamic symbol lookup, find a
matching RELATIVE relocation. */
dyn_r_type = r_type;
- if (! local_symbol_p)
+ if (dynamic_symbol_p)
{
dynindx = h->dynindx;
addend = rel->r_addend;
/* If we don't need dynamic symbol lookup, install two
RELATIVE relocations. */
- if (local_symbol_p)
+ if (!dynamic_symbol_p)
{
unsigned int dyn_r_type;