S_SET_EXTERNAL (symp2);
}
- switch (symbol_get_obj (symp)->visibility)
+ switch (sy_obj->visibility)
{
case visibility_unchanged:
break;
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);
}
}
+/* 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. */
#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()
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
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);
}
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
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 *);
#name: symver symver11
-#error: .*symbol cannot be used on reloc
+#error: .*: symbol 'foo' with multiple versions cannot be used in relocation
--- /dev/null
+#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
--- /dev/null
+ .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
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
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)
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