diff options
author | H.J. Lu <hjl.tools@gmail.com> | 2024-05-31 21:30:34 -0700 |
---|---|---|
committer | H.J. Lu <hjl.tools@gmail.com> | 2024-06-08 23:54:39 -0700 |
commit | 89d801850ac03d0531f7eef3d6978bec17a30a2d (patch) | |
tree | 7c8719feee02ca0df80571a765d46ce05394bd71 /gold/symtab.cc | |
parent | 2b05f934486de42f8200bf11cece21ae3bc284e6 (diff) | |
download | gdb-89d801850ac03d0531f7eef3d6978bec17a30a2d.zip gdb-89d801850ac03d0531f7eef3d6978bec17a30a2d.tar.gz gdb-89d801850ac03d0531f7eef3d6978bec17a30a2d.tar.bz2 |
gold: Properly remove the versioned symbol
When the versioned symbol foo is removed from the shared library, the
".symver foo,foo@VER" directive provides binary compatibility for foo@VER.
In this case, the unversioned symbol foo should be hidden and shouldn't
generate a multiple definition error.
PR gold/31830
* resolve.cc (Symbol_table::resolve): Move symbol version handling
to ...
* symtab.cc (Symbol_table::add_from_object): Here. If the hidden
version from .symver is the same as the default version from the
unversioned symbol, don't make the unversioned symbol the default
versioned
symbol.
* testsuite/Makefile.am (check_SCRIPTS): Add ver_test_pr31830.sh.
(check_DATA): ver_test_pr31830_a.syms and ver_test_pr31830_b.syms.
(ver_test_pr31830_a.syms): New.
(ver_test_pr31830_b.syms): Likewise.
(ver_test_pr31830_a.so): Likewise.
(ver_test_pr31830_b.so): Likewise.
* testsuite/Makefile.in: Regenerated.
* testsuite/ver_test_pr31830.script: New file.
* testsuite/ver_test_pr31830.sh: Likewise.
* testsuite/ver_test_pr31830_a.c: Likewise.
* testsuite/ver_test_pr31830_b.c: Likewise.
* testsuite/ver_test_pr31830_lto.c: Likewise.
* testsuite/ver_test_pr31830_lto.sh: Likewise.
Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
Diffstat (limited to 'gold/symtab.cc')
-rw-r--r-- | gold/symtab.cc | 76 |
1 files changed, 65 insertions, 11 deletions
diff --git a/gold/symtab.cc b/gold/symtab.cc index 9a55e6e..5857dd7 100644 --- a/gold/symtab.cc +++ b/gold/symtab.cc @@ -998,12 +998,64 @@ Symbol_table::add_from_object(Object* object, ret = this->get_sized_symbol<size>(ins.first->second); gold_assert(ret != NULL); + bool ret_is_ordinary; + const unsigned int ret_shndx = ret->shndx(&ret_is_ordinary); + was_undefined_in_reg = ret->is_undefined() && ret->in_reg(); // Commons from plugins are just placeholders. was_common = ret->is_common() && ret->object()->pluginobj() == NULL; - this->resolve(ret, sym, st_shndx, is_ordinary, orig_st_shndx, object, - version, is_default_version); + // It's possible for a symbol to be defined in an object file + // using .symver to give it a version, and for there to also be + // a linker script giving that symbol the same version. We + // don't want to give a multiple-definition error for this + // harmless redefinition. + bool check_version = false; + bool erase_default_version = false; + bool no_default_version = false; + if (ret->source() == Symbol::FROM_OBJECT + && is_ordinary + && ret_shndx == st_shndx) + { + if (ret->object() == object) + check_version = true; + + if (version != NULL && version == ret->version()) + { + // Don't give a multiple-definition error if the hidden + // version from .symver is the same as the default version + // from the unversioned symbol. + if (is_default_version && !ret->is_default ()) + { + no_default_version = true; + if (insdefault.second) + { + // Don't make the unversioned symbol the default + // version. + is_default_version = false; + erase_default_version = true; + check_version = true; + } + } + else if (!is_default_version && ret->is_default ()) + { + // Don't make the unversioned symbol the default + // version. + ret->set_is_not_default(); + no_default_version = true; + check_version = true; + } + } + } + + if (!(check_version + && ret->is_defined() + && ret_is_ordinary + && (no_default_version + || ret->value() == sym.get_st_value()))) + this->resolve(ret, sym, st_shndx, is_ordinary, orig_st_shndx, + object, version, is_default_version); + if (parameters->options().gc_sections()) this->gc_mark_dyn_syms(ret); @@ -1012,13 +1064,7 @@ Symbol_table::add_from_object(Object* object, insdefault.first); else { - bool dummy; - if (version != NULL - && ret->source() == Symbol::FROM_OBJECT - && ret->object() == object - && is_ordinary - && ret->shndx(&dummy) == st_shndx - && ret->is_default()) + if (version != NULL && check_version) { // We have seen NAME/VERSION already, and marked it as the // default version, but now we see a definition for @@ -1032,9 +1078,17 @@ Symbol_table::add_from_object(Object* object, // In any other case, the two symbols should have generated // a multiple definition error. // (See PR gold/18703.) - ret->set_is_not_default(); + // If the hidden version from .symver is the same as the + // default version from the unversioned symbol, don't make + // the unversioned symbol the default versioned symbol. const Stringpool::Key vnull_key = 0; - this->table_.erase(std::make_pair(name_key, vnull_key)); + if (erase_default_version) + this->table_.erase(std::make_pair(name_key, vnull_key)); + else if (ret->object() == object) + { + ret->set_is_not_default(); + this->table_.erase(std::make_pair(name_key, vnull_key)); + } } } } |