diff options
-rw-r--r-- | gas/config/obj-elf.c | 28 | ||||
-rw-r--r-- | gas/config/obj-elf.h | 5 | ||||
-rw-r--r-- | gas/symbols.c | 26 | ||||
-rw-r--r-- | gas/symbols.h | 2 | ||||
-rw-r--r-- | gas/testsuite/gas/symver/symver11.d | 2 | ||||
-rw-r--r-- | gas/testsuite/gas/symver/symver16.d | 13 | ||||
-rw-r--r-- | gas/testsuite/gas/symver/symver16.s | 16 | ||||
-rw-r--r-- | gas/write.c | 21 |
8 files changed, 103 insertions, 10 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() diff --git a/gas/symbols.c b/gas/symbols.c index 302eb4b..3cb9425 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 91f6988..317252c 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 caa76e1..10f8ef8 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 0000000..cdf0ddd --- /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 0000000..df330fd --- /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 253dfc4..e2c7bf2 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 |