mirror of
https://github.com/QuasarApp/LIEF.git
synced 2025-04-26 20:34:32 +00:00
Sort dynamic symbols
This commit is contained in:
parent
2145d79efb
commit
50a348e7f0
@ -93,6 +93,8 @@ class LIEF_API Builder {
|
||||
template<typename ELF_T>
|
||||
void build_symbol_gnuhash(void);
|
||||
|
||||
uint32_t sort_dynamic_symbols(void);
|
||||
|
||||
void build_empty_symbol_gnuhash(void);
|
||||
|
||||
template<typename ELF_T>
|
||||
|
@ -111,6 +111,46 @@ void Builder::write(const std::string& filename) const {
|
||||
}
|
||||
|
||||
|
||||
uint32_t Builder::sort_dynamic_symbols(void) {
|
||||
auto it_begin = std::begin(this->binary_->dynamic_symbols_);
|
||||
auto it_end = std::end(this->binary_->dynamic_symbols_);
|
||||
|
||||
auto it_first_non_local_symbol =
|
||||
std::stable_partition(it_begin, it_end, [](const Symbol* sym) {
|
||||
return sym->binding() == SYMBOL_BINDINGS::STB_LOCAL;
|
||||
});
|
||||
uint32_t first_non_local_symbol_index =
|
||||
std::distance(it_begin, it_first_non_local_symbol);
|
||||
std::string section_name = ".dynsym";
|
||||
if (this->binary_->has_section(section_name)) {
|
||||
Section& section = this->binary_->get_section(section_name);
|
||||
if (section.information() != first_non_local_symbol_index) {
|
||||
// TODO: Erase null entries of dynamic symbol table and symbol version table
|
||||
// if information of .dynsym section is smaller than null entries num.
|
||||
LIEF_WARN("information of {} section changes from {:d} to {:d}",
|
||||
section_name,
|
||||
section.information(),
|
||||
first_non_local_symbol_index);
|
||||
section.information(first_non_local_symbol_index);
|
||||
}
|
||||
}
|
||||
|
||||
auto it_first_exported_symbol = std::stable_partition(
|
||||
it_first_non_local_symbol, it_end, [](const Symbol* sym) {
|
||||
return sym->shndx() ==
|
||||
static_cast<uint16_t>(SYMBOL_SECTION_INDEX::SHN_UNDEF);
|
||||
});
|
||||
uint32_t first_exported_symbol_index =
|
||||
std::distance(it_begin, it_first_exported_symbol);
|
||||
if (this->binary_->gnu_hash().symbol_index() != first_exported_symbol_index) {
|
||||
LIEF_WARN("symndx of .gnu.hash section changes from {:d} to {:d}",
|
||||
this->binary_->gnu_hash().symbol_index(),
|
||||
first_exported_symbol_index);
|
||||
}
|
||||
return first_exported_symbol_index;
|
||||
}
|
||||
|
||||
|
||||
void Builder::build_empty_symbol_gnuhash(void) {
|
||||
LIEF_DEBUG("Build empty GNU Hash");
|
||||
auto&& it_gnuhash = std::find_if(
|
||||
|
@ -892,7 +892,7 @@ void Builder::build_symbol_gnuhash(void) {
|
||||
const GnuHash& gnu_hash = this->binary_->gnu_hash();
|
||||
|
||||
const uint32_t nb_buckets = gnu_hash.nb_buckets();
|
||||
const uint32_t symndx = gnu_hash.symbol_index();
|
||||
const uint32_t symndx = sort_dynamic_symbols();
|
||||
const uint32_t maskwords = gnu_hash.maskwords();
|
||||
const uint32_t shift2 = gnu_hash.shift2();
|
||||
|
||||
|
@ -126,6 +126,46 @@ class TestDynamic(TestCase):
|
||||
def setUp(self):
|
||||
self.logger = logging.getLogger(__name__)
|
||||
|
||||
@unittest.skipUnless(sys.platform.startswith("linux"), "requires Linux")
|
||||
def test_add_dynamic_symbols(self):
|
||||
sample = LibAddSample()
|
||||
libadd = lief.parse(sample.libadd)
|
||||
binadd = lief.parse(sample.binadd)
|
||||
dynamic_symbols = list(libadd.dynamic_symbols)
|
||||
for sym in dynamic_symbols:
|
||||
libadd.add_dynamic_symbol(sym)
|
||||
dynamic_section = libadd.get_section(".dynsym")
|
||||
libadd.extend(dynamic_section, dynamic_section.entry_size * (len(dynamic_symbols) * 2))
|
||||
libadd.write(sample.libadd)
|
||||
|
||||
p = Popen([sample.binadd_bin, '1', '2'],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
env={"LD_LIBRARY_PATH": sample.directory})
|
||||
stdout, _ = p.communicate()
|
||||
if p.returncode > 0:
|
||||
self.logger.fatal(stdout.decode("utf8"))
|
||||
self.assertEqual(p.returncode, 0)
|
||||
self.logger.debug(stdout.decode("utf8"))
|
||||
self.assertIsNotNone(re.search(r'From myLIb, a \+ b = 3', stdout.decode("utf8")))
|
||||
|
||||
libadd = lief.parse(sample.libadd)
|
||||
dynamic_section = libadd.get_section(".dynsym")
|
||||
# TODO: Size of libadd.dynamic_symbols is larger than dynamic_symbols_size.
|
||||
dynamic_symbols_size = int(dynamic_section.size / dynamic_section.entry_size)
|
||||
dynamic_symbols = list(libadd.dynamic_symbols)[:dynamic_symbols_size]
|
||||
first_not_null_symbol_index = dynamic_section.information
|
||||
first_exported_symbol_index = next(
|
||||
i for i, sym in enumerate(dynamic_symbols) if sym.shndx != 0)
|
||||
self.assertTrue(all(map(
|
||||
lambda sym: sym.shndx == 0 and sym.binding == lief.ELF.SYMBOL_BINDINGS.LOCAL,
|
||||
dynamic_symbols[:first_not_null_symbol_index])))
|
||||
self.assertTrue(all(map(
|
||||
lambda sym: sym.shndx == 0 and sym.binding != lief.ELF.SYMBOL_BINDINGS.LOCAL,
|
||||
dynamic_symbols[first_not_null_symbol_index:first_exported_symbol_index])))
|
||||
self.assertTrue(all(map(
|
||||
lambda sym: sym.shndx != 0,
|
||||
dynamic_symbols[first_exported_symbol_index:])))
|
||||
|
||||
@unittest.skipUnless(sys.platform.startswith("linux"), "requires Linux")
|
||||
def test_remove_library(self):
|
||||
|
Loading…
x
Reference in New Issue
Block a user