diff --git a/api/python/src/ELF/objects/pySymbolVersionDefinition.cpp b/api/python/src/ELF/objects/pySymbolVersionDefinition.cpp index 25183748..02e537ad 100644 --- a/api/python/src/ELF/objects/pySymbolVersionDefinition.cpp +++ b/api/python/src/ELF/objects/pySymbolVersionDefinition.cpp @@ -54,6 +54,9 @@ void create(nb::module_& m) { nb::overload_cast(&SymbolVersionDefinition::hash), "Hash value of the symbol's name (using ELF hash function)"_doc) + .def_prop_ro("ndx", &SymbolVersionDefinition::ndx, + "Numeric value used as an index in the :class`~.ELF.SymbolVersion` table"_doc) + .def_prop_ro("auxiliary_symbols", nb::overload_cast<>(&SymbolVersionDefinition::symbols_aux), nb::rv_policy::reference_internal) diff --git a/src/ELF/Builder.tcc b/src/ELF/Builder.tcc index 2e182fb1..b96d613b 100644 --- a/src/ELF/Builder.tcc +++ b/src/ELF/Builder.tcc @@ -1623,6 +1623,8 @@ ok_error_t Builder::build_symbol_definition() { vector_iostream svd_aux_raw(should_swap()); { for (const auto& names : verdef_info.names_list) { + verdef_info.names_offset[&names] = svd_aux_raw.tellp(); + for (size_t i = 0; i < names.size(); ++i) { const std::string& sva_name = names[i]; uint64_t dynstr_offset = 0; @@ -1634,13 +1636,13 @@ ok_error_t Builder::build_symbol_definition() { } dynstr_offset = it_name_offset->second; - const uint64_t next_offset = i < (names.size() - 1) ? - sizeof(Elf_Verdaux) : 0; + const bool is_last = i == (names.size() - 1); + const uint64_t next_offset = !is_last ? sizeof(Elf_Verdaux) : 0; Elf_Verdaux aux_header; aux_header.vda_name = static_cast(dynstr_offset); aux_header.vda_next = static_cast(next_offset); - verdef_info.names_offset[&names] = svd_aux_raw.tellp(); + svd_aux_raw.write_conv(aux_header); } } @@ -1652,8 +1654,8 @@ ok_error_t Builder::build_symbol_definition() { { for (size_t i = 0; i < sym_verdef.size(); ++i) { const SymbolVersionDefinition& svd = sym_verdef[i]; - const uint64_t next_offset = i < (sym_verdef.size() - 1) ? - sizeof(Elf_Verdef) : 0; + const bool is_last = i == (sym_verdef.size() - 1); + const uint64_t next_offset = !is_last ? sizeof(Elf_Verdef) : 0; auto it_names = verdef_info.def_to_names.find(&svd); if (it_names == verdef_info.def_to_names.end()) { diff --git a/src/ELF/Parser.tcc b/src/ELF/Parser.tcc index c6285972..089be17b 100644 --- a/src/ELF/Parser.tcc +++ b/src/ELF/Parser.tcc @@ -1514,48 +1514,46 @@ ok_error_t Parser::parse_symbol_version_requirement(uint64_t offset, uint32_t nb return ok(); } - template ok_error_t Parser::parse_symbol_version_definition(uint64_t offset, uint32_t nb_entries) { using Elf_Verdef = typename ELF_T::Elf_Verdef; using Elf_Verdaux = typename ELF_T::Elf_Verdaux; const uint64_t string_offset = get_dynamic_string_table(); - ScopedStream sscoped(*stream_, offset); + ScopedStream verdef_stream(*stream_, offset); uint64_t def_size = 0; for (size_t i = 0; i < nb_entries; ++i) { - const auto svd_header = sscoped->peek_conv(); - def_size = std::max(def_size, sscoped->pos() - offset + sizeof(Elf_Verdef)); + const auto svd_header = verdef_stream->peek_conv(); + def_size = std::max(def_size, verdef_stream->pos() - offset + sizeof(Elf_Verdef)); if (!svd_header) { break; } auto symbol_version_definition = std::make_unique(*svd_header); uint32_t nb_aux_symbols = svd_header->vd_cnt; - uint32_t next_aux_offset = 0; - - for (size_t j = 0; j < nb_aux_symbols; ++j) { - ScopedStream aux_stream(*stream_, sscoped->pos() + svd_header->vd_aux); - const auto svda_header = aux_stream->peek_conv(); - def_size = std::max(def_size, aux_stream->pos() - offset + sizeof(Elf_Verdaux)); - if (!svda_header) { - break; - } - - if (string_offset != 0) { - auto name = stream_->peek_string_at(string_offset + svda_header->vda_name); - if (name) { - symbol_version_definition->symbol_version_aux_.emplace_back(new SymbolVersionAux{std::move(*name)}); + { + ScopedStream aux_stream(*stream_, verdef_stream->pos() + svd_header->vd_aux); + for (size_t j = 0; j < nb_aux_symbols; ++j) { + const auto svda_header = aux_stream->peek_conv(); + def_size = std::max(def_size, aux_stream->pos() - offset + sizeof(Elf_Verdaux)); + if (!svda_header) { + break; } - } - // Additional check - if (svda_header->vda_next == 0) { - break; + if (string_offset != 0) { + auto name = stream_->peek_string_at(string_offset + svda_header->vda_name); + if (name) { + symbol_version_definition->symbol_version_aux_.emplace_back(new SymbolVersionAux{std::move(*name)}); + } + } + + // Additional check + if (svda_header->vda_next == 0) { + break; + } + aux_stream->increment_pos(svda_header->vda_next); } - aux_stream->increment_pos(svda_header->vda_next); - next_aux_offset += svda_header->vda_next; } binary_->symbol_version_definition_.push_back(std::move(symbol_version_definition)); @@ -1564,7 +1562,7 @@ ok_error_t Parser::parse_symbol_version_definition(uint64_t offset, uint32_t nb_ if (svd_header->vd_next == 0) { break; } - sscoped->increment_pos(svd_header->vd_next); + verdef_stream->increment_pos(svd_header->vd_next); } binary_->sizing_info_->verdef = def_size; diff --git a/tests/elf/test_symbol_versions.py b/tests/elf/test_symbol_versions.py index f5e28fec..650073bc 100644 --- a/tests/elf/test_symbol_versions.py +++ b/tests/elf/test_symbol_versions.py @@ -1,7 +1,7 @@ import pytest import lief -import pathlib +from pathlib import Path from utils import get_sample @@ -11,5 +11,36 @@ def test_issue_749(): sym = lib.get_dynamic_symbol("foo") assert sym.symbol_version.symbol_version_auxiliary.name == "LIBFOO_2.0" +def test_issue_1014(tmp_path: Path): + lib_path = get_sample('ELF/libfoo_issue_1014.so') + lib: lief.ELF.Binary = lief.parse(lib_path) + def check_lib(lib: lief.ELF.Binary): + svd = lib.symbols_version_definition + assert len(svd) == 6 + assert len(svd[0].auxiliary_symbols) == 1 + assert svd[0].auxiliary_symbols[0].name == "libfoo.so" + assert len(svd[1].auxiliary_symbols) == 1 + assert svd[1].auxiliary_symbols[0].name == "LIBFOO_1.0" + + assert len(svd[2].auxiliary_symbols) == 2 + assert svd[2].auxiliary_symbols[0].name == "LIBFOO_2.0" + assert svd[2].auxiliary_symbols[1].name == "LIBFOO_1.0" + + assert len(svd[3].auxiliary_symbols) == 2 + assert svd[3].auxiliary_symbols[0].name == "LIBFOO_3.0" + assert svd[3].auxiliary_symbols[1].name == "LIBFOO_2.0" + + assert len(svd[4].auxiliary_symbols) == 1 + assert svd[4].auxiliary_symbols[0].name == "LIBBAR_1.0" + + assert len(svd[5].auxiliary_symbols) == 2 + assert svd[5].auxiliary_symbols[0].name == "LIBBAR_2.0" + assert svd[5].auxiliary_symbols[1].name == "LIBBAR_1.0" + check_lib(lib) + + out = tmp_path / "libfoo_issue_1014.so" + lib.write(out.as_posix()) + new_lib = lief.ELF.parse(out.as_posix()) + check_lib(new_lib)