[PATCH] as: Replace the removed symbol with the versioned symbol
H.J. Lu
hjl.tools@gmail.com
Fri Aug 13 22:44:12 GMT 2021
On Sun, Aug 1, 2021 at 8:16 AM H.J. Lu <hjl.tools@gmail.com> wrote:
>
> 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.
Hi Nick, Alan,
Can you review this patch?
Thanks.
> 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.
> ---
> gas/config/obj-elf.c | 28 ++++++++++++++++++++++++++--
> gas/config/obj-elf.h | 5 +++++
> gas/symbols.c | 26 +++++++++++++++++++++++++-
> gas/symbols.h | 2 ++
> gas/testsuite/gas/symver/symver11.d | 2 +-
> gas/testsuite/gas/symver/symver16.d | 13 +++++++++++++
> gas/testsuite/gas/symver/symver16.s | 16 ++++++++++++++++
> gas/write.c | 21 +++++++++++++++------
> 8 files changed, 103 insertions(+), 10 deletions(-)
> create mode 100644 gas/testsuite/gas/symver/symver16.d
> create mode 100644 gas/testsuite/gas/symver/symver16.s
>
> diff --git a/gas/config/obj-elf.c b/gas/config/obj-elf.c
> index 42a3851e772..a6087a21eb3 100644
> --- a/gas/config/obj-elf.c
> +++ b/gas/config/obj-elf.c
> @@ -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. */
> diff --git a/gas/config/obj-elf.h b/gas/config/obj-elf.h
> index d1fd3152998..763c58dfcad 100644
> --- a/gas/config/obj-elf.h
> +++ b/gas/config/obj-elf.h
> @@ -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()
> diff --git a/gas/symbols.c b/gas/symbols.c
> index 302eb4bd6f7..3cb9425c4ce 100644
> --- a/gas/symbols.c
> +++ b/gas/symbols.c
> @@ -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
> diff --git a/gas/symbols.h b/gas/symbols.h
> index 91f69882a7e..317252c7fa1 100644
> --- a/gas/symbols.h
> +++ b/gas/symbols.h
> @@ -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 *);
> diff --git a/gas/testsuite/gas/symver/symver11.d b/gas/testsuite/gas/symver/symver11.d
> index caa76e167da..10f8ef810b2 100644
> --- a/gas/testsuite/gas/symver/symver11.d
> +++ b/gas/testsuite/gas/symver/symver11.d
> @@ -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
> diff --git a/gas/testsuite/gas/symver/symver16.d b/gas/testsuite/gas/symver/symver16.d
> new file mode 100644
> index 00000000000..cdf0ddde57d
> --- /dev/null
> +++ b/gas/testsuite/gas/symver/symver16.d
> @@ -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
> diff --git a/gas/testsuite/gas/symver/symver16.s b/gas/testsuite/gas/symver/symver16.s
> new file mode 100644
> index 00000000000..df330fd4f25
> --- /dev/null
> +++ b/gas/testsuite/gas/symver/symver16.s
> @@ -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
> diff --git a/gas/write.c b/gas/write.c
> index 253dfc476f8..e2c7bf29249 100644
> --- a/gas/write.c
> +++ b/gas/write.c
> @@ -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
> --
> 2.31.1
>
--
H.J.
More information about the Binutils
mailing list