Skip to content

Commit

Permalink
Improve the logic of the AUTO symbol counting (idea from: @adamjseitz)
Browse files Browse the repository at this point in the history
  • Loading branch information
romainthomas committed Jun 3, 2023
1 parent 0d7c39d commit 528435f
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 22 deletions.
55 changes: 33 additions & 22 deletions src/ELF/Parser.tcc
Original file line number Diff line number Diff line change
Expand Up @@ -437,39 +437,50 @@ result<uint32_t> Parser::get_numberof_dynamic_symbols(DYNSYM_COUNT_METHODS mtd)
case DYNSYM_COUNT_METHODS::COUNT_AUTO:
default:
{
uint32_t nb_dynsym = 0;
uint32_t nb_dynsym_tmp = 0;
uint32_t nb_reloc = 0;
uint32_t nb_section = 0;
uint32_t nb_hash = 0;

auto res = get_numberof_dynamic_symbols<ELF_T>(DYNSYM_COUNT_METHODS::COUNT_RELOCATIONS);
if (res) {
nb_dynsym = res.value();
if (auto res = get_numberof_dynamic_symbols<ELF_T>(DYNSYM_COUNT_METHODS::COUNT_RELOCATIONS)) {
nb_reloc = *res;
}
res = get_numberof_dynamic_symbols<ELF_T>(DYNSYM_COUNT_METHODS::COUNT_SECTION);
if (res) {
nb_dynsym_tmp = res.value();

if (auto res = get_numberof_dynamic_symbols<ELF_T>(DYNSYM_COUNT_METHODS::COUNT_SECTION)) {
nb_section = *res;
}

if (auto res = get_numberof_dynamic_symbols<ELF_T>(DYNSYM_COUNT_METHODS::COUNT_HASH)) {
nb_hash = *res;
}

if (nb_dynsym_tmp < Parser::NB_MAX_SYMBOLS &&
nb_dynsym_tmp > nb_dynsym &&
(nb_dynsym_tmp - nb_dynsym) < Parser::DELTA_NB_SYMBOLS)
LIEF_DEBUG("#dynsym.reloc: {}", nb_reloc);
LIEF_DEBUG("#dynsym.section: {}", nb_section);
LIEF_DEBUG("#dynsym.hash: {}", nb_hash);

if (nb_hash > 0 && nb_section == nb_hash) {
return nb_hash;
}

uint32_t candidate = nb_reloc;
if (nb_section < Parser::NB_MAX_SYMBOLS &&
nb_section > nb_reloc &&
(nb_section - nb_reloc) < Parser::DELTA_NB_SYMBOLS)
{
nb_dynsym = nb_dynsym_tmp;
candidate = nb_section;
}

res = get_numberof_dynamic_symbols<ELF_T>(DYNSYM_COUNT_METHODS::COUNT_HASH);
if (!res) {
// Fail to get number of symbols from the hash table
return nb_dynsym;
if (nb_hash == 0) {
return candidate;
}

nb_dynsym_tmp = res.value();
if (nb_dynsym_tmp < Parser::NB_MAX_SYMBOLS &&
nb_dynsym_tmp > nb_dynsym &&
(nb_dynsym_tmp - nb_dynsym) < Parser::DELTA_NB_SYMBOLS)
if (nb_hash < Parser::NB_MAX_SYMBOLS &&
nb_hash > candidate &&
(nb_hash - candidate) < Parser::DELTA_NB_SYMBOLS)
{
nb_dynsym = nb_dynsym_tmp;
candidate = nb_hash;
}
return nb_dynsym;

return candidate;
}
}
}
Expand Down
8 changes: 8 additions & 0 deletions tests/elf/test_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ def test_symbol_count():
assert len(gcc2.symbols) == 158
assert len(gcc3.symbols) == 158

def test_issue_922():
libcrypto_path = get_sample('ELF/libcrypto.so')
auto = lief.ELF.parse(libcrypto_path)
assert len(auto.symbols) == 14757

section = lief.ELF.parse(libcrypto_path, lief.ELF.DYNSYM_COUNT_METHODS.SECTION)
assert len(section.symbols) == 14757

def test_tiny():
tiny = lief.parse(get_sample('ELF/ELF32_x86_binary_tiny01.bin'))
assert len(tiny.segments) == 1
Expand Down
5 changes: 5 additions & 0 deletions tests/elf/test_section_frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ def test_frame(tmp_path):

def test_sectionless(tmp_path):
elf: lief.ELF.Binary = lief.parse(get_sample("ELF/mbedtls_selftest.elf64"))

assert len(elf.dynamic_symbols) == 40

header: lief.ELF.Header = elf.header

header.numberof_sections = 0
Expand All @@ -52,6 +55,8 @@ def test_sectionless(tmp_path):
sectionless = lief.parse(out.as_posix())
out = pathlib.Path(tmp_path) / "mbedtls_selftest.sectionless.built"

assert len(sectionless.dynamic_symbols) == 40

sectionless.add_library(sectionless.libraries[0])
sectionless.write(out.as_posix())

Expand Down

0 comments on commit 528435f

Please sign in to comment.