gas/ELF: don't accumulate .type settings

Recently a patch was submitted for a Xen Project test harness binary to
override the compiler specified @object to @func (see [1]). In a reply I
suggested we shouldn't make ourselves dependent on currently unspecified
behavior of gas here: It accumulates all requests, and then
bfd/elf.c:swap_out_syms(), in an apparently ad hoc manner, prioritizes
certain flags over others.

Make the behavior predictable: Generally the last .type is what counts.
Exceptions are directives which set multiple bits (TLS, IFUNC, and
UNIQUE): Subsequent directives requesting just the more generic bit
(i.e. FUNC following IFUNC) won't clear the more specific one.  Warn
about incompatible changes, except from/to STT_NOTYPE.

Also add a new target hook, which hppa wants to use right away afaict.

In the course of adding the warning I ran into two ld testsuite
failures.  I can only assume that it was a copy-and-paste mistake that
lead to the same symbol having its type set twice.

[1] https://lists.xenproject.org/archives/html/xen-devel/2019-05/msg01980.html
This commit is contained in:
Jan Beulich
2019-07-04 10:35:47 +02:00
parent db7fbcbeb7
commit f2d4ba38f5
10 changed files with 123 additions and 2 deletions

View File

@@ -2069,7 +2069,38 @@ obj_elf_type (int ignore ATTRIBUTE_UNUSED)
if (*input_line_pointer == '"')
++input_line_pointer;
elfsym->symbol.flags |= type;
#ifdef md_elf_symbol_type_change
if (!md_elf_symbol_type_change (sym, elfsym, type))
#endif
{
flagword mask = BSF_FUNCTION | BSF_OBJECT;
if (type != BSF_FUNCTION)
mask |= BSF_GNU_INDIRECT_FUNCTION;
if (type != BSF_OBJECT)
{
mask |= BSF_GNU_UNIQUE | BSF_THREAD_LOCAL;
if (S_IS_COMMON (sym))
{
as_bad (_("cannot change type of common symbol '%s'"),
S_GET_NAME (sym));
mask = type = 0;
}
}
/* Don't warn when changing to STT_NOTYPE. */
if (type)
{
flagword new = (elfsym->symbol.flags & ~mask) | type;
if (new != (elfsym->symbol.flags | type))
as_warn (_("symbol '%s' already has its type set"), S_GET_NAME (sym));
elfsym->symbol.flags = new;
}
else
elfsym->symbol.flags &= ~mask;
}
demand_empty_rest_of_line ();
}