mirror of
https://github.com/serge1/ELFIO.git
synced 2024-12-26 09:14:29 +00:00
Added support for ".gnu.version_d"
This commit is contained in:
parent
41f4012d49
commit
647aba7a29
@ -1349,6 +1349,23 @@ struct Elf64_Dyn
|
||||
} d_un;
|
||||
};
|
||||
|
||||
struct Elfxx_Verdef
|
||||
{
|
||||
Elf_Half vd_version;
|
||||
Elf_Half vd_flags;
|
||||
Elf_Half vd_ndx;
|
||||
Elf_Half vd_cnt;
|
||||
Elf_Word vd_hash;
|
||||
Elf_Word vd_aux;
|
||||
Elf_Word vd_next;
|
||||
};
|
||||
|
||||
struct Elfxx_Verdaux
|
||||
{
|
||||
Elf_Word vda_name;
|
||||
Elf_Word vda_next;
|
||||
};
|
||||
|
||||
struct Elfxx_Verneed
|
||||
{
|
||||
Elf_Half vn_version;
|
||||
|
@ -174,6 +174,88 @@ using versym_r_section_accessor = versym_r_section_accessor_template<section>;
|
||||
using const_versym_r_section_accessor =
|
||||
versym_r_section_accessor_template<const section>;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class S> class versym_d_section_accessor_template
|
||||
{
|
||||
public:
|
||||
//------------------------------------------------------------------------------
|
||||
versym_d_section_accessor_template( const elfio& elf_file,
|
||||
S* versym_d_section )
|
||||
: elf_file( elf_file ), versym_d_section( versym_d_section ),
|
||||
entries_num( 0 )
|
||||
{
|
||||
// Find .dynamic section
|
||||
const section* dynamic_section = elf_file.sections[".dynamic"];
|
||||
|
||||
if ( dynamic_section == nullptr ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const_dynamic_section_accessor dynamic_section_acc( elf_file,
|
||||
dynamic_section );
|
||||
Elf_Xword dyn_sec_num = dynamic_section_acc.get_entries_num();
|
||||
for ( Elf_Xword i = 0; i < dyn_sec_num; ++i ) {
|
||||
Elf_Xword tag;
|
||||
Elf_Xword value;
|
||||
std::string str;
|
||||
|
||||
if ( dynamic_section_acc.get_entry( i, tag, value, str ) &&
|
||||
tag == DT_VERDEFNUM ) {
|
||||
entries_num = (Elf_Word)value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Elf_Word get_entries_num() const { return entries_num; }
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool get_entry( Elf_Word no,
|
||||
Elf_Half& flags,
|
||||
Elf_Half& version_index,
|
||||
Elf_Word& hash,
|
||||
std::string& dep_name ) const
|
||||
{
|
||||
if ( versym_d_section == nullptr || ( no >= get_entries_num() ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const_string_section_accessor string_section_acc(
|
||||
elf_file.sections[versym_d_section->get_link()] );
|
||||
|
||||
Elfxx_Verdef* verdef = (Elfxx_Verdef*)versym_d_section->get_data();
|
||||
Elfxx_Verdaux* verdaux =
|
||||
(Elfxx_Verdaux*)( (char*)verdef + verdef->vd_aux );
|
||||
for ( Elf_Word i = 0; i < no; ++i ) {
|
||||
verdef = (Elfxx_Verdef*)( (char*)verdef + verdef->vd_next );
|
||||
verdaux = (Elfxx_Verdaux*)( (char*)verdef + verdef->vd_aux );
|
||||
}
|
||||
|
||||
// verdef->vd_version should always be 1
|
||||
// see https://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA.junk/symversion.html#VERDEFENTRIES
|
||||
// verdef->vd_cnt should always be 1.
|
||||
// see https://maskray.me/blog/2020-11-26-all-about-symbol-versioning
|
||||
|
||||
flags = verdef->vd_flags;
|
||||
version_index = verdef->vd_ndx;
|
||||
hash = verdef->vd_hash;
|
||||
dep_name = string_section_acc.get_string( verdaux->vda_name );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
private:
|
||||
const elfio& elf_file;
|
||||
S* versym_d_section = nullptr;
|
||||
Elf_Word entries_num = 0;
|
||||
};
|
||||
|
||||
using versym_d_section_accessor = versym_d_section_accessor_template<section>;
|
||||
using const_versym_d_section_accessor =
|
||||
versym_d_section_accessor_template<const section>;
|
||||
|
||||
} // namespace ELFIO
|
||||
|
||||
#endif // ELFIO_VERSYM_HPP
|
||||
|
@ -416,6 +416,78 @@ TEST( ELFIOTest, gnu_version_64_le )
|
||||
EXPECT_EQ( dep_name, "GLIBC_2.2.5" );
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
TEST( ELFIOTest, gnu_version_d_64_le )
|
||||
{
|
||||
elfio reader;
|
||||
// Load ELF data
|
||||
|
||||
ASSERT_EQ( reader.load( "elf_examples/libversion_d.so" ), true );
|
||||
|
||||
section* dynsym = reader.sections[".dynsym"];
|
||||
const_symbol_section_accessor dynsym_acc( reader, dynsym );
|
||||
|
||||
section* gnu_version = reader.sections[".gnu.version"];
|
||||
const_versym_section_accessor gnu_version_arr( gnu_version );
|
||||
|
||||
const section* gnu_version_d = reader.sections[".gnu.version_d"];
|
||||
const_versym_d_section_accessor gnu_version_d_arr( reader, gnu_version_d );
|
||||
|
||||
section* dynstr = reader.sections[".dynstr"];
|
||||
|
||||
EXPECT_EQ( gnu_version_d->get_link(), dynstr->get_index() );
|
||||
|
||||
EXPECT_EQ( dynsym_acc.get_symbols_num(),
|
||||
gnu_version_arr.get_entries_num() );
|
||||
|
||||
EXPECT_EQ( dynsym_acc.get_symbols_num(), 10 );
|
||||
|
||||
EXPECT_EQ( gnu_version_d_arr.get_entries_num(), 3 );
|
||||
|
||||
auto v_check = [&]( const std::string& symbol,
|
||||
const std::string& vername ) -> void {
|
||||
std::string name;
|
||||
Elf64_Addr value;
|
||||
Elf_Xword size;
|
||||
unsigned char bind;
|
||||
unsigned char type;
|
||||
Elf_Half section_index;
|
||||
unsigned char other;
|
||||
Elf64_Half verindex;
|
||||
|
||||
for ( Elf64_Word i = 0; i < dynsym_acc.get_symbols_num(); i++ ) {
|
||||
ASSERT_EQ( dynsym_acc.get_symbol( i, name, value, size, bind, type,
|
||||
section_index, other ),
|
||||
true );
|
||||
|
||||
Elf64_Half vi;
|
||||
ASSERT_EQ( gnu_version_arr.get_entry( i, vi ), true );
|
||||
if ( name == symbol ) {
|
||||
verindex = vi;
|
||||
}
|
||||
}
|
||||
ASSERT_NE( verindex, 0 );
|
||||
|
||||
for ( Elf64_Word i = 0; i < gnu_version_d_arr.get_entries_num(); i++ ) {
|
||||
Elf_Half flags;
|
||||
Elf_Half version_index;
|
||||
Elf_Word hash;
|
||||
std::string dep_name;
|
||||
ASSERT_EQ( gnu_version_d_arr.get_entry( i, flags, version_index,
|
||||
hash, dep_name ),
|
||||
true );
|
||||
if ( version_index == verindex ) {
|
||||
EXPECT_EQ( flags, 0 );
|
||||
EXPECT_EQ( dep_name, vername );
|
||||
return;
|
||||
}
|
||||
}
|
||||
FAIL() << "version entry is not found";
|
||||
};
|
||||
v_check( "_Z20print_hello_world_v1v", "HELLO_1.0" );
|
||||
v_check( "_Z20print_hello_world_v2v", "HELLO_2.0" );
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// TEST( ELFIOTest, gnu_version_64_le_modify )
|
||||
// {
|
||||
|
5
tests/elf_examples/version_d.cpp
Normal file
5
tests/elf_examples/version_d.cpp
Normal file
@ -0,0 +1,5 @@
|
||||
#include <stdio.h>
|
||||
|
||||
void print_hello_world_v1() { printf( "hello v1" ); }
|
||||
|
||||
void print_hello_world_v2() { printf( "hello v2" ); }
|
9
tests/elf_examples/version_d.map
Normal file
9
tests/elf_examples/version_d.map
Normal file
@ -0,0 +1,9 @@
|
||||
HELLO_1.0 {
|
||||
global:
|
||||
_Z20print_hello_world_v1v;
|
||||
};
|
||||
|
||||
HELLO_2.0 {
|
||||
global:
|
||||
_Z20print_hello_world_v2v;
|
||||
};
|
Loading…
Reference in New Issue
Block a user