Implement 'lazy' load for sections

This commit is contained in:
Serge Lamikhov-Center 2022-11-13 00:05:25 +02:00
parent 7c0abb1785
commit 9827eac948
3 changed files with 62 additions and 34 deletions

View File

@ -193,7 +193,7 @@ class elfio
return false;
}
load_sections( stream );
load_sections( stream, is_lazy );
bool is_still_good = load_segments( stream, is_lazy );
return is_still_good;
}
@ -494,7 +494,7 @@ class elfio
}
//------------------------------------------------------------------------------
bool load_sections( std::istream& stream ) noexcept
bool load_sections( std::istream& stream, bool is_lazy ) noexcept
{
unsigned char file_class = header->get_class();
Elf_Half entry_size = header->get_section_entry_size();
@ -512,7 +512,8 @@ class elfio
section* sec = create_section();
sec->load( stream,
static_cast<std::streamoff>( offset ) +
static_cast<std::streampos>( i ) * entry_size );
static_cast<std::streampos>( i ) * entry_size,
is_lazy );
// To mark that the section is not permitted to reassign address
// during layout calculation
sec->set_address( sec->get_address() );

View File

@ -64,11 +64,12 @@ class section
ELFIO_SET_ACCESS_DECL( Elf_Half, index );
virtual bool load( std::istream& stream,
std::streampos header_offset ) noexcept = 0;
std::streampos header_offset,
bool is_lazy ) noexcept = 0;
virtual void save( std::ostream& stream,
std::streampos header_offset,
std::streampos data_offset ) noexcept = 0;
virtual bool is_address_initialized() const noexcept = 0;
std::streampos data_offset ) noexcept = 0;
virtual bool is_address_initialized() const noexcept = 0;
};
template <class T> class section_impl : public section
@ -94,7 +95,6 @@ template <class T> class section_impl : public section
ELFIO_GET_SET_ACCESS( Elf_Xword, entry_size, header.sh_entsize );
ELFIO_GET_SET_ACCESS( Elf_Word, name_string_offset, header.sh_name );
ELFIO_GET_ACCESS( Elf64_Addr, address, header.sh_addr );
//------------------------------------------------------------------------------
Elf_Half get_index() const noexcept override { return index; }
@ -122,7 +122,13 @@ template <class T> class section_impl : public section
}
//------------------------------------------------------------------------------
const char* get_data() const noexcept override { return data.get(); }
const char* get_data() const noexcept override
{
if ( is_lazy ) {
load_data();
}
return data.get();
}
//------------------------------------------------------------------------------
void set_data( const char* raw_data, Elf_Word size ) noexcept override
@ -203,11 +209,21 @@ template <class T> class section_impl : public section
//------------------------------------------------------------------------------
void set_index( const Elf_Half& value ) noexcept override { index = value; }
bool is_compressed() const noexcept
{
return ( ( get_flags() & SHF_RPX_DEFLATE ) ||
( get_flags() & SHF_COMPRESSED ) ) &&
compression != nullptr;
}
//------------------------------------------------------------------------------
bool load( std::istream& stream,
std::streampos header_offset ) noexcept override
std::streampos header_offset,
bool is_lazy_ ) noexcept override
{
header = { 0 };
pstream = &stream;
is_lazy = is_lazy_;
header = { 0 };
if ( translator->empty() ) {
stream.seekg( 0, std::istream::end );
@ -220,33 +236,44 @@ template <class T> class section_impl : public section
stream.seekg( ( *translator )[header_offset] );
stream.read( reinterpret_cast<char*>( &header ), sizeof( header ) );
if ( !is_lazy || is_compressed() ) {
bool ret = load_data();
if ( is_compressed() ) {
Elf_Xword size = get_size();
Elf_Xword uncompressed_size = 0;
auto decompressed_data = compression->inflate(
data.get(), convertor, size, uncompressed_size );
if ( decompressed_data != nullptr ) {
set_size( uncompressed_size );
data = std::move( decompressed_data );
}
}
return ret;
}
return true;
}
bool load_data() const noexcept
{
is_lazy = false;
Elf_Xword size = get_size();
if ( nullptr == data && SHT_NULL != get_type() &&
SHT_NOBITS != get_type() && size < get_stream_size() ) {
data.reset( new ( std::nothrow ) char[size_t( size ) + 1] );
if ( ( 0 != size ) && ( nullptr != data ) ) {
stream.seekg(
pstream->seekg(
( *translator )[( *convertor )( header.sh_offset )] );
stream.read( data.get(), size );
if ( static_cast<Elf_Xword>( stream.gcount() ) != size ) {
pstream->read( data.get(), size );
if ( static_cast<Elf_Xword>( pstream->gcount() ) != size ) {
data = nullptr;
return false;
}
if ( ( ( get_flags() & SHF_RPX_DEFLATE ) ||
( get_flags() & SHF_COMPRESSED ) ) &&
compression != nullptr ) {
// at this point, data holds the whole compressed stream
Elf_Xword uncompressed_size = 0;
auto decompressed_data = compression->inflate(
data.get(), convertor, size, uncompressed_size );
if ( decompressed_data != nullptr ) {
set_size( uncompressed_size );
data = std::move( decompressed_data );
}
}
// refresh size because it may have changed if we had to decompress data
size = get_size();
data.get()[size] =
@ -290,8 +317,7 @@ template <class T> class section_impl : public section
}
//------------------------------------------------------------------------------
void save_data( std::ostream& stream,
std::streampos data_offset ) const noexcept
void save_data( std::ostream& stream, std::streampos data_offset ) noexcept
{
adjust_stream_size( stream, data_offset );
@ -311,16 +337,18 @@ template <class T> class section_impl : public section
//------------------------------------------------------------------------------
private:
T header = {};
Elf_Half index = 0;
mutable std::istream* pstream = nullptr;
T header = {};
Elf_Half index = 0;
std::string name;
std::unique_ptr<char[]> data;
Elf_Word data_size = 0;
mutable std::unique_ptr<char[]> data;
mutable Elf_Word data_size = 0;
const endianess_convertor* convertor = nullptr;
const address_translator* translator = nullptr;
const std::shared_ptr<compression_interface> compression = nullptr;
bool is_address_set = false;
size_t stream_size = 0;
mutable bool is_lazy = false;
};
} // namespace ELFIO

View File

@ -101,7 +101,6 @@ template <class T> class segment_impl : public segment
{
if ( is_lazy ) {
load_data();
is_lazy = false;
}
return data.get();
}
@ -198,6 +197,7 @@ template <class T> class segment_impl : public segment
//------------------------------------------------------------------------------
bool load_data() const noexcept
{
is_lazy = false;
if ( PT_NULL == get_type() || 0 == get_file_size() ) {
return true;
}
@ -213,7 +213,6 @@ template <class T> class segment_impl : public segment
if ( nullptr != data.get() && pstream->read( data.get(), size ) ) {
data.get()[size] = 0;
is_lazy = false;
}
else {
data = nullptr;