as: Replace the removed symbol with the versioned symbol

When a symbol removed by .symver is used in relocation and there is one
and only one versioned symbol, don't remove the symbol.  Instead, mark
it to be removed and replace the removed symbol used in relocation with
the versioned symbol before generating relocation.

	PR gas/28157
	* symbols.c (symbol_flags): Add removed.
	(symbol_entry_find): Updated.
	(symbol_mark_removed): New function.
	(symbol_removed_p): Likewise.
	* symbols.h (symbol_mark_removed): New prototype.
	(symbol_removed_p): Likewise.
	* write.c (write_relocs): Call obj_fixup_removed_symbol on
	removed fixp->fx_addsy and fixp->fx_subsy if defined.
	(set_symtab): Don't add a symbol if symbol_removed_p returns true.
	* config/obj-elf.c (elf_frob_symbol):  Don't remove the symbol
	if it is used on relocation.  Instead, mark it as to be removed
	and issue an error if the symbol has more than one versioned name.
	(elf_fixup_removed_symbol): New function.
	* config/obj-elf.h (elf_fixup_removed_symbol): New prototype.
	(obj_fixup_removed_symbol): New.
	* testsuite/gas/symver/symver11.d: Updated expected error
	message.
	* testsuite/gas/symver/symver16.d: New file.
	* testsuite/gas/symver/symver16.s: Likewise.
This commit is contained in:
H.J. Lu 2021-08-16 06:46:44 -07:00
parent 70069e7823
commit eb09df162b
8 changed files with 103 additions and 10 deletions

View File

@ -2705,7 +2705,7 @@ elf_frob_symbol (symbolS *symp, int *puntp)
S_SET_EXTERNAL (symp2);
}
switch (symbol_get_obj (symp)->visibility)
switch (sy_obj->visibility)
{
case visibility_unchanged:
break;
@ -2716,7 +2716,18 @@ elf_frob_symbol (symbolS *symp, int *puntp)
elfsym->internal_elf_sym.st_other |= STV_HIDDEN;
break;
case visibility_remove:
symbol_remove (symp, &symbol_rootP, &symbol_lastP);
/* Don't remove the symbol if it is used in relocation.
Instead, mark it as to be removed and issue an error
if the symbol has more than one versioned name. */
if (symbol_used_in_reloc_p (symp))
{
if (sy_obj->versioned_name->next != NULL)
as_bad (_("symbol '%s' with multiple versions cannot be used in relocation"),
S_GET_NAME (symp));
symbol_mark_removed (symp);
}
else
symbol_remove (symp, &symbol_rootP, &symbol_lastP);
break;
case visibility_local:
S_CLEAR_EXTERNAL (symp);
@ -2734,6 +2745,19 @@ elf_frob_symbol (symbolS *symp, int *puntp)
}
}
/* Fix up SYMPP which has been marked to be removed by .symver. */
void
elf_fixup_removed_symbol (symbolS **sympp)
{
symbolS *symp = *sympp;
struct elf_obj_sy *sy_obj = symbol_get_obj (symp);
/* Replace the removed symbol with the versioned symbol. */
symp = symbol_find (sy_obj->versioned_name->name);
*sympp = symp;
}
struct group_list
{
asection **head; /* Section lists. */

View File

@ -273,6 +273,11 @@ extern void elf_frob_symbol (symbolS *, int *);
#define obj_frob_symbol(symp, punt) elf_frob_symbol (symp, &punt)
#endif
extern void elf_fixup_removed_symbol (symbolS **);
#ifndef obj_fixup_removed_symbol
#define obj_fixup_removed_symbol(sympp) elf_fixup_removed_symbol (sympp)
#endif
extern void elf_pop_insert (void);
#ifndef obj_pop_insert
#define obj_pop_insert() elf_pop_insert()

View File

@ -78,6 +78,10 @@ struct symbol_flags
before. It is cleared as soon as any direct reference to the
symbol is present. */
unsigned int weakrefd : 1;
/* Whether the symbol has been marked to be removed by a .symver
directive. */
unsigned int removed : 1;
};
/* A pointer in the symbol may point to either a complete symbol
@ -194,7 +198,7 @@ static void *
symbol_entry_find (htab_t table, const char *name)
{
hashval_t hash = htab_hash_string (name);
symbol_entry_t needle = { { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
symbol_entry_t needle = { { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
hash, name, 0, 0, 0 } };
return htab_find_with_hash (table, &needle, hash);
}
@ -2807,6 +2811,26 @@ symbol_written_p (symbolS *s)
return s->flags.written;
}
/* Mark a symbol as to be removed. */
void
symbol_mark_removed (symbolS *s)
{
if (s->flags.local_symbol)
return;
s->flags.removed = 1;
}
/* Return whether a symbol has been marked to be removed. */
int
symbol_removed_p (symbolS *s)
{
if (s->flags.local_symbol)
return 0;
return s->flags.removed;
}
/* Mark a symbol has having been resolved. */
void

