mirror of
https://github.com/serge1/ELFIO.git
synced 2024-12-26 18:15:40 +00:00
Add support for GNU hash lookup algorithm
This commit is contained in:
parent
46b1e22414
commit
ef262285dc
@ -87,30 +87,24 @@ template <class S> class symbol_section_accessor_template
|
||||
|
||||
if ( 0 != get_hash_table_index() ) {
|
||||
if ( hash_section->get_type() == SHT_HASH ) {
|
||||
Elf_Word nbucket = *(const Elf_Word*)hash_section->get_data();
|
||||
Elf_Word nchain = *(const Elf_Word*)( hash_section->get_data() +
|
||||
sizeof( Elf_Word ) );
|
||||
Elf_Word val = elf_hash( (const unsigned char*)name.c_str() );
|
||||
Elf_Word y = *(const Elf_Word*)( hash_section->get_data() +
|
||||
( 2 + val % nbucket ) *
|
||||
sizeof( Elf_Word ) );
|
||||
std::string str;
|
||||
get_symbol( y, str, value, size, bind, type, section_index,
|
||||
other );
|
||||
while ( str != name && STN_UNDEF != y && y < nchain ) {
|
||||
y = *(const Elf_Word*)( hash_section->get_data() +
|
||||
( 2 + nbucket + y ) *
|
||||
sizeof( Elf_Word ) );
|
||||
get_symbol( y, str, value, size, bind, type, section_index,
|
||||
other );
|
||||
ret = hash_lookup( name, value, size, bind, type, section_index,
|
||||
other );
|
||||
}
|
||||
if ( hash_section->get_type() == SHT_GNU_HASH ||
|
||||
hash_section->get_type() == DT_GNU_HASH ) {
|
||||
if ( elf_file.get_class() == ELFCLASS32 ) {
|
||||
ret = gnu_hash_lookup<uint32_t>(
|
||||
name, value, size, bind, type, section_index, other );
|
||||
}
|
||||
if ( str == name ) {
|
||||
ret = true;
|
||||
else {
|
||||
ret = gnu_hash_lookup<uint64_t>(
|
||||
name, value, size, bind, type, section_index, other );
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for ( Elf_Xword i = 0; i < get_symbols_num() && !ret; i++ ) {
|
||||
|
||||
if ( !ret ) {
|
||||
for ( Elf_Xword i = 0; !ret && i < get_symbols_num(); i++ ) {
|
||||
std::string symbol_name;
|
||||
if ( get_symbol( i, symbol_name, value, size, bind, type,
|
||||
section_index, other ) ) {
|
||||
@ -279,6 +273,109 @@ template <class S> class symbol_section_accessor_template
|
||||
//------------------------------------------------------------------------------
|
||||
Elf_Half get_hash_table_index() const { return hash_section_index; }
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool hash_lookup( const std::string& name,
|
||||
Elf64_Addr& value,
|
||||
Elf_Xword& size,
|
||||
unsigned char& bind,
|
||||
unsigned char& type,
|
||||
Elf_Half& section_index,
|
||||
unsigned char& other ) const
|
||||
{
|
||||
bool ret = false;
|
||||
const endianess_convertor& convertor = elf_file.get_convertor();
|
||||
|
||||
Elf_Word nbucket = *(const Elf_Word*)hash_section->get_data();
|
||||
nbucket = convertor( nbucket );
|
||||
Elf_Word nchain =
|
||||
*(const Elf_Word*)( hash_section->get_data() + sizeof( Elf_Word ) );
|
||||
nchain = convertor( nchain );
|
||||
Elf_Word val = elf_hash( (const unsigned char*)name.c_str() );
|
||||
Elf_Word y =
|
||||
*(const Elf_Word*)( hash_section->get_data() +
|
||||
( 2 + val % nbucket ) * sizeof( Elf_Word ) );
|
||||
y = convertor( y );
|
||||
std::string str;
|
||||
get_symbol( y, str, value, size, bind, type, section_index, other );
|
||||
while ( str != name && STN_UNDEF != y && y < nchain ) {
|
||||
y = *(const Elf_Word*)( hash_section->get_data() +
|
||||
( 2 + nbucket + y ) * sizeof( Elf_Word ) );
|
||||
y = convertor( y );
|
||||
get_symbol( y, str, value, size, bind, type, section_index, other );
|
||||
}
|
||||
|
||||
if ( str == name ) {
|
||||
ret = true;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class T>
|
||||
bool gnu_hash_lookup( const std::string& name,
|
||||
Elf64_Addr& value,
|
||||
Elf_Xword& size,
|
||||
unsigned char& bind,
|
||||
unsigned char& type,
|
||||
Elf_Half& section_index,
|
||||
unsigned char& other ) const
|
||||
{
|
||||
bool ret = false;
|
||||
const endianess_convertor& convertor = elf_file.get_convertor();
|
||||
|
||||
uint32_t nbuckets = *( (uint32_t*)hash_section->get_data() + 0 );
|
||||
uint32_t symoffset = *( (uint32_t*)hash_section->get_data() + 1 );
|
||||
uint32_t bloom_size = *( (uint32_t*)hash_section->get_data() + 2 );
|
||||
uint32_t bloom_shift = *( (uint32_t*)hash_section->get_data() + 3 );
|
||||
nbuckets = convertor( nbuckets );
|
||||
symoffset = convertor( symoffset );
|
||||
bloom_size = convertor( bloom_size );
|
||||
bloom_shift = convertor( bloom_shift );
|
||||
|
||||
T* bloom_filter =
|
||||
(T*)( hash_section->get_data() + 4 * sizeof( uint32_t ) );
|
||||
|
||||
uint32_t hash = elf_gnu_hash( (const unsigned char*)name.c_str() );
|
||||
uint32_t bloom_index = ( hash / ( 8 * sizeof( T ) ) ) % bloom_size;
|
||||
T bloom_bits =
|
||||
( (T)1 << ( hash % ( 8 * sizeof( T ) ) ) ) |
|
||||
( (T)1 << ( ( hash >> bloom_shift ) % ( 8 * sizeof( T ) ) ) );
|
||||
|
||||
if ( ( convertor( bloom_filter[bloom_index] ) & bloom_bits ) ==
|
||||
bloom_bits ) {
|
||||
uint32_t bucket = hash % nbuckets;
|
||||
uint32_t* buckets =
|
||||
(uint32_t*)( hash_section->get_data() + 4 * sizeof( uint32_t ) +
|
||||
bloom_size * sizeof( T ) );
|
||||
uint32_t* chains =
|
||||
(uint32_t*)( hash_section->get_data() + 4 * sizeof( uint32_t ) +
|
||||
bloom_size * sizeof( T ) +
|
||||
nbuckets * sizeof( uint32_t ) );
|
||||
|
||||
if ( convertor( buckets[bucket] ) >= symoffset ) {
|
||||
uint32_t chain_index = convertor( buckets[bucket] ) - symoffset;
|
||||
uint32_t chain_hash = convertor( chains[chain_index] );
|
||||
std::string symname;
|
||||
while ( true ) {
|
||||
if ( ( chain_hash >> 1 ) == ( hash >> 1 ) &&
|
||||
get_symbol( chain_index + symoffset, symname, value,
|
||||
size, bind, type, section_index, other ) &&
|
||||
name == symname ) {
|
||||
ret = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( chain_hash & 1 )
|
||||
break;
|
||||
chain_hash = convertor( chains[++chain_index] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class T> const T* generic_get_symbol_ptr( Elf_Xword index ) const
|
||||
{
|
||||
|
@ -91,7 +91,7 @@ class endianess_convertor
|
||||
if ( !need_conversion ) {
|
||||
return value;
|
||||
}
|
||||
return ( int64_t )( *this )( (uint64_t)value );
|
||||
return (int64_t)(*this)( (uint64_t)value );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -113,7 +113,7 @@ class endianess_convertor
|
||||
if ( !need_conversion ) {
|
||||
return value;
|
||||
}
|
||||
return ( int32_t )( *this )( (uint32_t)value );
|
||||
return (int32_t)(*this)( (uint32_t)value );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -133,7 +133,7 @@ class endianess_convertor
|
||||
if ( !need_conversion ) {
|
||||
return value;
|
||||
}
|
||||
return ( int16_t )( *this )( (uint16_t)value );
|
||||
return (int16_t)(*this)( (uint16_t)value );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -175,6 +175,16 @@ inline uint32_t elf_hash( const unsigned char* name )
|
||||
return h;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
inline uint32_t elf_gnu_hash( const unsigned char* s )
|
||||
{
|
||||
uint32_t h = 0x1505;
|
||||
for ( unsigned char c = *s; c != '\0'; c = *++s )
|
||||
h = ( h << 5 ) + h + c;
|
||||
return h;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
inline std::string to_hex_string( uint64_t value )
|
||||
{
|
||||
std::string str;
|
||||
@ -191,6 +201,7 @@ inline std::string to_hex_string( uint64_t value )
|
||||
return "0x" + str;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
inline void adjust_stream_size( std::ostream& stream, std::streamsize offset )
|
||||
{
|
||||
stream.seekp( 0, stream.end );
|
||||
|
@ -243,3 +243,115 @@ BOOST_AUTO_TEST_CASE( test_hex )
|
||||
BOOST_CHECK_EQUAL( to_hex_string( 0xFFFFFFFFFFFFFFFF ),
|
||||
"0xFFFFFFFFFFFFFFFF" );
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
BOOST_AUTO_TEST_CASE( hash32_le )
|
||||
{
|
||||
elfio reader;
|
||||
// Load ELF data
|
||||
|
||||
BOOST_REQUIRE_EQUAL( reader.load( "elf_examples/ARMSCII-8.so" ), true );
|
||||
|
||||
std::string name;
|
||||
Elf64_Addr value;
|
||||
Elf_Xword size;
|
||||
unsigned char bind;
|
||||
unsigned char type;
|
||||
Elf_Half section_index;
|
||||
unsigned char other;
|
||||
section* symsec = reader.sections[".dynsym"];
|
||||
symbol_section_accessor syms( reader, symsec );
|
||||
|
||||
for ( int i = 0; i < syms.get_symbols_num(); i++ ) {
|
||||
BOOST_REQUIRE_EQUAL( syms.get_symbol( i, name, value, size, bind, type,
|
||||
section_index, other ),
|
||||
true );
|
||||
BOOST_CHECK_EQUAL( syms.get_symbol( name, value, size, bind, type,
|
||||
section_index, other ),
|
||||
true );
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
BOOST_AUTO_TEST_CASE( hash32_be )
|
||||
{
|
||||
elfio reader;
|
||||
// Load ELF data
|
||||
|
||||
BOOST_REQUIRE_EQUAL( reader.load( "elf_examples/test_ppc" ), true );
|
||||
|
||||
std::string name;
|
||||
Elf64_Addr value;
|
||||
Elf_Xword size;
|
||||
unsigned char bind;
|
||||
unsigned char type;
|
||||
Elf_Half section_index;
|
||||
unsigned char other;
|
||||
section* symsec = reader.sections[".dynsym"];
|
||||
symbol_section_accessor syms( reader, symsec );
|
||||
|
||||
for ( int i = 0; i < syms.get_symbols_num(); i++ ) {
|
||||
BOOST_REQUIRE_EQUAL( syms.get_symbol( i, name, value, size, bind, type,
|
||||
section_index, other ),
|
||||
true );
|
||||
BOOST_CHECK_EQUAL( syms.get_symbol( name, value, size, bind, type,
|
||||
section_index, other ),
|
||||
true );
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
BOOST_AUTO_TEST_CASE( gnu_hash32_le )
|
||||
{
|
||||
elfio reader;
|
||||
// Load ELF data
|
||||
|
||||
BOOST_REQUIRE_EQUAL( reader.load( "elf_examples/hello_32" ), true );
|
||||
|
||||
std::string name;
|
||||
Elf64_Addr value;
|
||||
Elf_Xword size;
|
||||
unsigned char bind;
|
||||
unsigned char type;
|
||||
Elf_Half section_index;
|
||||
unsigned char other;
|
||||
section* symsec = reader.sections[".dynsym"];
|
||||
symbol_section_accessor syms( reader, symsec );
|
||||
|
||||
for ( int i = 0; i < syms.get_symbols_num(); i++ ) {
|
||||
BOOST_REQUIRE_EQUAL( syms.get_symbol( i, name, value, size, bind, type,
|
||||
section_index, other ),
|
||||
true );
|
||||
BOOST_CHECK_EQUAL( syms.get_symbol( name, value, size, bind, type,
|
||||
section_index, other ),
|
||||
true );
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
BOOST_AUTO_TEST_CASE( gnu_hash64_le )
|
||||
{
|
||||
elfio reader;
|
||||
// Load ELF data
|
||||
|
||||
BOOST_REQUIRE_EQUAL( reader.load( "elf_examples/main" ), true );
|
||||
|
||||
std::string name;
|
||||
Elf64_Addr value;
|
||||
Elf_Xword size;
|
||||
unsigned char bind;
|
||||
unsigned char type;
|
||||
Elf_Half section_index;
|
||||
unsigned char other;
|
||||
section* symsec = reader.sections[".dynsym"];
|
||||
symbol_section_accessor syms( reader, symsec );
|
||||
|
||||
for ( int i = 0; i < syms.get_symbols_num(); i++ ) {
|
||||
BOOST_REQUIRE_EQUAL( syms.get_symbol( i, name, value, size, bind, type,
|
||||
section_index, other ),
|
||||
true );
|
||||
BOOST_CHECK_EQUAL( syms.get_symbol( name, value, size, bind, type,
|
||||
section_index, other ),
|
||||
true );
|
||||
}
|
||||
}
|
||||
|
0
tests/elf_examples/arm_v7m_test_debug.elf
Executable file → Normal file
0
tests/elf_examples/arm_v7m_test_debug.elf
Executable file → Normal file
0
tests/elf_examples/arm_v7m_test_release.elf
Executable file → Normal file
0
tests/elf_examples/arm_v7m_test_release.elf
Executable file → Normal file
0
tests/elf_examples/ctors
Executable file → Normal file
0
tests/elf_examples/ctors
Executable file → Normal file
0
tests/elf_examples/read_write_arm_elf32_input
Executable file → Normal file
0
tests/elf_examples/read_write_arm_elf32_input
Executable file → Normal file
Loading…
Reference in New Issue
Block a user