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_HPP 24 #define ELFIO_HPP 25 26 #include <string> 27 #include <iostream> 28 #include <fstream> 29 #include <functional> 30 #include <algorithm> 31 #include <array> 32 #include <vector> 33 #include <deque> 34 #include <memory> 35 36 #include <elfio/elf_types.hpp> 37 #include <elfio/elfio_version.hpp> 38 #include <elfio/elfio_utils.hpp> 39 #include <elfio/elfio_header.hpp> 40 #include <elfio/elfio_section.hpp> 41 #include <elfio/elfio_segment.hpp> 42 #include <elfio/elfio_strings.hpp> 43 44 #define ELFIO_HEADER_ACCESS_GET( TYPE, FNAME ) \ 45 TYPE get_##FNAME() const noexcept \ 46 { \ 47 return header ? ( header->get_##FNAME() ) : 0; \ 48 } 49 50 #define ELFIO_HEADER_ACCESS_GET_SET( TYPE, FNAME ) \ 51 TYPE get_##FNAME() const noexcept \ 52 { \ 53 return header ? ( header->get_##FNAME() ) : 0; \ 54 } \ 55 void set_##FNAME( TYPE val ) noexcept \ 56 { \ 57 if ( header ) { \ 58 header->set_##FNAME( val ); \ 59 } \ 60 } 61 62 namespace ELFIO { 63 64 //------------------------------------------------------------------------------ 65 class elfio 66 { 67 public: 68 //------------------------------------------------------------------------------ elfio()69 elfio() noexcept : sections( this ), segments( this ) 70 { 71 create( ELFCLASS32, ELFDATA2LSB ); 72 } 73 elfio(compression_interface * compression)74 explicit elfio( compression_interface* compression ) noexcept 75 : sections( this ), segments( this ), 76 compression( std::shared_ptr<compression_interface>( compression ) ) 77 { 78 elfio(); 79 } 80 elfio(elfio && other)81 elfio( elfio&& other ) noexcept 82 : sections( this ), segments( this ), 83 current_file_pos( other.current_file_pos ) 84 { 85 header = std::move( other.header ); 86 sections_ = std::move( other.sections_ ); 87 segments_ = std::move( other.segments_ ); 88 convertor = std::move( other.convertor ); 89 addr_translator = std::move( other.addr_translator ); 90 compression = std::move( other.compression ); 91 92 other.header = nullptr; 93 other.sections_.clear(); 94 other.segments_.clear(); 95 other.compression = nullptr; 96 } 97 operator =(elfio && other)98 elfio& operator=( elfio&& other ) noexcept 99 { 100 if ( this != &other ) { 101 header = std::move( other.header ); 102 sections_ = std::move( other.sections_ ); 103 segments_ = std::move( other.segments_ ); 104 convertor = std::move( other.convertor ); 105 addr_translator = std::move( other.addr_translator ); 106 current_file_pos = other.current_file_pos; 107 compression = std::move( other.compression ); 108 109 other.current_file_pos = 0; 110 other.header = nullptr; 111 other.compression = nullptr; 112 other.sections_.clear(); 113 other.segments_.clear(); 114 } 115 return *this; 116 } 117 118 //------------------------------------------------------------------------------ 119 // clang-format off 120 elfio( const elfio& ) = delete; 121 elfio& operator=( const elfio& ) = delete; 122 ~elfio() = default; 123 // clang-format on 124 125 //------------------------------------------------------------------------------ create(unsigned char file_class,unsigned char encoding)126 void create( unsigned char file_class, unsigned char encoding ) noexcept 127 { 128 sections_.clear(); 129 segments_.clear(); 130 convertor.setup( encoding ); 131 header = create_header( file_class, encoding ); 132 create_mandatory_sections(); 133 } 134 set_address_translation(std::vector<address_translation> & addr_trans)135 void set_address_translation( 136 std::vector<address_translation>& addr_trans ) noexcept 137 { 138 addr_translator.set_address_translation( addr_trans ); 139 } 140 141 //------------------------------------------------------------------------------ load(const std::string & file_name,bool is_lazy=false)142 bool load( const std::string& file_name, bool is_lazy = false ) noexcept 143 { 144 pstream = std::make_unique<std::ifstream>(); 145 pstream->open( file_name.c_str(), std::ios::in | std::ios::binary ); 146 if ( pstream == nullptr || !*pstream ) { 147 return false; 148 } 149 150 bool ret = load( *pstream, is_lazy ); 151 152 if ( !is_lazy ) { 153 pstream.release(); 154 } 155 156 return ret; 157 } 158 159 //------------------------------------------------------------------------------ load(std::istream & stream,bool is_lazy=false)160 bool load( std::istream& stream, bool is_lazy = false ) noexcept 161 { 162 sections_.clear(); 163 segments_.clear(); 164 165 std::array<char, EI_NIDENT> e_ident = { 0 }; 166 // Read ELF file signature 167 stream.seekg( addr_translator[0] ); 168 stream.read( e_ident.data(), sizeof( e_ident ) ); 169 170 // Is it ELF file? 171 if ( stream.gcount() != sizeof( e_ident ) || 172 e_ident[EI_MAG0] != ELFMAG0 || e_ident[EI_MAG1] != ELFMAG1 || 173 e_ident[EI_MAG2] != ELFMAG2 || e_ident[EI_MAG3] != ELFMAG3 ) { 174 return false; 175 } 176 177 if ( ( e_ident[EI_CLASS] != ELFCLASS64 ) && 178 ( e_ident[EI_CLASS] != ELFCLASS32 ) ) { 179 return false; 180 } 181 182 if ( ( e_ident[EI_DATA] != ELFDATA2LSB ) && 183 ( e_ident[EI_DATA] != ELFDATA2MSB ) ) { 184 return false; 185 } 186 187 convertor.setup( e_ident[EI_DATA] ); 188 header = create_header( e_ident[EI_CLASS], e_ident[EI_DATA] ); 189 if ( nullptr == header ) { 190 return false; 191 } 192 if ( !header->load( stream ) ) { 193 return false; 194 } 195 196 load_sections( stream, is_lazy ); 197 bool is_still_good = load_segments( stream, is_lazy ); 198 return is_still_good; 199 } 200 201 //------------------------------------------------------------------------------ save(const std::string & file_name)202 bool save( const std::string& file_name ) noexcept 203 { 204 std::ofstream stream; 205 stream.open( file_name.c_str(), std::ios::out | std::ios::binary ); 206 if ( !stream ) { 207 return false; 208 } 209 210 return save( stream ); 211 } 212 213 //------------------------------------------------------------------------------ save(std::ostream & stream)214 bool save( std::ostream& stream ) noexcept 215 { 216 if ( !stream || header == nullptr ) { 217 return false; 218 } 219 220 // Define layout specific header fields 221 // The position of the segment table is fixed after the header. 222 // The position of the section table is variable and needs to be fixed 223 // before saving. 224 header->set_segments_num( segments.size() ); 225 header->set_segments_offset( 226 segments.size() > 0 ? header->get_header_size() : 0 ); 227 header->set_sections_num( sections.size() ); 228 header->set_sections_offset( 0 ); 229 230 // Layout the first section right after the segment table 231 current_file_pos = 232 header->get_header_size() + 233 header->get_segment_entry_size() * 234 static_cast<Elf_Xword>( header->get_segments_num() ); 235 236 calc_segment_alignment(); 237 238 bool is_still_good = layout_segments_and_their_sections(); 239 is_still_good = is_still_good && layout_sections_without_segments(); 240 is_still_good = is_still_good && layout_section_table(); 241 242 is_still_good = is_still_good && save_header( stream ); 243 is_still_good = is_still_good && save_sections( stream ); 244 is_still_good = is_still_good && save_segments( stream ); 245 246 return is_still_good; 247 } 248 249 //------------------------------------------------------------------------------ 250 // ELF header access functions 251 ELFIO_HEADER_ACCESS_GET( unsigned char, class ); 252 ELFIO_HEADER_ACCESS_GET( unsigned char, elf_version ); 253 ELFIO_HEADER_ACCESS_GET( unsigned char, encoding ); 254 ELFIO_HEADER_ACCESS_GET( Elf_Word, version ); 255 ELFIO_HEADER_ACCESS_GET( Elf_Half, header_size ); 256 ELFIO_HEADER_ACCESS_GET( Elf_Half, section_entry_size ); 257 ELFIO_HEADER_ACCESS_GET( Elf_Half, segment_entry_size ); 258 259 ELFIO_HEADER_ACCESS_GET_SET( unsigned char, os_abi ); 260 ELFIO_HEADER_ACCESS_GET_SET( unsigned char, abi_version ); 261 ELFIO_HEADER_ACCESS_GET_SET( Elf_Half, type ); 262 ELFIO_HEADER_ACCESS_GET_SET( Elf_Half, machine ); 263 ELFIO_HEADER_ACCESS_GET_SET( Elf_Word, flags ); 264 ELFIO_HEADER_ACCESS_GET_SET( Elf64_Addr, entry ); 265 ELFIO_HEADER_ACCESS_GET_SET( Elf64_Off, sections_offset ); 266 ELFIO_HEADER_ACCESS_GET_SET( Elf64_Off, segments_offset ); 267 ELFIO_HEADER_ACCESS_GET_SET( Elf_Half, section_name_str_index ); 268 269 //------------------------------------------------------------------------------ get_convertor() const270 const endianess_convertor& get_convertor() const noexcept 271 { 272 return convertor; 273 } 274 275 //------------------------------------------------------------------------------ get_default_entry_size(Elf_Word section_type) const276 Elf_Xword get_default_entry_size( Elf_Word section_type ) const noexcept 277 { 278 switch ( section_type ) { 279 case SHT_RELA: 280 if ( header->get_class() == ELFCLASS64 ) { 281 return sizeof( Elf64_Rela ); 282 } 283 else { 284 return sizeof( Elf32_Rela ); 285 } 286 case SHT_REL: 287 if ( header->get_class() == ELFCLASS64 ) { 288 return sizeof( Elf64_Rel ); 289 } 290 else { 291 return sizeof( Elf32_Rel ); 292 } 293 case SHT_SYMTAB: 294 if ( header->get_class() == ELFCLASS64 ) { 295 return sizeof( Elf64_Sym ); 296 } 297 else { 298 return sizeof( Elf32_Sym ); 299 } 300 case SHT_DYNAMIC: 301 if ( header->get_class() == ELFCLASS64 ) { 302 return sizeof( Elf64_Dyn ); 303 } 304 else { 305 return sizeof( Elf32_Dyn ); 306 } 307 default: 308 return 0; 309 } 310 } 311 312 //------------------------------------------------------------------------------ 313 //! returns an empty string if no problems are detected, 314 //! or a string containing an error message if problems are found, 315 //! with one error per line. validate() const316 std::string validate() const noexcept 317 { 318 // clang-format off 319 320 std::string errors; 321 // Check for overlapping sections in the file 322 // This is explicitly forbidden by ELF specification 323 for ( int i = 0; i < sections.size(); ++i) { 324 for ( int j = i+1; j < sections.size(); ++j ) { 325 const section* a = sections[i]; 326 const section* b = sections[j]; 327 if ( ( ( a->get_type() & SHT_NOBITS) == 0 ) 328 && ( ( b->get_type() & SHT_NOBITS) == 0 ) 329 && ( a->get_size() > 0 ) 330 && ( b->get_size() > 0 ) 331 && ( a->get_offset() > 0 ) 332 && ( b->get_offset() > 0 ) 333 && ( is_offset_in_section( a->get_offset(), b ) 334 || is_offset_in_section( a->get_offset()+a->get_size()-1, b ) 335 || is_offset_in_section( b->get_offset(), a ) 336 || is_offset_in_section( b->get_offset()+b->get_size()-1, a ) ) ) { 337 errors += "Sections " + a->get_name() + " and " + b->get_name() + " overlap in file\n"; 338 } 339 } 340 } 341 // clang-format on 342 343 // Check for conflicting section / program header tables, where 344 // the same offset has different vaddresses in section table and 345 // program header table. 346 // This doesn't seem to be explicitly forbidden by ELF specification, 347 // but: 348 // - it doesn't make any sense 349 // - ELFIO relies on this being consistent when writing ELF files, 350 // since offsets are re-calculated from vaddress 351 for ( int h = 0; h < segments.size(); ++h ) { 352 const segment* seg = segments[h]; 353 const section* sec = 354 find_prog_section_for_offset( seg->get_offset() ); 355 if ( seg->get_type() == PT_LOAD && seg->get_file_size() > 0 && 356 sec != nullptr ) { 357 Elf64_Addr sec_addr = 358 get_virtual_addr( seg->get_offset(), sec ); 359 if ( sec_addr != seg->get_virtual_address() ) { 360 errors += "Virtual address of segment " + 361 std::to_string( h ) + " (" + 362 to_hex_string( seg->get_virtual_address() ) + 363 ")" + " conflicts with address of section " + 364 sec->get_name() + " (" + 365 to_hex_string( sec_addr ) + ")" + " at offset " + 366 to_hex_string( seg->get_offset() ) + "\n"; 367 } 368 } 369 } 370 371 // more checks to be added here... 372 373 return errors; 374 } 375 376 private: 377 //------------------------------------------------------------------------------ is_offset_in_section(Elf64_Off offset,const section * sec)378 static bool is_offset_in_section( Elf64_Off offset, 379 const section* sec ) noexcept 380 { 381 return ( offset >= sec->get_offset() ) && 382 ( offset < ( sec->get_offset() + sec->get_size() ) ); 383 } 384 385 //------------------------------------------------------------------------------ get_virtual_addr(Elf64_Off offset,const section * sec)386 static Elf64_Addr get_virtual_addr( Elf64_Off offset, 387 const section* sec ) noexcept 388 { 389 return sec->get_address() + offset - sec->get_offset(); 390 } 391 392 //------------------------------------------------------------------------------ 393 const section* find_prog_section_for_offset(Elf64_Off offset) const394 find_prog_section_for_offset( Elf64_Off offset ) const noexcept 395 { 396 for ( const auto& sec : sections ) { 397 if ( sec->get_type() == SHT_PROGBITS && 398 is_offset_in_section( offset, sec.get() ) ) { 399 return sec.get(); 400 } 401 } 402 return nullptr; 403 } 404 405 //------------------------------------------------------------------------------ create_header(unsigned char file_class,unsigned char encoding)406 std::unique_ptr<elf_header> create_header( unsigned char file_class, 407 unsigned char encoding ) noexcept 408 { 409 std::unique_ptr<elf_header> new_header; 410 411 if ( file_class == ELFCLASS64 ) { 412 new_header = std::unique_ptr<elf_header>( 413 new ( std::nothrow ) elf_header_impl<Elf64_Ehdr>( 414 &convertor, encoding, &addr_translator ) ); 415 } 416 else if ( file_class == ELFCLASS32 ) { 417 new_header = std::unique_ptr<elf_header>( 418 new ( std::nothrow ) elf_header_impl<Elf32_Ehdr>( 419 &convertor, encoding, &addr_translator ) ); 420 } 421 else { 422 return nullptr; 423 } 424 425 return new_header; 426 } 427 428 //------------------------------------------------------------------------------ create_section()429 section* create_section() noexcept 430 { 431 unsigned char file_class = get_class(); 432 433 if ( file_class == ELFCLASS64 ) { 434 sections_.emplace_back( 435 new ( std::nothrow ) section_impl<Elf64_Shdr>( 436 &convertor, &addr_translator, compression ) ); 437 } 438 else if ( file_class == ELFCLASS32 ) { 439 sections_.emplace_back( 440 new ( std::nothrow ) section_impl<Elf32_Shdr>( 441 &convertor, &addr_translator, compression ) ); 442 } 443 else { 444 sections_.pop_back(); 445 return nullptr; 446 } 447 448 section* new_section = sections_.back().get(); 449 new_section->set_index( static_cast<Elf_Half>( sections_.size() - 1 ) ); 450 451 return new_section; 452 } 453 454 //------------------------------------------------------------------------------ create_segment()455 segment* create_segment() noexcept 456 { 457 unsigned char file_class = header->get_class(); 458 459 if ( file_class == ELFCLASS64 ) { 460 segments_.emplace_back( 461 new ( std::nothrow ) 462 segment_impl<Elf64_Phdr>( &convertor, &addr_translator ) ); 463 } 464 else if ( file_class == ELFCLASS32 ) { 465 segments_.emplace_back( 466 new ( std::nothrow ) 467 segment_impl<Elf32_Phdr>( &convertor, &addr_translator ) ); 468 } 469 else { 470 segments_.pop_back(); 471 return nullptr; 472 } 473 474 segment* new_segment = segments_.back().get(); 475 new_segment->set_index( static_cast<Elf_Half>( segments_.size() - 1 ) ); 476 477 return new_segment; 478 } 479 480 //------------------------------------------------------------------------------ create_mandatory_sections()481 void create_mandatory_sections() noexcept 482 { 483 // Create null section without calling to 'add_section' as no string 484 // section containing section names exists yet 485 section* sec0 = create_section(); 486 sec0->set_index( 0 ); 487 sec0->set_name( "" ); 488 sec0->set_name_string_offset( 0 ); 489 490 set_section_name_str_index( 1 ); 491 section* shstrtab = sections.add( ".shstrtab" ); 492 shstrtab->set_type( SHT_STRTAB ); 493 shstrtab->set_addr_align( 1 ); 494 } 495 496 //------------------------------------------------------------------------------ load_sections(std::istream & stream,bool is_lazy)497 bool load_sections( std::istream& stream, bool is_lazy ) noexcept 498 { 499 unsigned char file_class = header->get_class(); 500 Elf_Half entry_size = header->get_section_entry_size(); 501 Elf_Half num = header->get_sections_num(); 502 Elf64_Off offset = header->get_sections_offset(); 503 504 if ( ( num != 0 && file_class == ELFCLASS64 && 505 entry_size < sizeof( Elf64_Shdr ) ) || 506 ( num != 0 && file_class == ELFCLASS32 && 507 entry_size < sizeof( Elf32_Shdr ) ) ) { 508 return false; 509 } 510 511 for ( Elf_Half i = 0; i < num; ++i ) { 512 section* sec = create_section(); 513 sec->load( stream, 514 static_cast<std::streamoff>( offset ) + 515 static_cast<std::streampos>( i ) * entry_size, 516 is_lazy ); 517 // To mark that the section is not permitted to reassign address 518 // during layout calculation 519 sec->set_address( sec->get_address() ); 520 } 521 522 Elf_Half shstrndx = get_section_name_str_index(); 523 524 if ( SHN_UNDEF != shstrndx ) { 525 string_section_accessor str_reader( sections[shstrndx] ); 526 for ( Elf_Half i = 0; i < num; ++i ) { 527 Elf_Word section_offset = sections[i]->get_name_string_offset(); 528 const char* p = str_reader.get_string( section_offset ); 529 if ( p != nullptr ) { 530 sections[i]->set_name( p ); 531 } 532 } 533 } 534 535 return true; 536 } 537 538 //------------------------------------------------------------------------------ 539 //! Checks whether the addresses of the section entirely fall within the given segment. 540 //! It doesn't matter if the addresses are memory addresses, or file offsets, 541 //! they just need to be in the same address space is_sect_in_seg(Elf64_Off sect_begin,Elf_Xword sect_size,Elf64_Off seg_begin,Elf64_Off seg_end)542 static bool is_sect_in_seg( Elf64_Off sect_begin, 543 Elf_Xword sect_size, 544 Elf64_Off seg_begin, 545 Elf64_Off seg_end ) noexcept 546 { 547 return ( seg_begin <= sect_begin ) && 548 ( sect_begin + sect_size <= seg_end ) && 549 ( sect_begin < 550 seg_end ); // this is important criteria when sect_size == 0 551 // Example: seg_begin=10, seg_end=12 (-> covering the bytes 10 and 11) 552 // sect_begin=12, sect_size=0 -> shall return false! 553 } 554 555 //------------------------------------------------------------------------------ load_segments(std::istream & stream,bool is_lazy)556 bool load_segments( std::istream& stream, bool is_lazy ) noexcept 557 { 558 unsigned char file_class = header->get_class(); 559 Elf_Half entry_size = header->get_segment_entry_size(); 560 Elf_Half num = header->get_segments_num(); 561 Elf64_Off offset = header->get_segments_offset(); 562 563 if ( ( num != 0 && file_class == ELFCLASS64 && 564 entry_size < sizeof( Elf64_Phdr ) ) || 565 ( num != 0 && file_class == ELFCLASS32 && 566 entry_size < sizeof( Elf32_Phdr ) ) ) { 567 return false; 568 } 569 570 for ( Elf_Half i = 0; i < num; ++i ) { 571 if ( file_class == ELFCLASS64 ) { 572 segments_.emplace_back( 573 new ( std::nothrow ) segment_impl<Elf64_Phdr>( 574 &convertor, &addr_translator ) ); 575 } 576 else if ( file_class == ELFCLASS32 ) { 577 segments_.emplace_back( 578 new ( std::nothrow ) segment_impl<Elf32_Phdr>( 579 &convertor, &addr_translator ) ); 580 } 581 else { 582 segments_.pop_back(); 583 return false; 584 } 585 586 segment* seg = segments_.back().get(); 587 588 if ( !seg->load( stream, 589 static_cast<std::streamoff>( offset ) + 590 static_cast<std::streampos>( i ) * entry_size, 591 is_lazy ) || 592 stream.fail() ) { 593 segments_.pop_back(); 594 return false; 595 } 596 597 seg->set_index( i ); 598 599 // Add sections to the segments (similar to readelfs algorithm) 600 Elf64_Off segBaseOffset = seg->get_offset(); 601 Elf64_Off segEndOffset = segBaseOffset + seg->get_file_size(); 602 Elf64_Off segVBaseAddr = seg->get_virtual_address(); 603 Elf64_Off segVEndAddr = segVBaseAddr + seg->get_memory_size(); 604 for ( const auto& psec : sections ) { 605 // SHF_ALLOC sections are matched based on the virtual address 606 // otherwise the file offset is matched 607 if ( ( ( psec->get_flags() & SHF_ALLOC ) == SHF_ALLOC ) 608 ? is_sect_in_seg( psec->get_address(), 609 psec->get_size(), segVBaseAddr, 610 segVEndAddr ) 611 : is_sect_in_seg( psec->get_offset(), psec->get_size(), 612 segBaseOffset, segEndOffset ) ) { 613 // Alignment of segment shall not be updated, to preserve original value 614 // It will be re-calculated on saving. 615 seg->add_section_index( psec->get_index(), 0 ); 616 } 617 } 618 } 619 620 return true; 621 } 622 623 //------------------------------------------------------------------------------ save_header(std::ostream & stream) const624 bool save_header( std::ostream& stream ) const noexcept 625 { 626 return header->save( stream ); 627 } 628 629 //------------------------------------------------------------------------------ save_sections(std::ostream & stream) const630 bool save_sections( std::ostream& stream ) const noexcept 631 { 632 for ( const auto& sec : sections_ ) { 633 std::streampos headerPosition = 634 static_cast<std::streamoff>( header->get_sections_offset() ) + 635 static_cast<std::streampos>( 636 header->get_section_entry_size() ) * 637 sec->get_index(); 638 639 sec->save( stream, headerPosition, sec->get_offset() ); 640 } 641 return true; 642 } 643 644 //------------------------------------------------------------------------------ save_segments(std::ostream & stream) const645 bool save_segments( std::ostream& stream ) const noexcept 646 { 647 for ( const auto& seg : segments_ ) { 648 std::streampos headerPosition = 649 static_cast<std::streamoff>( header->get_segments_offset() ) + 650 static_cast<std::streampos>( 651 header->get_segment_entry_size() ) * 652 seg->get_index(); 653 654 seg->save( stream, headerPosition, seg->get_offset() ); 655 } 656 return true; 657 } 658 659 //------------------------------------------------------------------------------ is_section_without_segment(unsigned int section_index) const660 bool is_section_without_segment( unsigned int section_index ) const noexcept 661 { 662 bool found = false; 663 664 for ( unsigned int j = 0; !found && ( j < segments.size() ); ++j ) { 665 for ( Elf_Half k = 0; 666 !found && ( k < segments[j]->get_sections_num() ); ++k ) { 667 found = segments[j]->get_section_index_at( k ) == section_index; 668 } 669 } 670 671 return !found; 672 } 673 674 //------------------------------------------------------------------------------ is_subsequence_of(const segment * seg1,const segment * seg2)675 static bool is_subsequence_of( const segment* seg1, 676 const segment* seg2 ) noexcept 677 { 678 // Return 'true' if sections of seg1 are a subset of sections in seg2 679 const std::vector<Elf_Half>& sections1 = seg1->get_sections(); 680 const std::vector<Elf_Half>& sections2 = seg2->get_sections(); 681 682 bool found = false; 683 if ( sections1.size() < sections2.size() ) { 684 found = std::includes( sections2.begin(), sections2.end(), 685 sections1.begin(), sections1.end() ); 686 } 687 688 return found; 689 } 690 691 //------------------------------------------------------------------------------ get_ordered_segments() const692 std::vector<segment*> get_ordered_segments() const noexcept 693 { 694 std::vector<segment*> res; 695 std::deque<segment*> worklist; 696 697 res.reserve( segments.size() ); 698 for ( const auto& seg : segments ) { 699 worklist.emplace_back( seg.get() ); 700 } 701 702 // Bring the segments which start at address 0 to the front 703 size_t nextSlot = 0; 704 for ( size_t i = 0; i < worklist.size(); ++i ) { 705 if ( i != nextSlot && worklist[i]->is_offset_initialized() && 706 worklist[i]->get_offset() == 0 ) { 707 if ( worklist[nextSlot]->get_offset() == 0 ) { 708 ++nextSlot; 709 } 710 std::swap( worklist[i], worklist[nextSlot] ); 711 ++nextSlot; 712 } 713 } 714 715 while ( !worklist.empty() ) { 716 segment* seg = worklist.front(); 717 worklist.pop_front(); 718 719 size_t i = 0; 720 for ( ; i < worklist.size(); ++i ) { 721 if ( is_subsequence_of( seg, worklist[i] ) ) { 722 break; 723 } 724 } 725 726 if ( i < worklist.size() ) { 727 worklist.emplace_back( seg ); 728 } 729 else { 730 res.emplace_back( seg ); 731 } 732 } 733 734 return res; 735 } 736 737 //------------------------------------------------------------------------------ layout_sections_without_segments()738 bool layout_sections_without_segments() noexcept 739 { 740 for ( unsigned int i = 0; i < sections_.size(); ++i ) { 741 if ( is_section_without_segment( i ) ) { 742 const auto& sec = sections_[i]; 743 744 Elf_Xword section_align = sec->get_addr_align(); 745 if ( section_align > 1 && 746 current_file_pos % section_align != 0 ) { 747 current_file_pos += 748 section_align - current_file_pos % section_align; 749 } 750 751 if ( 0 != sec->get_index() ) { 752 sec->set_offset( current_file_pos ); 753 } 754 755 if ( SHT_NOBITS != sec->get_type() && 756 SHT_NULL != sec->get_type() ) { 757 current_file_pos += sec->get_size(); 758 } 759 } 760 } 761 762 return true; 763 } 764 765 //------------------------------------------------------------------------------ calc_segment_alignment() const766 void calc_segment_alignment() const noexcept 767 { 768 for ( const auto& seg : segments_ ) { 769 for ( Elf_Half i = 0; i < seg->get_sections_num(); ++i ) { 770 const auto& sect = sections_[seg->get_section_index_at( i )]; 771 if ( sect->get_addr_align() > seg->get_align() ) { 772 seg->set_align( sect->get_addr_align() ); 773 } 774 } 775 } 776 } 777 778 //------------------------------------------------------------------------------ layout_segments_and_their_sections()779 bool layout_segments_and_their_sections() noexcept 780 { 781 std::vector<segment*> worklist; 782 std::vector<bool> section_generated( sections.size(), false ); 783 784 // Get segments in a order in where segments which contain a 785 // sub sequence of other segments are located at the end 786 worklist = get_ordered_segments(); 787 788 for ( auto* seg : worklist ) { 789 Elf_Xword segment_memory = 0; 790 Elf_Xword segment_filesize = 0; 791 Elf_Xword seg_start_pos = current_file_pos; 792 // Special case: PHDR segment 793 // This segment contains the program headers but no sections 794 if ( seg->get_type() == PT_PHDR && seg->get_sections_num() == 0 ) { 795 seg_start_pos = header->get_segments_offset(); 796 segment_memory = segment_filesize = 797 header->get_segment_entry_size() * 798 static_cast<Elf_Xword>( header->get_segments_num() ); 799 } 800 // Special case: 801 else if ( seg->is_offset_initialized() && seg->get_offset() == 0 ) { 802 seg_start_pos = 0; 803 if ( seg->get_sections_num() > 0 ) { 804 segment_memory = segment_filesize = current_file_pos; 805 } 806 } 807 // New segments with not generated sections 808 // have to be aligned 809 else if ( seg->get_sections_num() > 0 && 810 !section_generated[seg->get_section_index_at( 0 )] ) { 811 Elf_Xword align = seg->get_align() > 0 ? seg->get_align() : 1; 812 Elf64_Off cur_page_alignment = current_file_pos % align; 813 Elf64_Off req_page_alignment = 814 seg->get_virtual_address() % align; 815 Elf64_Off error = req_page_alignment - cur_page_alignment; 816 817 current_file_pos += ( seg->get_align() + error ) % align; 818 seg_start_pos = current_file_pos; 819 } 820 else if ( seg->get_sections_num() > 0 ) { 821 seg_start_pos = 822 sections[seg->get_section_index_at( 0 )]->get_offset(); 823 } 824 825 // Write segment's data 826 if ( !write_segment_data( seg, section_generated, segment_memory, 827 segment_filesize, seg_start_pos ) ) { 828 return false; 829 } 830 831 seg->set_file_size( segment_filesize ); 832 833 // If we already have a memory size from loading an elf file (value > 0), 834 // it must not shrink! 835 // Memory size may be bigger than file size and it is the loader's job to do something 836 // with the surplus bytes in memory, like initializing them with a defined value. 837 if ( seg->get_memory_size() < segment_memory ) { 838 seg->set_memory_size( segment_memory ); 839 } 840 841 seg->set_offset( seg_start_pos ); 842 } 843 844 return true; 845 } 846 847 //------------------------------------------------------------------------------ layout_section_table()848 bool layout_section_table() noexcept 849 { 850 // Simply place the section table at the end for now 851 Elf64_Off alignmentError = current_file_pos % 4; 852 current_file_pos += ( 4 - alignmentError ) % 4; 853 header->set_sections_offset( current_file_pos ); 854 return true; 855 } 856 857 //------------------------------------------------------------------------------ write_segment_data(const segment * seg,std::vector<bool> & section_generated,Elf_Xword & segment_memory,Elf_Xword & segment_filesize,const Elf_Xword & seg_start_pos)858 bool write_segment_data( const segment* seg, 859 std::vector<bool>& section_generated, 860 Elf_Xword& segment_memory, 861 Elf_Xword& segment_filesize, 862 const Elf_Xword& seg_start_pos ) noexcept 863 { 864 for ( Elf_Half j = 0; j < seg->get_sections_num(); ++j ) { 865 Elf_Half index = seg->get_section_index_at( j ); 866 867 section* sec = sections[index]; 868 869 // The NULL section is always generated 870 if ( SHT_NULL == sec->get_type() ) { 871 section_generated[index] = true; 872 continue; 873 } 874 875 Elf_Xword section_align = 0; 876 // Fix up the alignment 877 if ( !section_generated[index] && sec->is_address_initialized() && 878 SHT_NOBITS != sec->get_type() && SHT_NULL != sec->get_type() && 879 0 != sec->get_size() ) { 880 // Align the sections based on the virtual addresses 881 // when possible (this is what matters for execution) 882 Elf64_Off req_offset = 883 sec->get_address() - seg->get_virtual_address(); 884 Elf64_Off cur_offset = current_file_pos - seg_start_pos; 885 if ( req_offset < cur_offset ) { 886 // something has gone awfully wrong, abort! 887 // section_align would turn out negative, seeking backwards and overwriting previous data 888 return false; 889 } 890 section_align = req_offset - cur_offset; 891 } 892 else if ( !section_generated[index] && 893 !sec->is_address_initialized() ) { 894 // If no address has been specified then only the section 895 // alignment constraint has to be matched 896 Elf_Xword align = sec->get_addr_align(); 897 if ( align == 0 ) { 898 align = 1; 899 } 900 Elf64_Off error = current_file_pos % align; 901 section_align = ( align - error ) % align; 902 } 903 else if ( section_generated[index] ) { 904 // Alignment for already generated sections 905 section_align = 906 sec->get_offset() - seg_start_pos - segment_filesize; 907 } 908 909 // Determine the segment file and memory sizes 910 // Special case .tbss section (NOBITS) in non TLS segment 911 if ( ( ( sec->get_flags() & SHF_ALLOC ) == SHF_ALLOC ) && 912 !( ( ( sec->get_flags() & SHF_TLS ) == SHF_TLS ) && 913 ( seg->get_type() != PT_TLS ) && 914 ( SHT_NOBITS == sec->get_type() ) ) ) { 915 segment_memory += sec->get_size() + section_align; 916 } 917 918 if ( SHT_NOBITS != sec->get_type() ) { 919 segment_filesize += sec->get_size() + section_align; 920 } 921 922 // Nothing to be done when generating nested segments 923 if ( section_generated[index] ) { 924 continue; 925 } 926 927 current_file_pos += section_align; 928 929 // Set the section addresses when missing 930 if ( !sec->is_address_initialized() ) { 931 sec->set_address( seg->get_virtual_address() + 932 current_file_pos - seg_start_pos ); 933 } 934 935 if ( 0 != sec->get_index() ) { 936 sec->set_offset( current_file_pos ); 937 } 938 939 if ( SHT_NOBITS != sec->get_type() ) { 940 current_file_pos += sec->get_size(); 941 } 942 943 section_generated[index] = true; 944 } 945 946 return true; 947 } 948 949 //------------------------------------------------------------------------------ 950 public: 951 friend class Sections; 952 class Sections 953 { 954 public: 955 //------------------------------------------------------------------------------ Sections(elfio * parent)956 explicit Sections( elfio* parent ) : parent( parent ) {} 957 958 //------------------------------------------------------------------------------ size() const959 Elf_Half size() const noexcept 960 { 961 return static_cast<Elf_Half>( parent->sections_.size() ); 962 } 963 964 //------------------------------------------------------------------------------ operator [](unsigned int index) const965 section* operator[]( unsigned int index ) const noexcept 966 { 967 section* sec = nullptr; 968 969 if ( index < parent->sections_.size() ) { 970 sec = parent->sections_[index].get(); 971 } 972 973 return sec; 974 } 975 976 //------------------------------------------------------------------------------ operator [](const std::string & name) const977 section* operator[]( const std::string& name ) const noexcept 978 { 979 section* sec = nullptr; 980 981 for ( const auto& it : parent->sections_ ) { 982 if ( it->get_name() == name ) { 983 sec = it.get(); 984 break; 985 } 986 } 987 988 return sec; 989 } 990 991 //------------------------------------------------------------------------------ add(const std::string & name) const992 section* add( const std::string& name ) const noexcept 993 { 994 section* new_section = parent->create_section(); 995 new_section->set_name( name ); 996 997 Elf_Half str_index = parent->get_section_name_str_index(); 998 section* string_table( parent->sections_[str_index].get() ); 999 string_section_accessor str_writer( string_table ); 1000 Elf_Word pos = str_writer.add_string( name ); 1001 new_section->set_name_string_offset( pos ); 1002 1003 return new_section; 1004 } 1005 1006 //------------------------------------------------------------------------------ begin()1007 std::vector<std::unique_ptr<section>>::iterator begin() noexcept 1008 { 1009 return parent->sections_.begin(); 1010 } 1011 1012 //------------------------------------------------------------------------------ end()1013 std::vector<std::unique_ptr<section>>::iterator end() noexcept 1014 { 1015 return parent->sections_.end(); 1016 } 1017 1018 //------------------------------------------------------------------------------ 1019 std::vector<std::unique_ptr<section>>::const_iterator begin() const1020 begin() const noexcept 1021 { 1022 return parent->sections_.cbegin(); 1023 } 1024 1025 //------------------------------------------------------------------------------ 1026 std::vector<std::unique_ptr<section>>::const_iterator end() const1027 end() const noexcept 1028 { 1029 return parent->sections_.cend(); 1030 } 1031 1032 //------------------------------------------------------------------------------ 1033 private: 1034 elfio* parent; 1035 }; 1036 Sections sections; 1037 1038 //------------------------------------------------------------------------------ 1039 friend class Segments; 1040 class Segments 1041 { 1042 public: 1043 //------------------------------------------------------------------------------ Segments(elfio * parent)1044 explicit Segments( elfio* parent ) : parent( parent ) {} 1045 1046 //------------------------------------------------------------------------------ size() const1047 Elf_Half size() const noexcept 1048 { 1049 return static_cast<Elf_Half>( parent->segments_.size() ); 1050 } 1051 1052 //------------------------------------------------------------------------------ operator [](unsigned int index) const1053 segment* operator[]( unsigned int index ) const noexcept 1054 { 1055 return parent->segments_[index].get(); 1056 } 1057 1058 //------------------------------------------------------------------------------ add()1059 segment* add() noexcept { return parent->create_segment(); } 1060 1061 //------------------------------------------------------------------------------ begin()1062 std::vector<std::unique_ptr<segment>>::iterator begin() noexcept 1063 { 1064 return parent->segments_.begin(); 1065 } 1066 1067 //------------------------------------------------------------------------------ end()1068 std::vector<std::unique_ptr<segment>>::iterator end() noexcept 1069 { 1070 return parent->segments_.end(); 1071 } 1072 1073 //------------------------------------------------------------------------------ 1074 std::vector<std::unique_ptr<segment>>::const_iterator begin() const1075 begin() const noexcept 1076 { 1077 return parent->segments_.cbegin(); 1078 } 1079 1080 //------------------------------------------------------------------------------ 1081 std::vector<std::unique_ptr<segment>>::const_iterator end() const1082 end() const noexcept 1083 { 1084 return parent->segments_.cend(); 1085 } 1086 1087 //------------------------------------------------------------------------------ 1088 private: 1089 elfio* parent; 1090 }; 1091 Segments segments; 1092 1093 //------------------------------------------------------------------------------ 1094 private: 1095 std::unique_ptr<std::ifstream> pstream = nullptr; 1096 std::unique_ptr<elf_header> header = nullptr; 1097 std::vector<std::unique_ptr<section>> sections_; 1098 std::vector<std::unique_ptr<segment>> segments_; 1099 endianess_convertor convertor; 1100 address_translator addr_translator; 1101 std::shared_ptr<compression_interface> compression = nullptr; 1102 1103 Elf_Xword current_file_pos = 0; 1104 }; 1105 1106 } // namespace ELFIO 1107 1108 #include <elfio/elfio_symbols.hpp> 1109 #include <elfio/elfio_note.hpp> 1110 #include <elfio/elfio_relocation.hpp> 1111 #include <elfio/elfio_dynamic.hpp> 1112 #include <elfio/elfio_array.hpp> 1113 #include <elfio/elfio_modinfo.hpp> 1114 #include <elfio/elfio_versym.hpp> 1115 1116 #endif // ELFIO_HPP 1117