* elflink.c (_bfd_elf_merge_symbol): Set old_alignment for

usual common symbols as well as for dynamic.  Add poldbfd param.
	Save old bfd.  Adjust callers.
	(_bfd_elf_add_default_symbol): Add poldbfd param.  Pass "section"
	and "value" by value, not pointer.  Adjust caller.
	(elf_link_add_object_symbols): Combine undef_bfd and old_bfd vars.
	Delete code to set same.  Use old_bfd and old_alignment from
	_bfd_elf_merge_symbol instead.  Add default symbol before
	alignment and size checks.  Wrap overlong lines.
This commit is contained in:
Alan Modra 2013-03-25 06:12:06 +00:00
parent e3c9d23467
commit 4f3fedcf68
2 changed files with 172 additions and 207 deletions

View File

@ -1,3 +1,15 @@
2013-03-25 Alan Modra <amodra@gmail.com>
* elflink.c (_bfd_elf_merge_symbol): Set old_alignment for
usual common symbols as well as for dynamic. Add poldbfd param.
Save old bfd. Adjust callers.
(_bfd_elf_add_default_symbol): Add poldbfd param. Pass "section"
and "value" by value, not pointer. Adjust caller.
(elf_link_add_object_symbols): Combine undef_bfd and old_bfd vars.
Delete code to set same. Use old_bfd and old_alignment from
_bfd_elf_merge_symbol instead. Add default symbol before
alignment and size checks. Wrap overlong lines.
2013-03-25 Alan Modra <amodra@gmail.com> 2013-03-25 Alan Modra <amodra@gmail.com>
* elflink.c (_bfd_elf_add_default_symbol): Delete "override" param. * elflink.c (_bfd_elf_add_default_symbol): Delete "override" param.

View File