View File

@ -193,6 +193,8 @@ extern int symbol_mri_common_p (symbolS *);
extern void symbol_mark_written (symbolS *);
extern void symbol_clear_written (symbolS *);
extern int symbol_written_p (symbolS *);
extern void symbol_mark_removed (symbolS *);
extern int symbol_removed_p (symbolS *);
extern void symbol_mark_resolved (symbolS *);
extern int symbol_resolved_p (symbolS *);
extern int symbol_section_p (symbolS *);

View File

@ -1,2 +1,2 @@
#name: symver symver11
#error: .*symbol cannot be used on reloc
#error: .*: symbol 'foo' with multiple versions cannot be used in relocation

View File

@ -0,0 +1,13 @@
#name: symver symver16
#readelf: -srW
#...
Relocation section .*
#...
[0-9a-f]+[ \t]+[0-9a-f]+[ \t]+R_.*[ \t]+[0-9a-f]+[ \t]+foo@@VERS_1.*
#...
[0-9a-f]+[ \t]+[0-9a-f]+[ \t]+R_.*[ \t]+[0-9a-f]+[ \t]+bar@VERS_1.*
#...
+[0-9]+: 0+ +1 +OBJECT +GLOBAL +DEFAULT +[0-9]+ +foo@@VERS_1
+[0-9]+: 0+1 +1 +OBJECT +GLOBAL +DEFAULT +[0-9]+ +bar@VERS_1
#pass

View File

@ -0,0 +1,16 @@
.data
.type foo,%object
foo:
.byte 0
.size foo,.-foo
.globl foo
.symver foo,foo@@VERS_1,remove
.globl bar
.symver bar,bar@VERS_1,remove
.type bar,%object
bar:
.byte 0
.size bar,.-bar
.balign 8
.dc.a foo
.dc.a bar

View File

@ -1289,6 +1289,13 @@ write_relocs (bfd *abfd ATTRIBUTE_UNUSED, asection *sec,
as_bad_where (fixp->fx_file, fixp->fx_line,
_("internal error: fixup not contained within frag"));
#ifdef obj_fixup_removed_symbol
if (fixp->fx_addsy && symbol_removed_p (fixp->fx_addsy))
obj_fixup_removed_symbol (&fixp->fx_addsy);
if (fixp->fx_subsy && symbol_removed_p (fixp->fx_subsy))
obj_fixup_removed_symbol (&fixp->fx_subsy);
#endif
#ifndef RELOC_EXPANSION_POSSIBLE
*reloc = tc_gen_reloc (sec, fixp);
#else
@ -1755,9 +1762,10 @@ set_symtab (void)
two. Generate unused section symbols only if needed. */
nsyms = 0;
for (symp = symbol_rootP; symp; symp = symbol_next (symp))
if (bfd_keep_unused_section_symbols (stdoutput)
|| !symbol_section_p (symp)
|| symbol_used_in_reloc_p (symp))
if (!symbol_removed_p (symp)
&& (bfd_keep_unused_section_symbols (stdoutput)
|| !symbol_section_p (symp)
|| symbol_used_in_reloc_p (symp)))
nsyms++;
if (nsyms)
@ -1768,9 +1776,10 @@ set_symtab (void)
asympp = (asymbol **) bfd_alloc (stdoutput, amt);
symp = symbol_rootP;
for (i = 0; i < nsyms; symp = symbol_next (symp))
if (bfd_keep_unused_section_symbols (stdoutput)
|| !symbol_section_p (symp)
|| symbol_used_in_reloc_p (symp))
if (!symbol_removed_p (symp)
&& (bfd_keep_unused_section_symbols (stdoutput)
|| !symbol_section_p (symp)
|| symbol_used_in_reloc_p (symp)))
{
asympp[i] = symbol_get_bfdsym (symp);
if (asympp[i]->flags != BSF_SECTION_SYM