aboutsummaryrefslogtreecommitdiff
path: root/gas/config
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2021-08-16 06:46:44 -0700
committerH.J. Lu <hjl.tools@gmail.com>2021-08-16 06:46:44 -0700
commiteb09df162bafa67abee713be594a99bd20bd6825 (patch)
tree8cea62798489a53661cacaa7eab76421d8340463 /gas/config
parent70069e7823d412a01d983379504222c557319cbd (diff)
downloadfsf-binutils-gdb-eb09df162bafa67abee713be594a99bd20bd6825.zip
fsf-binutils-gdb-eb09df162bafa67abee713be594a99bd20bd6825.tar.gz
fsf-binutils-gdb-eb09df162bafa67abee713be594a99bd20bd6825.tar.bz2
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.
Diffstat (limited to 'gas/config')
-rw-r--r--gas/config/obj-elf.c28
-rw-r--r--gas/config/obj-elf.h5
2 files changed, 31 insertions, 2 deletions
diff --git a/gas/config/obj-elf.c b/gas/config/obj-elf.c
index 42a3851..a6087a2 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 d1fd315..763c58d 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()