@ -895,17 +895,18 @@ elf_merge_st_other (bfd *abfd, struct elf_link_hash_entry *h,
} }
} }
/* This function is called when we want to define a new symbol. It /* This function is called when we want to merge a new symbol with an
handles the various cases which arise when we find a definition in existing symbol. It handles the various cases which arise when we
a dynamic object, or when there is already a definition in a find a definition in a dynamic object, or when there is already a
dynamic object. The new symbol is described by NAME, SYM, PSEC, definition in a dynamic object. The new symbol is described by
and PVALUE. We set SYM_HASH to the hash table entry. We set NAME, SYM, PSEC, and PVALUE. We set SYM_HASH to the hash table
OVERRIDE if the old symbol is overriding a new definition. We set entry. We set POLDBFD to the old symbol's BFD. We set POLD_WEAK
TYPE_CHANGE_OK if it is OK for the type to change. We set if the old symbol was weak. We set POLD_ALIGNMENT to the alignment
SIZE_CHANGE_OK if it is OK for the size to change. By OK to of an old common symbol. We set OVERRIDE if the old symbol is
change, we mean that we shouldn't warn if the type or size does overriding a new definition. We set TYPE_CHANGE_OK if it is OK for
change. We set POLD_ALIGNMENT if an old common symbol in a dynamic the type to change. We set SIZE_CHANGE_OK if it is OK for the size
object is overridden by a regular object. */ to change. By OK to change, we mean that we shouldn't warn if the
type or size does change. */
static bfd_boolean static bfd_boolean
_bfd_elf_merge_symbol (bfd *abfd, _bfd_elf_merge_symbol (bfd *abfd,
@ -914,9 +915,10 @@ _bfd_elf_merge_symbol (bfd *abfd,
Elf_Internal_Sym *sym, Elf_Internal_Sym *sym,
asection **psec, asection **psec,
bfd_vma *pvalue, bfd_vma *pvalue,
struct elf_link_hash_entry **sym_hash,
bfd **poldbfd,
bfd_boolean *pold_weak, bfd_boolean *pold_weak,
unsigned int *pold_alignment, unsigned int *pold_alignment,
struct elf_link_hash_entry **sym_hash,
bfd_boolean *skip, bfd_boolean *skip,
bfd_boolean *override, bfd_boolean *override,
bfd_boolean *type_change_ok, bfd_boolean *type_change_ok,
@ -1030,8 +1032,12 @@ _bfd_elf_merge_symbol (bfd *abfd,
case bfd_link_hash_common: case bfd_link_hash_common:
oldbfd = h->root.u.c.p->section->owner; oldbfd = h->root.u.c.p->section->owner;
oldsec = h->root.u.c.p->section; oldsec = h->root.u.c.p->section;
if (pold_alignment)
*pold_alignment = h->root.u.c.p->alignment_power;
break; break;
} }
if (poldbfd && *poldbfd == NULL)
*poldbfd = oldbfd;
/* Differentiate strong and weak symbols. */ /* Differentiate strong and weak symbols. */
newweak = bind == STB_WEAK; newweak = bind == STB_WEAK;
@ -1568,7 +1574,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
/* This function is called to create an indirect symbol from the /* This function is called to create an indirect symbol from the
default for the symbol with the default version if needed. The default for the symbol with the default version if needed. The
symbol is described by H, NAME, SYM, PSEC, VALUE, and OVERRIDE. We symbol is described by H, NAME, SYM, SEC, and VALUE. We
set DYNSYM if the new indirect symbol is dynamic. */ set DYNSYM if the new indirect symbol is dynamic. */
static bfd_boolean static bfd_boolean
@ -1577,8 +1583,9 @@ _bfd_elf_add_default_symbol (bfd *abfd,
struct elf_link_hash_entry *h, struct elf_link_hash_entry *h,
const char *name, const char *name,
Elf_Internal_Sym *sym, Elf_Internal_Sym *sym,
asection **psec, asection *sec,
bfd_vma *value, bfd_vma value,
bfd **poldbfd,
bfd_boolean *dynsym) bfd_boolean *dynsym)
{ {
bfd_boolean type_change_ok; bfd_boolean type_change_ok;
@ -1593,7 +1600,6 @@ _bfd_elf_add_default_symbol (bfd *abfd,
bfd_boolean override; bfd_boolean override;
char *p; char *p;
size_t len, shortlen; size_t len, shortlen;
asection *sec;
/* If this symbol has a version, and it is the default version, we /* If this symbol has a version, and it is the default version, we
create an indirect symbol from the default name to the fully create an indirect symbol from the default name to the fully
@ -1620,9 +1626,8 @@ _bfd_elf_add_default_symbol (bfd *abfd,
actually going to define an indirect symbol. */ actually going to define an indirect symbol. */
type_change_ok = FALSE; type_change_ok = FALSE;
size_change_ok = FALSE; size_change_ok = FALSE;
sec = *psec; if (!_bfd_elf_merge_symbol (abfd, info, shortname, sym, &sec, &value,
if (!_bfd_elf_merge_symbol (abfd, info, shortname, sym, &sec, value, &hi, poldbfd, NULL, NULL, &skip, &override,
NULL, NULL, &hi, &skip, &override,
&type_change_ok, &size_change_ok)) &type_change_ok, &size_change_ok))
return FALSE; return FALSE;
@ -1729,9 +1734,8 @@ nondefault:
/* Once again, merge with any existing symbol. */ /* Once again, merge with any existing symbol. */
type_change_ok = FALSE; type_change_ok = FALSE;
size_change_ok = FALSE; size_change_ok = FALSE;
sec = *psec; if (!_bfd_elf_merge_symbol (abfd, info, shortname, sym, &sec, &value,
if (!_bfd_elf_merge_symbol (abfd, info, shortname, sym, &sec, value, &hi, NULL, NULL, NULL, &skip, &override,
NULL, NULL, &hi, &skip, &override,
&type_change_ok, &size_change_ok)) &type_change_ok, &size_change_ok))
return FALSE; return FALSE;
@ -3831,7 +3835,6 @@ error_free_dyn:
bfd_boolean common; bfd_boolean common;
unsigned int old_alignment; unsigned int old_alignment;
bfd *old_bfd; bfd *old_bfd;
bfd * undef_bfd = NULL;
override = FALSE; override = FALSE;
@ -3977,22 +3980,6 @@ error_free_dyn:
unsigned int vernum = 0; unsigned int vernum = 0;
bfd_boolean skip; bfd_boolean skip;
/* If this is a definition of a symbol which was previously
referenced, then make a note of the bfd that contained the
reference. This is used if we need to refer to the source
of the reference later on. */
if (! bfd_is_und_section (sec))
{
h = elf_link_hash_lookup (elf_hash_table (info), name,
FALSE, FALSE, FALSE);
if (h != NULL
&& (h->root.type == bfd_link_hash_undefined
|| h->root.type == bfd_link_hash_undefweak)
&& h->root.u.undef.abfd)
undef_bfd = h->root.u.undef.abfd;
}
if (ever == NULL) if (ever == NULL)
{ {
if (info->default_imported_symver) if (info->default_imported_symver)
@ -4100,23 +4087,9 @@ error_free_dyn:
name = newname; name = newname;
} }
/* If necessary, make a second attempt to locate the bfd if (!_bfd_elf_merge_symbol (abfd, info, name, isym, &sec, &value,
containing an unresolved reference to the current symbol. */ sym_hash, &old_bfd, &old_weak,
if (! bfd_is_und_section (sec) && undef_bfd == NULL) &old_alignment, &skip, &override,
{
h = elf_link_hash_lookup (elf_hash_table (info), name,
FALSE, FALSE, FALSE);
if (h != NULL
&& (h->root.type == bfd_link_hash_undefined
|| h->root.type == bfd_link_hash_undefweak)
&& h->root.u.undef.abfd)
undef_bfd = h->root.u.undef.abfd;
}
if (!_bfd_elf_merge_symbol (abfd, info, name, isym, &sec,
&value, &old_weak, &old_alignment,
sym_hash, &skip, &override,
&type_change_ok, &size_change_ok)) &type_change_ok, &size_change_ok))
goto error_free_vers; goto error_free_vers;
@ -4131,28 +4104,6 @@ error_free_dyn:
|| h->root.type == bfd_link_hash_warning) || h->root.type == bfd_link_hash_warning)
h = (struct elf_link_hash_entry *) h->root.u.i.link; h = (struct elf_link_hash_entry *) h->root.u.i.link;
/* Remember the old alignment if this is a common symbol, so
that we don't reduce the alignment later on. We can't
check later, because _bfd_generic_link_add_one_symbol
will set a default for the alignment which we want to
override. We also remember the old bfd where the existing
definition comes from. */
switch (h->root.type)
{
default:
break;
case bfd_link_hash_defined:
case bfd_link_hash_defweak:
old_bfd = h->root.u.def.section->owner;
break;
case bfd_link_hash_common:
old_bfd = h->root.u.c.p->section->owner;
old_alignment = h->root.u.c.p->alignment_power;
break;
}
if (elf_tdata (abfd)->verdef != NULL if (elf_tdata (abfd)->verdef != NULL
&& vernum > 1 && vernum > 1
&& definition) && definition)
@ -4222,127 +4173,14 @@ error_free_dyn:
if (is_elf_hash_table (htab)) if (is_elf_hash_table (htab))
{ {
bfd_boolean dynsym;
/* Check the alignment when a common symbol is involved. This
can change when a common symbol is overridden by a normal
definition or a common symbol is ignored due to the old
normal definition. We need to make sure the maximum
alignment is maintained. */
if ((old_alignment || common)
&& h->root.type != bfd_link_hash_common)
{
unsigned int common_align;
unsigned int normal_align;
unsigned int symbol_align;
bfd *normal_bfd;
bfd *common_bfd;
symbol_align = ffs (h->root.u.def.value) - 1;
if (h->root.u.def.section->owner != NULL
&& (h->root.u.def.section->owner->flags & DYNAMIC) == 0)
{
normal_align = h->root.u.def.section->alignment_power;
if (normal_align > symbol_align)
normal_align = symbol_align;
}
else
normal_align = symbol_align;
if (old_alignment)
{
common_align = old_alignment;
common_bfd = old_bfd;
normal_bfd = abfd;
}
else
{
common_align = bfd_log2 (isym->st_value);
common_bfd = abfd;
normal_bfd = old_bfd;
}
if (normal_align < common_align)
{
/* PR binutils/2735 */
if (normal_bfd == NULL)
(*_bfd_error_handler)
(_("Warning: alignment %u of common symbol `%s' in %B"
" is greater than the alignment (%u) of its section %A"),
common_bfd, h->root.u.def.section,
1 << common_align, name, 1 << normal_align);
else
(*_bfd_error_handler)
(_("Warning: alignment %u of symbol `%s' in %B"
" is smaller than %u in %B"),
normal_bfd, common_bfd,
1 << normal_align, name, 1 << common_align);
}
}
/* Remember the symbol size if it isn't undefined. */
if ((isym->st_size != 0 && isym->st_shndx != SHN_UNDEF)
&& (definition || h->size == 0))
{
if (h->size != 0
&& h->size != isym->st_size
&& ! size_change_ok)
(*_bfd_error_handler)
(_("Warning: size of symbol `%s' changed"
" from %lu in %B to %lu in %B"),
old_bfd, abfd,
name, (unsigned long) h->size,
(unsigned long) isym->st_size);
h->size = isym->st_size;
}
/* If this is a common symbol, then we always want H->SIZE
to be the size of the common symbol. The code just above
won't fix the size if a common symbol becomes larger. We
don't warn about a size change here, because that is
covered by --warn-common. Allow changed between different
function types. */
if (h->root.type == bfd_link_hash_common)
h->size = h->root.u.c.size;
if (ELF_ST_TYPE (isym->st_info) != STT_NOTYPE
&& ((definition && !new_weak)
|| (old_weak && h->root.type == bfd_link_hash_common)
|| h->type == STT_NOTYPE))
{
unsigned int type = ELF_ST_TYPE (isym->st_info);
/* Turn an IFUNC symbol from a DSO into a normal FUNC
symbol. */
if (type == STT_GNU_IFUNC
&& (abfd->flags & DYNAMIC) != 0)
type = STT_FUNC;
if (h->type != type)
{
if (h->type != STT_NOTYPE && ! type_change_ok)
(*_bfd_error_handler)
(_("Warning: type of symbol `%s' changed"
" from %d to %d in %B"),
abfd, name, h->type, type);
h->type = type;
}
}
/* Merge st_other field. */
elf_merge_st_other (abfd, h, isym, definition, dynamic);
/* Set a flag in the hash table entry indicating the type of /* Set a flag in the hash table entry indicating the type of
reference or definition we just found. Keep a count of reference or definition we just found. A dynamic symbol
the number of dynamic symbols we find. A dynamic symbol
is one which is referenced or defined by both a regular is one which is referenced or defined by both a regular
object and a shared object. */ object and a shared object. */
dynsym = FALSE; bfd_boolean dynsym = FALSE;
/* Plugin symbols aren't normal. Don't set def_regular or /* Plugin symbols aren't normal. Don't set def_regular or
ref_regular for them, nor make them dynamic. */ ref_regular for them, or make them dynamic. */
if ((abfd->flags & BFD_PLUGIN) != 0) if ((abfd->flags & BFD_PLUGIN) != 0)
; ;
else if (! dynamic) else if (! dynamic)
@ -4395,24 +4233,138 @@ error_free_dyn:
dynsym = TRUE; dynsym = TRUE;
} }
/* Check to see if we need to add an indirect symbol for
the default name. */
if (definition
|| (!override && h->root.type == bfd_link_hash_common))
if (!_bfd_elf_add_default_symbol (abfd, info, h, name, isym,
sec, value, &old_bfd, &dynsym))
goto error_free_vers;
/* Check the alignment when a common symbol is involved. This
can change when a common symbol is overridden by a normal
definition or a common symbol is ignored due to the old
normal definition. We need to make sure the maximum
alignment is maintained. */
if ((old_alignment || common)
&& h->root.type != bfd_link_hash_common)
{
unsigned int common_align;
unsigned int normal_align;
unsigned int symbol_align;
bfd *normal_bfd;
bfd *common_bfd;
symbol_align = ffs (h->root.u.def.value) - 1;
if (h->root.u.def.section->owner != NULL
&& (h->root.u.def.section->owner->flags & DYNAMIC) == 0)
{
normal_align = h->root.u.def.section->alignment_power;
if (normal_align > symbol_align)
normal_align = symbol_align;
}
else
normal_align = symbol_align;
if (old_alignment)
{
common_align = old_alignment;
common_bfd = old_bfd;
normal_bfd = abfd;
}
else
{
common_align = bfd_log2 (isym->st_value);
common_bfd = abfd;
normal_bfd = old_bfd;
}
if (normal_align < common_align)
{
/* PR binutils/2735 */
if (normal_bfd == NULL)
(*_bfd_error_handler)
(_("Warning: alignment %u of common symbol `%s' in %B is"
" greater than the alignment (%u) of its section %A"),
common_bfd, h->root.u.def.section,
1 << common_align, name, 1 << normal_align);
else
(*_bfd_error_handler)
(_("Warning: alignment %u of symbol `%s' in %B"
" is smaller than %u in %B"),
normal_bfd, common_bfd,
1 << normal_align, name, 1 << common_align);
}
}
/* Remember the symbol size if it isn't undefined. */
if ((isym->st_size != 0 && isym->st_shndx != SHN_UNDEF)
&& (definition || h->size == 0))
{
if (h->size != 0
&& h->size != isym->st_size
&& ! size_change_ok)
(*_bfd_error_handler)
(_("Warning: size of symbol `%s' changed"
" from %lu in %B to %lu in %B"),
old_bfd, abfd,
name, (unsigned long) h->size,
(unsigned long) isym->st_size);
h->size = isym->st_size;
}
/* If this is a common symbol, then we always want H->SIZE
to be the size of the common symbol. The code just above
won't fix the size if a common symbol becomes larger. We
don't warn about a size change here, because that is
covered by --warn-common. Allow changes between different
function types. */
if (h->root.type == bfd_link_hash_common)
h->size = h->root.u.c.size;
if (ELF_ST_TYPE (isym->st_info) != STT_NOTYPE
&& ((definition && !new_weak)
|| (old_weak && h->root.type == bfd_link_hash_common)
|| h->type == STT_NOTYPE))
{
unsigned int type = ELF_ST_TYPE (isym->st_info);
/* Turn an IFUNC symbol from a DSO into a normal FUNC
symbol. */
if (type == STT_GNU_IFUNC
&& (abfd->flags & DYNAMIC) != 0)
type = STT_FUNC;
if (h->type != type)
{
if (h->type != STT_NOTYPE && ! type_change_ok)
(*_bfd_error_handler)
(_("Warning: type of symbol `%s' changed"
" from %d to %d in %B"),
abfd, name, h->type, type);
h->type = type;
}
}
/* Merge st_other field. */
elf_merge_st_other (abfd, h, isym, definition, dynamic);
/* We don't want to make debug symbol dynamic. */ /* We don't want to make debug symbol dynamic. */
if (definition && (sec->flags & SEC_DEBUGGING) && !info->relocatable) if (definition && (sec->flags & SEC_DEBUGGING) && !info->relocatable)
dynsym = FALSE; dynsym = FALSE;
/* Nor should we make plugin symbols dynamic. */
if ((abfd->flags & BFD_PLUGIN) != 0)
dynsym = FALSE;
if (definition) if (definition)
{ {
h->target_internal = isym->st_target_internal; h->target_internal = isym->st_target_internal;
h->unique_global = (flags & BSF_GNU_UNIQUE) != 0; h->unique_global = (flags & BSF_GNU_UNIQUE) != 0;
} }
/* Check to see if we need to add an indirect symbol for
the default name. */
if (definition
|| (!override && h->root.type == bfd_link_hash_common))
if (!_bfd_elf_add_default_symbol (abfd, info, h, name, isym,
&sec, &value, &dynsym))
goto error_free_vers;
if (definition && !dynamic) if (definition && !dynamic)
{ {
char *p = strchr (name, ELF_VER_CHR); char *p = strchr (name, ELF_VER_CHR);
@ -4463,8 +4415,8 @@ error_free_dyn:
&& definition && definition
&& ((dynsym && ((dynsym
&& h->ref_regular_nonweak && h->ref_regular_nonweak
&& (undef_bfd == NULL && (old_bfd == NULL
|| (undef_bfd->flags & BFD_PLUGIN) == 0)) || (old_bfd->flags & BFD_PLUGIN) == 0))
|| (h->ref_dynamic_nonweak || (h->ref_dynamic_nonweak
&& (elf_dyn_lib_class (abfd) & DYN_AS_NEEDED) != 0 && (elf_dyn_lib_class (abfd) & DYN_AS_NEEDED) != 0
&& !on_needed_list (elf_dt_name (abfd), htab->needed)))) && !on_needed_list (elf_dt_name (abfd), htab->needed))))
@ -4477,15 +4429,16 @@ error_free_dyn:
Add a DT_NEEDED entry for it. Issue an error if Add a DT_NEEDED entry for it. Issue an error if
--no-add-needed is used and the reference was not --no-add-needed is used and the reference was not
a weak one. */ a weak one. */
if (undef_bfd != NULL if (old_bfd != NULL
&& h->ref_regular_nonweak && h->ref_regular_nonweak
&& (elf_dyn_lib_class (abfd) & DYN_NO_NEEDED) != 0) && (elf_dyn_lib_class (abfd) & DYN_NO_NEEDED) != 0)
{ {
(*_bfd_error_handler) (*_bfd_error_handler)
(_("%B: undefined reference to symbol '%s'"), (_("%B: undefined reference to symbol '%s'"),
undef_bfd, name); old_bfd, name);
(*_bfd_error_handler) (*_bfd_error_handler)
(_("note: '%s' is defined in DSO %B so try adding it to the linker command line"), (_("note: '%s' is defined in DSO %B"
" so try adding it to the linker command line"),
abfd, name); abfd, name);
bfd_set_error (bfd_error_invalid_operation); bfd_set_error (bfd_error_invalid_operation);
goto error_free_vers; goto error_free_vers;