1 /* 2 Copyright (C) 2001-present by Serge Lamikhov-Center 3 4 Permission is hereby granted, free of charge, to any person obtaining a copy 5 of this software and associated documentation files (the "Software"), to deal 6 in the Software without restriction, including without limitation the rights 7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 copies of the Software, and to permit persons to whom the Software is 9 furnished to do so, subject to the following conditions: 10 11 The above copyright notice and this permission notice shall be included in 12 all copies or substantial portions of the Software. 13 14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 THE SOFTWARE. 21 */ 22 23 #ifndef ELFIO_SYMBOLS_HPP 24 #define ELFIO_SYMBOLS_HPP 25 26 namespace ELFIO { 27 28 //------------------------------------------------------------------------------ 29 template <class S> class symbol_section_accessor_template 30 { 31 public: 32 //------------------------------------------------------------------------------ symbol_section_accessor_template(const elfio & elf_file,S * symbol_section)33 explicit symbol_section_accessor_template( const elfio& elf_file, 34 S* symbol_section ) 35 : elf_file( elf_file ), symbol_section( symbol_section ) 36 { 37 find_hash_section(); 38 } 39 40 //------------------------------------------------------------------------------ get_symbols_num() const41 Elf_Xword get_symbols_num() const 42 { 43 Elf_Xword nRet = 0; 44 45 size_t minimum_symbol_size; 46 switch ( elf_file.get_class() ) { 47 case ELFCLASS32: 48 minimum_symbol_size = sizeof( Elf32_Sym ); 49 break; 50 case ELFCLASS64: 51 minimum_symbol_size = sizeof( Elf64_Sym ); 52 break; 53 default: 54 return nRet; 55 } 56 57 if ( symbol_section->get_entry_size() >= minimum_symbol_size && 58 symbol_section->get_size() <= symbol_section->get_stream_size() ) { 59 nRet = 60 symbol_section->get_size() / symbol_section->get_entry_size(); 61 } 62 63 return nRet; 64 } 65 66 //------------------------------------------------------------------------------ get_symbol(Elf_Xword index,std::string & name,Elf64_Addr & value,Elf_Xword & size,unsigned char & bind,unsigned char & type,Elf_Half & section_index,unsigned char & other) const67 bool get_symbol( Elf_Xword index, 68 std::string& name, 69 Elf64_Addr& value, 70 Elf_Xword& size, 71 unsigned char& bind, 72 unsigned char& type, 73 Elf_Half& section_index, 74 unsigned char& other ) const 75 { 76 bool ret = false; 77 78 if ( elf_file.get_class() == ELFCLASS32 ) { 79 ret = generic_get_symbol<Elf32_Sym>( index, name, value, size, bind, 80 type, section_index, other ); 81 } 82 else { 83 ret = generic_get_symbol<Elf64_Sym>( index, name, value, size, bind, 84 type, section_index, other ); 85 } 86 87 return ret; 88 } 89 90 //------------------------------------------------------------------------------ get_symbol(const std::string & name,Elf64_Addr & value,Elf_Xword & size,unsigned char & bind,unsigned char & type,Elf_Half & section_index,unsigned char & other) const91 bool get_symbol( const std::string& name, 92 Elf64_Addr& value, 93 Elf_Xword& size, 94 unsigned char& bind, 95 unsigned char& type, 96 Elf_Half& section_index, 97 unsigned char& other ) const 98 { 99 bool ret = false; 100 101 if ( 0 != get_hash_table_index() ) { 102 if ( hash_section->get_type() == SHT_HASH ) { 103 ret = hash_lookup( name, value, size, bind, type, section_index, 104 other ); 105 } 106 if ( hash_section->get_type() == SHT_GNU_HASH || 107 hash_section->get_type() == DT_GNU_HASH ) { 108 if ( elf_file.get_class() == ELFCLASS32 ) { 109 ret = gnu_hash_lookup<uint32_t>( 110 name, value, size, bind, type, section_index, other ); 111 } 112 else { 113 ret = gnu_hash_lookup<uint64_t>( 114 name, value, size, bind, type, section_index, other ); 115 } 116 } 117 } 118 119 if ( !ret ) { 120 for ( Elf_Xword i = 0; !ret && i < get_symbols_num(); i++ ) { 121 std::string symbol_name; 122 if ( get_symbol( i, symbol_name, value, size, bind, type, 123 section_index, other ) ) { 124 if ( symbol_name == name ) { 125 ret = true; 126 } 127 } 128 } 129 } 130 131 return ret; 132 } 133 134 //------------------------------------------------------------------------------ get_symbol(const Elf64_Addr & value,std::string & name,Elf_Xword & size,unsigned char & bind,unsigned char & type,Elf_Half & section_index,unsigned char & other) const135 bool get_symbol( const Elf64_Addr& value, 136 std::string& name, 137 Elf_Xword& size, 138 unsigned char& bind, 139 unsigned char& type, 140 Elf_Half& section_index, 141 unsigned char& other ) const 142 { 143 144 const endianess_convertor& convertor = elf_file.get_convertor(); 145 146 Elf_Xword idx = 0; 147 bool match = false; 148 Elf64_Addr v = 0; 149 150 if ( elf_file.get_class() == ELFCLASS32 ) { 151 match = generic_search_symbols<Elf32_Sym>( 152 [&]( const Elf32_Sym* sym ) { 153 return convertor( sym->st_value ) == value; 154 }, 155 idx ); 156 } 157 else { 158 match = generic_search_symbols<Elf64_Sym>( 159 [&]( const Elf64_Sym* sym ) { 160 return convertor( sym->st_value ) == value; 161 }, 162 idx ); 163 } 164 165 if ( match ) { 166 return get_symbol( idx, name, v, size, bind, type, section_index, 167 other ); 168 } 169 170 return false; 171 } 172 173 //------------------------------------------------------------------------------ add_symbol(Elf_Word name,Elf64_Addr value,Elf_Xword size,unsigned char info,unsigned char other,Elf_Half shndx)174 Elf_Word add_symbol( Elf_Word name, 175 Elf64_Addr value, 176 Elf_Xword size, 177 unsigned char info, 178 unsigned char other, 179 Elf_Half shndx ) 180 { 181 Elf_Word nRet; 182 183 if ( symbol_section->get_size() == 0 ) { 184 if ( elf_file.get_class() == ELFCLASS32 ) { 185 nRet = generic_add_symbol<Elf32_Sym>( 0, 0, 0, 0, 0, 0 ); 186 } 187 else { 188 nRet = generic_add_symbol<Elf64_Sym>( 0, 0, 0, 0, 0, 0 ); 189 } 190 } 191 192 if ( elf_file.get_class() == ELFCLASS32 ) { 193 nRet = generic_add_symbol<Elf32_Sym>( name, value, size, info, 194 other, shndx ); 195 } 196 else { 197 nRet = generic_add_symbol<Elf64_Sym>( name, value, size, info, 198 other, shndx ); 199 } 200 201 return nRet; 202 } 203 204 //------------------------------------------------------------------------------ add_symbol(Elf_Word name,Elf64_Addr value,Elf_Xword size,unsigned char bind,unsigned char type,unsigned char other,Elf_Half shndx)205 Elf_Word add_symbol( Elf_Word name, 206 Elf64_Addr value, 207 Elf_Xword size, 208 unsigned char bind, 209 unsigned char type, 210 unsigned char other, 211 Elf_Half shndx ) 212 { 213 return add_symbol( name, value, size, ELF_ST_INFO( bind, type ), other, 214 shndx ); 215 } 216 217 //------------------------------------------------------------------------------ add_symbol(string_section_accessor & pStrWriter,const char * str,Elf64_Addr value,Elf_Xword size,unsigned char info,unsigned char other,Elf_Half shndx)218 Elf_Word add_symbol( string_section_accessor& pStrWriter, 219 const char* str, 220 Elf64_Addr value, 221 Elf_Xword size, 222 unsigned char info, 223 unsigned char other, 224 Elf_Half shndx ) 225 { 226 Elf_Word index = pStrWriter.add_string( str ); 227 return add_symbol( index, value, size, info, other, shndx ); 228 } 229 230 //------------------------------------------------------------------------------ add_symbol(string_section_accessor & pStrWriter,const char * str,Elf64_Addr value,Elf_Xword size,unsigned char bind,unsigned char type,unsigned char other,Elf_Half shndx)231 Elf_Word add_symbol( string_section_accessor& pStrWriter, 232 const char* str, 233 Elf64_Addr value, 234 Elf_Xword size, 235 unsigned char bind, 236 unsigned char type, 237 unsigned char other, 238 Elf_Half shndx ) 239 { 240 return add_symbol( pStrWriter, str, value, size, 241 ELF_ST_INFO( bind, type ), other, shndx ); 242 } 243 244 //------------------------------------------------------------------------------ arrange_local_symbols(std::function<void (Elf_Xword first,Elf_Xword second)> func=nullptr)245 Elf_Xword arrange_local_symbols( 246 std::function<void( Elf_Xword first, Elf_Xword second )> func = 247 nullptr ) 248 { 249 Elf_Xword nRet = 0; 250 251 if ( elf_file.get_class() == ELFCLASS32 ) { 252 nRet = generic_arrange_local_symbols<Elf32_Sym>( func ); 253 } 254 else { 255 nRet = generic_arrange_local_symbols<Elf64_Sym>( func ); 256 } 257 258 return nRet; 259 } 260 261 //------------------------------------------------------------------------------ 262 private: 263 //------------------------------------------------------------------------------ find_hash_section()264 void find_hash_section() 265 { 266 Elf_Half nSecNo = elf_file.sections.size(); 267 for ( Elf_Half i = 0; i < nSecNo; ++i ) { 268 const section* sec = elf_file.sections[i]; 269 if ( sec->get_link() == symbol_section->get_index() && 270 ( sec->get_type() == SHT_HASH || 271 sec->get_type() == SHT_GNU_HASH || 272 sec->get_type() == DT_GNU_HASH ) ) { 273 hash_section = sec; 274 hash_section_index = i; 275 break; 276 } 277 } 278 } 279 280 //------------------------------------------------------------------------------ get_string_table_index() const281 Elf_Half get_string_table_index() const 282 { 283 return (Elf_Half)symbol_section->get_link(); 284 } 285 286 //------------------------------------------------------------------------------ get_hash_table_index() const287 Elf_Half get_hash_table_index() const { return hash_section_index; } 288 289 //------------------------------------------------------------------------------ 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) const290 bool hash_lookup( const std::string& name, 291 Elf64_Addr& value, 292 Elf_Xword& size, 293 unsigned char& bind, 294 unsigned char& type, 295 Elf_Half& section_index, 296 unsigned char& other ) const 297 { 298 bool ret = false; 299 const endianess_convertor& convertor = elf_file.get_convertor(); 300 301 Elf_Word nbucket = *(const Elf_Word*)hash_section->get_data(); 302 nbucket = convertor( nbucket ); 303 Elf_Word nchain = 304 *(const Elf_Word*)( hash_section->get_data() + sizeof( Elf_Word ) ); 305 nchain = convertor( nchain ); 306 Elf_Word val = elf_hash( (const unsigned char*)name.c_str() ); 307 Elf_Word y = 308 *(const Elf_Word*)( hash_section->get_data() + 309 ( 2 + val % nbucket ) * sizeof( Elf_Word ) ); 310 y = convertor( y ); 311 std::string str; 312 get_symbol( y, str, value, size, bind, type, section_index, other ); 313 while ( str != name && STN_UNDEF != y && y < nchain ) { 314 y = *(const Elf_Word*)( hash_section->get_data() + 315 ( 2 + nbucket + y ) * sizeof( Elf_Word ) ); 316 y = convertor( y ); 317 get_symbol( y, str, value, size, bind, type, section_index, other ); 318 } 319 320 if ( str == name ) { 321 ret = true; 322 } 323 324 return ret; 325 } 326 327 //------------------------------------------------------------------------------ 328 template <class T> 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) const329 bool gnu_hash_lookup( const std::string& name, 330 Elf64_Addr& value, 331 Elf_Xword& size, 332 unsigned char& bind, 333 unsigned char& type, 334 Elf_Half& section_index, 335 unsigned char& other ) const 336 { 337 bool ret = false; 338 const endianess_convertor& convertor = elf_file.get_convertor(); 339 340 uint32_t nbuckets = *( (uint32_t*)hash_section->get_data() + 0 ); 341 uint32_t symoffset = *( (uint32_t*)hash_section->get_data() + 1 ); 342 uint32_t bloom_size = *( (uint32_t*)hash_section->get_data() + 2 ); 343 uint32_t bloom_shift = *( (uint32_t*)hash_section->get_data() + 3 ); 344 nbuckets = convertor( nbuckets ); 345 symoffset = convertor( symoffset ); 346 bloom_size = convertor( bloom_size ); 347 bloom_shift = convertor( bloom_shift ); 348 349 T* bloom_filter = 350 (T*)( hash_section->get_data() + 4 * sizeof( uint32_t ) ); 351 352 uint32_t hash = elf_gnu_hash( (const unsigned char*)name.c_str() ); 353 uint32_t bloom_index = ( hash / ( 8 * sizeof( T ) ) ) % bloom_size; 354 T bloom_bits = 355 ( (T)1 << ( hash % ( 8 * sizeof( T ) ) ) ) | 356 ( (T)1 << ( ( hash >> bloom_shift ) % ( 8 * sizeof( T ) ) ) ); 357 358 if ( ( convertor( bloom_filter[bloom_index] ) & bloom_bits ) != 359 bloom_bits ) 360 return ret; 361 362 uint32_t bucket = hash % nbuckets; 363 auto* buckets = 364 (uint32_t*)( hash_section->get_data() + 4 * sizeof( uint32_t ) + 365 bloom_size * sizeof( T ) ); 366 auto* chains = 367 (uint32_t*)( hash_section->get_data() + 4 * sizeof( uint32_t ) + 368 bloom_size * sizeof( T ) + 369 nbuckets * sizeof( uint32_t ) ); 370 371 if ( convertor( buckets[bucket] ) >= symoffset ) { 372 uint32_t chain_index = convertor( buckets[bucket] ) - symoffset; 373 uint32_t chain_hash = convertor( chains[chain_index] ); 374 std::string symname; 375 376 while ( true ) { 377 if ( ( chain_hash >> 1 ) == ( hash >> 1 ) && 378 get_symbol( chain_index + symoffset, symname, value, size, 379 bind, type, section_index, other ) && 380 name == symname ) { 381 ret = true; 382 break; 383 } 384 385 if ( chain_hash & 1 ) 386 break; 387 chain_hash = convertor( chains[++chain_index] ); 388 } 389 } 390 391 return ret; 392 } 393 394 //------------------------------------------------------------------------------ generic_get_symbol_ptr(Elf_Xword index) const395 template <class T> const T* generic_get_symbol_ptr( Elf_Xword index ) const 396 { 397 if ( 0 != symbol_section->get_data() && index < get_symbols_num() ) { 398 const T* pSym = reinterpret_cast<const T*>( 399 symbol_section->get_data() + 400 index * symbol_section->get_entry_size() ); 401 402 return pSym; 403 } 404 405 return nullptr; 406 } 407 408 //------------------------------------------------------------------------------ 409 template <class T> generic_search_symbols(std::function<bool (const T *)> match,Elf_Xword & idx) const410 bool generic_search_symbols( std::function<bool( const T* )> match, 411 Elf_Xword& idx ) const 412 { 413 for ( Elf_Xword i = 0; i < get_symbols_num(); i++ ) { 414 const T* symPtr = generic_get_symbol_ptr<T>( i ); 415 416 if ( symPtr == nullptr ) 417 return false; 418 419 if ( match( symPtr ) ) { 420 idx = i; 421 return true; 422 } 423 } 424 425 return false; 426 } 427 428 //------------------------------------------------------------------------------ 429 template <class T> generic_get_symbol(Elf_Xword index,std::string & name,Elf64_Addr & value,Elf_Xword & size,unsigned char & bind,unsigned char & type,Elf_Half & section_index,unsigned char & other) const430 bool generic_get_symbol( Elf_Xword index, 431 std::string& name, 432 Elf64_Addr& value, 433 Elf_Xword& size, 434 unsigned char& bind, 435 unsigned char& type, 436 Elf_Half& section_index, 437 unsigned char& other ) const 438 { 439 bool ret = false; 440 441 if ( nullptr != symbol_section->get_data() && 442 index < get_symbols_num() ) { 443 const T* pSym = reinterpret_cast<const T*>( 444 symbol_section->get_data() + 445 index * symbol_section->get_entry_size() ); 446 447 const endianess_convertor& convertor = elf_file.get_convertor(); 448 449 section* string_section = 450 elf_file.sections[get_string_table_index()]; 451 string_section_accessor str_reader( string_section ); 452 const char* pStr = 453 str_reader.get_string( convertor( pSym->st_name ) ); 454 if ( nullptr != pStr ) { 455 name = pStr; 456 } 457 value = convertor( pSym->st_value ); 458 size = convertor( pSym->st_size ); 459 bind = ELF_ST_BIND( pSym->st_info ); 460 type = ELF_ST_TYPE( pSym->st_info ); 461 section_index = convertor( pSym->st_shndx ); 462 other = pSym->st_other; 463 464 ret = true; 465 } 466 467 return ret; 468 } 469 470 //------------------------------------------------------------------------------ 471 template <class T> generic_add_symbol(Elf_Word name,Elf64_Addr value,Elf_Xword size,unsigned char info,unsigned char other,Elf_Half shndx)472 Elf_Word generic_add_symbol( Elf_Word name, 473 Elf64_Addr value, 474 Elf_Xword size, 475 unsigned char info, 476 unsigned char other, 477 Elf_Half shndx ) 478 { 479 const endianess_convertor& convertor = elf_file.get_convertor(); 480 481 T entry; 482 entry.st_name = convertor( name ); 483 entry.st_value = decltype( entry.st_value )( value ); 484 entry.st_value = convertor( entry.st_value ); 485 entry.st_size = decltype( entry.st_size )( size ); 486 entry.st_size = convertor( entry.st_size ); 487 entry.st_info = convertor( info ); 488 entry.st_other = convertor( other ); 489 entry.st_shndx = convertor( shndx ); 490 491 symbol_section->append_data( reinterpret_cast<char*>( &entry ), 492 sizeof( entry ) ); 493 494 Elf_Word nRet = 495 Elf_Word( symbol_section->get_size() / sizeof( entry ) - 1 ); 496 497 return nRet; 498 } 499 500 //------------------------------------------------------------------------------ 501 template <class T> generic_arrange_local_symbols(std::function<void (Elf_Xword first,Elf_Xword second)> func)502 Elf_Xword generic_arrange_local_symbols( 503 std::function<void( Elf_Xword first, Elf_Xword second )> func ) 504 { 505 const endianess_convertor& convertor = elf_file.get_convertor(); 506 507 Elf_Word first_not_local = 508 1; // Skip the first entry. It is always NOTYPE 509 Elf_Xword current = 0; 510 Elf_Xword count = get_symbols_num(); 511 512 while ( true ) { 513 T* p1 = nullptr; 514 T* p2 = nullptr; 515 516 while ( first_not_local < count ) { 517 p1 = const_cast<T*>( 518 generic_get_symbol_ptr<T>( first_not_local ) ); 519 if ( ELF_ST_BIND( convertor( p1->st_info ) ) != STB_LOCAL ) 520 break; 521 ++first_not_local; 522 } 523 524 current = first_not_local + 1; 525 while ( current < count ) { 526 p2 = const_cast<T*>( generic_get_symbol_ptr<T>( current ) ); 527 if ( ELF_ST_BIND( convertor( p2->st_info ) ) == STB_LOCAL ) 528 break; 529 ++current; 530 } 531 532 if ( first_not_local < count && current < count ) { 533 if ( func ) 534 func( first_not_local, current ); 535 536 std::swap( *p1, *p2 ); 537 } 538 else { 539 // Update 'info' field of the section 540 symbol_section->set_info( first_not_local ); 541 break; 542 } 543 } 544 545 return first_not_local; 546 } 547 548 //------------------------------------------------------------------------------ 549 private: 550 const elfio& elf_file; 551 S* symbol_section; 552 Elf_Half hash_section_index{ 0 }; 553 const section* hash_section{ nullptr }; 554 }; 555 556 using symbol_section_accessor = symbol_section_accessor_template<section>; 557 using const_symbol_section_accessor = 558 symbol_section_accessor_template<const section>; 559 560 } // namespace ELFIO 561 562 #endif // ELFIO_SYMBOLS_HPP 563