From 8367e0e32cace0b9a318caa8683916568806b3ff Mon Sep 17 00:00:00 2001 From: Maschell Date: Wed, 4 Jan 2023 14:33:56 +0100 Subject: [PATCH] Remove all save functions from ELFIO. We don't need them anyway --- source/elfio/elfio.hpp | 493 --------------------------------- source/elfio/elfio_header.hpp | 11 - source/elfio/elfio_section.hpp | 47 +--- source/elfio/elfio_segment.hpp | 14 - 4 files changed, 1 insertion(+), 564 deletions(-) diff --git a/source/elfio/elfio.hpp b/source/elfio/elfio.hpp index 343b41b..849dd2a 100644 --- a/source/elfio/elfio.hpp +++ b/source/elfio/elfio.hpp @@ -197,54 +197,6 @@ class elfio return is_still_good; } - //------------------------------------------------------------------------------ - bool save( const std::string& file_name ) - { - std::ofstream stream; - stream.open( file_name.c_str(), std::ios::out | std::ios::binary ); - if ( !stream ) { - return false; - } - - return save( stream ); - } - - //------------------------------------------------------------------------------ - bool save( std::ostream& stream ) - { - if ( !stream || header == nullptr ) { - return false; - } - - // Define layout specific header fields - // The position of the segment table is fixed after the header. - // The position of the section table is variable and needs to be fixed - // before saving. - header->set_segments_num( segments.size() ); - header->set_segments_offset( - segments.size() > 0 ? header->get_header_size() : 0 ); - header->set_sections_num( sections.size() ); - header->set_sections_offset( 0 ); - - // Layout the first section right after the segment table - current_file_pos = - header->get_header_size() + - header->get_segment_entry_size() * - static_cast( header->get_segments_num() ); - - calc_segment_alignment(); - - bool is_still_good = layout_segments_and_their_sections(); - is_still_good = is_still_good && layout_sections_without_segments(); - is_still_good = is_still_good && layout_section_table(); - - is_still_good = is_still_good && save_header( stream ); - is_still_good = is_still_good && save_sections( stream ); - is_still_good = is_still_good && save_segments( stream ); - - return is_still_good; - } - //------------------------------------------------------------------------------ // ELF header access functions ELFIO_HEADER_ACCESS_GET( unsigned char, class ); @@ -268,107 +220,6 @@ class elfio //------------------------------------------------------------------------------ const endianess_convertor& get_convertor() const { return convertor; } - //------------------------------------------------------------------------------ - Elf_Xword get_default_entry_size( Elf_Word section_type ) const - { - switch ( section_type ) { - case SHT_RELA: - if ( header->get_class() == ELFCLASS64 ) { - return sizeof( Elf64_Rela ); - } - else { - return sizeof( Elf32_Rela ); - } - case SHT_REL: - if ( header->get_class() == ELFCLASS64 ) { - return sizeof( Elf64_Rel ); - } - else { - return sizeof( Elf32_Rel ); - } - case SHT_SYMTAB: - if ( header->get_class() == ELFCLASS64 ) { - return sizeof( Elf64_Sym ); - } - else { - return sizeof( Elf32_Sym ); - } - case SHT_DYNAMIC: - if ( header->get_class() == ELFCLASS64 ) { - return sizeof( Elf64_Dyn ); - } - else { - return sizeof( Elf32_Dyn ); - } - default: - return 0; - } - } - - //------------------------------------------------------------------------------ - //! returns an empty string if no problems are detected, - //! or a string containing an error message if problems are found, - //! with one error per line. - std::string validate() const - { - // clang-format off - - std::string errors; - // Check for overlapping sections in the file - // This is explicitly forbidden by ELF specification - for ( int i = 0; i < sections.size(); ++i) { - for ( int j = i+1; j < sections.size(); ++j ) { - const section* a = sections[i]; - const section* b = sections[j]; - if ( ( ( a->get_type() & SHT_NOBITS) == 0 ) - && ( ( b->get_type() & SHT_NOBITS) == 0 ) - && ( a->get_size() > 0 ) - && ( b->get_size() > 0 ) - && ( a->get_offset() > 0 ) - && ( b->get_offset() > 0 ) - && ( is_offset_in_section( a->get_offset(), b ) - || is_offset_in_section( a->get_offset()+a->get_size()-1, b ) - || is_offset_in_section( b->get_offset(), a ) - || is_offset_in_section( b->get_offset()+b->get_size()-1, a ) ) ) { - errors += "Sections " + a->get_name() + " and " + b->get_name() + " overlap in file\n"; - } - } - } - // clang-format on - - // Check for conflicting section / program header tables, where - // the same offset has different vaddresses in section table and - // program header table. - // This doesn't seem to be explicitly forbidden by ELF specification, - // but: - // - it doesn't make any sense - // - ELFIO relies on this being consistent when writing ELF files, - // since offsets are re-calculated from vaddress - for ( int h = 0; h < segments.size(); ++h ) { - const segment* seg = segments[h]; - const section* sec = - find_prog_section_for_offset( seg->get_offset() ); - if ( seg->get_type() == PT_LOAD && seg->get_file_size() > 0 && - sec != nullptr ) { - Elf64_Addr sec_addr = - get_virtual_addr( seg->get_offset(), sec ); - if ( sec_addr != seg->get_virtual_address() ) { - errors += "Virtual address of segment " + - std::to_string( h ) + " (" + - to_hex_string( seg->get_virtual_address() ) + - ")" + " conflicts with address of section " + - sec->get_name() + " (" + - to_hex_string( sec_addr ) + ")" + " at offset " + - to_hex_string( seg->get_offset() ) + "\n"; - } - } - } - - // more checks to be added here... - - return errors; - } - private: //------------------------------------------------------------------------------ static bool is_offset_in_section( Elf64_Off offset, const section* sec ) @@ -377,24 +228,6 @@ class elfio ( offset < ( sec->get_offset() + sec->get_size() ) ); } - //------------------------------------------------------------------------------ - static Elf64_Addr get_virtual_addr( Elf64_Off offset, const section* sec ) - { - return sec->get_address() + offset - sec->get_offset(); - } - - //------------------------------------------------------------------------------ - const section* find_prog_section_for_offset( Elf64_Off offset ) const - { - for ( const auto& sec : sections ) { - if ( sec->get_type() == SHT_PROGBITS && - is_offset_in_section( offset, sec.get() ) ) { - return sec.get(); - } - } - return nullptr; - } - //------------------------------------------------------------------------------ std::unique_ptr create_header( unsigned char file_class, unsigned char encoding ) @@ -613,334 +446,8 @@ class elfio return true; } - //------------------------------------------------------------------------------ - bool save_header( std::ostream& stream ) const - { - return header->save( stream ); - } - - //------------------------------------------------------------------------------ - bool save_sections( std::ostream& stream ) const - { - for ( const auto& sec : sections_ ) { - std::streampos headerPosition = - static_cast( header->get_sections_offset() ) + - static_cast( - header->get_section_entry_size() ) * - sec->get_index(); - - sec->save( stream, headerPosition, sec->get_offset() ); - } - return true; - } - - //------------------------------------------------------------------------------ - bool save_segments( std::ostream& stream ) const - { - for ( const auto& seg : segments_ ) { - std::streampos headerPosition = - static_cast( header->get_segments_offset() ) + - static_cast( - header->get_segment_entry_size() ) * - seg->get_index(); - - seg->save( stream, headerPosition, seg->get_offset() ); - } - return true; - } - - //------------------------------------------------------------------------------ - bool is_section_without_segment( unsigned int section_index ) const - { - bool found = false; - - for ( unsigned int j = 0; !found && ( j < segments.size() ); ++j ) { - for ( Elf_Half k = 0; - !found && ( k < segments[j]->get_sections_num() ); ++k ) { - found = segments[j]->get_section_index_at( k ) == section_index; - } - } - - return !found; - } - - //------------------------------------------------------------------------------ - static bool is_subsequence_of( const segment* seg1, const segment* seg2 ) - { - // Return 'true' if sections of seg1 are a subset of sections in seg2 - const std::vector& sections1 = seg1->get_sections(); - const std::vector& sections2 = seg2->get_sections(); - - bool found = false; - if ( sections1.size() < sections2.size() ) { - found = std::includes( sections2.begin(), sections2.end(), - sections1.begin(), sections1.end() ); - } - - return found; - } - - //------------------------------------------------------------------------------ - std::vector get_ordered_segments() const - { - std::vector res; - std::deque worklist; - - res.reserve( segments.size() ); - for ( const auto& seg : segments ) { - worklist.emplace_back( seg.get() ); - } - - // Bring the segments which start at address 0 to the front - size_t nextSlot = 0; - for ( size_t i = 0; i < worklist.size(); ++i ) { - if ( i != nextSlot && worklist[i]->is_offset_initialized() && - worklist[i]->get_offset() == 0 ) { - if ( worklist[nextSlot]->get_offset() == 0 ) { - ++nextSlot; - } - std::swap( worklist[i], worklist[nextSlot] ); - ++nextSlot; - } - } - - while ( !worklist.empty() ) { - segment* seg = worklist.front(); - worklist.pop_front(); - - size_t i = 0; - for ( ; i < worklist.size(); ++i ) { - if ( is_subsequence_of( seg, worklist[i] ) ) { - break; - } - } - - if ( i < worklist.size() ) { - worklist.emplace_back( seg ); - } - else { - res.emplace_back( seg ); - } - } - - return res; - } - - //------------------------------------------------------------------------------ - bool layout_sections_without_segments() - { - for ( unsigned int i = 0; i < sections_.size(); ++i ) { - if ( is_section_without_segment( i ) ) { - const auto& sec = sections_[i]; - - Elf_Xword section_align = sec->get_addr_align(); - if ( section_align > 1 && - current_file_pos % section_align != 0 ) { - current_file_pos += - section_align - current_file_pos % section_align; - } - - if ( 0 != sec->get_index() ) { - sec->set_offset( current_file_pos ); - } - - if ( SHT_NOBITS != sec->get_type() && - SHT_NULL != sec->get_type() ) { - current_file_pos += sec->get_size(); - } - } - } - - return true; - } - - //------------------------------------------------------------------------------ - void calc_segment_alignment() const - { - for ( const auto& seg : segments_ ) { - for ( Elf_Half i = 0; i < seg->get_sections_num(); ++i ) { - const auto& sect = sections_[seg->get_section_index_at( i )]; - if ( sect->get_addr_align() > seg->get_align() ) { - seg->set_align( sect->get_addr_align() ); - } - } - } - } - - //------------------------------------------------------------------------------ - bool layout_segments_and_their_sections() - { - std::vector worklist; - std::vector section_generated( sections.size(), false ); - - // Get segments in a order in where segments which contain a - // sub sequence of other segments are located at the end - worklist = get_ordered_segments(); - - for ( auto* seg : worklist ) { - Elf_Xword segment_memory = 0; - Elf_Xword segment_filesize = 0; - Elf_Xword seg_start_pos = current_file_pos; - // Special case: PHDR segment - // This segment contains the program headers but no sections - if ( seg->get_type() == PT_PHDR && seg->get_sections_num() == 0 ) { - seg_start_pos = header->get_segments_offset(); - segment_memory = segment_filesize = - header->get_segment_entry_size() * - static_cast( header->get_segments_num() ); - } - // Special case: - else if ( seg->is_offset_initialized() && seg->get_offset() == 0 ) { - seg_start_pos = 0; - if ( seg->get_sections_num() > 0 ) { - segment_memory = segment_filesize = current_file_pos; - } - } - // New segments with not generated sections - // have to be aligned - else if ( seg->get_sections_num() > 0 && - !section_generated[seg->get_section_index_at( 0 )] ) { - Elf_Xword align = seg->get_align() > 0 ? seg->get_align() : 1; - Elf64_Off cur_page_alignment = current_file_pos % align; - Elf64_Off req_page_alignment = - seg->get_virtual_address() % align; - Elf64_Off error = req_page_alignment - cur_page_alignment; - - current_file_pos += ( seg->get_align() + error ) % align; - seg_start_pos = current_file_pos; - } - else if ( seg->get_sections_num() > 0 ) { - seg_start_pos = - sections[seg->get_section_index_at( 0 )]->get_offset(); - } - - // Write segment's data - if ( !write_segment_data( seg, section_generated, segment_memory, - segment_filesize, seg_start_pos ) ) { - return false; - } - - seg->set_file_size( segment_filesize ); - - // If we already have a memory size from loading an elf file (value > 0), - // it must not shrink! - // Memory size may be bigger than file size and it is the loader's job to do something - // with the surplus bytes in memory, like initializing them with a defined value. - if ( seg->get_memory_size() < segment_memory ) { - seg->set_memory_size( segment_memory ); - } - - seg->set_offset( seg_start_pos ); - } - - return true; - } - - //------------------------------------------------------------------------------ - bool layout_section_table() - { - // Simply place the section table at the end for now - Elf64_Off alignmentError = current_file_pos % 4; - current_file_pos += ( 4 - alignmentError ) % 4; - header->set_sections_offset( current_file_pos ); - return true; - } - - //------------------------------------------------------------------------------ - bool write_segment_data( const segment* seg, - std::vector& section_generated, - Elf_Xword& segment_memory, - Elf_Xword& segment_filesize, - const Elf_Xword& seg_start_pos ) - { - for ( Elf_Half j = 0; j < seg->get_sections_num(); ++j ) { - Elf_Half index = seg->get_section_index_at( j ); - - section* sec = sections[index]; - - // The NULL section is always generated - if ( SHT_NULL == sec->get_type() ) { - section_generated[index] = true; - continue; - } - - Elf_Xword section_align = 0; - // Fix up the alignment - if ( !section_generated[index] && sec->is_address_initialized() && - SHT_NOBITS != sec->get_type() && SHT_NULL != sec->get_type() && - 0 != sec->get_size() ) { - // Align the sections based on the virtual addresses - // when possible (this is what matters for execution) - Elf64_Off req_offset = - sec->get_address() - seg->get_virtual_address(); - Elf64_Off cur_offset = current_file_pos - seg_start_pos; - if ( req_offset < cur_offset ) { - // something has gone awfully wrong, abort! - // section_align would turn out negative, seeking backwards and overwriting previous data - return false; - } - section_align = req_offset - cur_offset; - } - else if ( !section_generated[index] && - !sec->is_address_initialized() ) { - // If no address has been specified then only the section - // alignment constraint has to be matched - Elf_Xword align = sec->get_addr_align(); - if ( align == 0 ) { - align = 1; - } - Elf64_Off error = current_file_pos % align; - section_align = ( align - error ) % align; - } - else if ( section_generated[index] ) { - // Alignment for already generated sections - section_align = - sec->get_offset() - seg_start_pos - segment_filesize; - } - - // Determine the segment file and memory sizes - // Special case .tbss section (NOBITS) in non TLS segment - if ( ( ( sec->get_flags() & SHF_ALLOC ) == SHF_ALLOC ) && - !( ( ( sec->get_flags() & SHF_TLS ) == SHF_TLS ) && - ( seg->get_type() != PT_TLS ) && - ( SHT_NOBITS == sec->get_type() ) ) ) { - segment_memory += sec->get_size() + section_align; - } - - if ( SHT_NOBITS != sec->get_type() ) { - segment_filesize += sec->get_size() + section_align; - } - - // Nothing to be done when generating nested segments - if ( section_generated[index] ) { - continue; - } - - current_file_pos += section_align; - - // Set the section addresses when missing - if ( !sec->is_address_initialized() ) { - sec->set_address( seg->get_virtual_address() + - current_file_pos - seg_start_pos ); - } - - if ( 0 != sec->get_index() ) { - sec->set_offset( current_file_pos ); - } - - if ( SHT_NOBITS != sec->get_type() ) { - current_file_pos += sec->get_size(); - } - - section_generated[index] = true; - } - - return true; - } - //------------------------------------------------------------------------------ public: - friend class Sections; class Sections { public: diff --git a/source/elfio/elfio_header.hpp b/source/elfio/elfio_header.hpp index eccae13..c783496 100644 --- a/source/elfio/elfio_header.hpp +++ b/source/elfio/elfio_header.hpp @@ -33,7 +33,6 @@ class elf_header virtual ~elf_header() = default; virtual bool load( std::istream& stream ) = 0; - virtual bool save( std::ostream& stream ) const = 0; // ELF header functions ELFIO_GET_ACCESS_DECL( unsigned char, class ); @@ -108,16 +107,6 @@ template class elf_header_impl : public elf_header return ( stream.gcount() == sizeof( header ) ); } - //------------------------------------------------------------------------------ - bool save( std::ostream& stream ) const override - { - stream.seekp( ( *translator )[0] ); - stream.write( reinterpret_cast( &header ), - sizeof( header ) ); - - return stream.good(); - } - //------------------------------------------------------------------------------ // ELF header functions ELFIO_GET_ACCESS( unsigned char, class, header.e_ident[EI_CLASS] ); diff --git a/source/elfio/elfio_section.hpp b/source/elfio/elfio_section.hpp index ed9281e..3e262ec 100644 --- a/source/elfio/elfio_section.hpp +++ b/source/elfio/elfio_section.hpp @@ -68,9 +68,6 @@ class section virtual bool load( std::istream& stream, std::streampos header_offset, bool is_lazy ) = 0; - virtual void save( std::ostream& stream, - std::streampos header_offset, - std::streampos data_offset ) = 0; virtual bool is_address_initialized() const = 0; }; @@ -301,51 +298,9 @@ template class section_impl : public section return true; } - //------------------------------------------------------------------------------ - void save( std::ostream& stream, - std::streampos header_offset, - std::streampos data_offset ) override - { - if ( 0 != get_index() ) { - header.sh_offset = decltype( header.sh_offset )( data_offset ); - header.sh_offset = ( *convertor )( header.sh_offset ); - } - - save_header( stream, header_offset ); - if ( get_type() != SHT_NOBITS && get_type() != SHT_NULL && - get_size() != 0 && data != nullptr ) { - save_data( stream, data_offset ); - } - } - //------------------------------------------------------------------------------ private: - //------------------------------------------------------------------------------ - void save_header( std::ostream& stream, std::streampos header_offset ) const - { - adjust_stream_size( stream, header_offset ); - stream.write( reinterpret_cast( &header ), - sizeof( header ) ); - } - - //------------------------------------------------------------------------------ - void save_data( std::ostream& stream, std::streampos data_offset ) - { - adjust_stream_size( stream, data_offset ); - - if ( ( ( get_flags() & SHF_COMPRESSED ) || - ( get_flags() & SHF_RPX_DEFLATE ) ) && - compression != nullptr ) { - Elf_Xword decompressed_size = get_size(); - Elf_Xword compressed_size = 0; - auto compressed_ptr = compression->deflate( - data.get(), convertor, decompressed_size, compressed_size ); - stream.write( compressed_ptr.get(), compressed_size ); - } - else { - stream.write( get_data(), get_size() ); - } - } + private: //------------------------------------------------------------------------------ private: diff --git a/source/elfio/elfio_segment.hpp b/source/elfio/elfio_segment.hpp index 6b0f81d..03dcd0e 100644 --- a/source/elfio/elfio_segment.hpp +++ b/source/elfio/elfio_segment.hpp @@ -65,9 +65,6 @@ class segment virtual bool load( std::istream& stream, std::streampos header_offset, bool is_lazy ) = 0; - virtual void save( std::ostream& stream, - std::streampos header_offset, - std::streampos data_offset ) = 0; }; //------------------------------------------------------------------------------ @@ -218,17 +215,6 @@ template class segment_impl : public segment return true; } - //------------------------------------------------------------------------------ - void save( std::ostream& stream, - std::streampos header_offset, - std::streampos data_offset ) override - { - ph.p_offset = decltype( ph.p_offset )( data_offset ); - ph.p_offset = ( *convertor )( ph.p_offset ); - adjust_stream_size( stream, header_offset ); - stream.write( reinterpret_cast( &ph ), sizeof( ph ) ); - } - //------------------------------------------------------------------------------ size_t get_stream_size() const { return stream_size; }