From 333359c75dfe81400ebae3826ced070903a9b22e Mon Sep 17 00:00:00 2001 From: Maschell Date: Wed, 4 Jan 2023 15:05:26 +0100 Subject: [PATCH] Avoid using streams in ELFIO to massively reduce the binary size --- source/elfio/elfio.hpp | 61 +++++----------- source/elfio/elfio_dump.hpp | 2 - source/elfio/elfio_header.hpp | 14 ++-- source/elfio/elfio_section.hpp | 70 +++++++------------ source/elfio/elfio_segment.hpp | 50 ++++--------- source/elfio/elfio_symbols.hpp | 3 +- source/elfio/elfio_utils.hpp | 1 - source/plugin/PluginInformationFactory.cpp | 5 +- .../plugin/PluginMetaInformationFactory.cpp | 15 +--- source/utils/membuf.hpp | 23 ------ source/utils/wiiu_zlib.hpp | 6 +- 11 files changed, 73 insertions(+), 177 deletions(-) delete mode 100644 source/utils/membuf.hpp diff --git a/source/elfio/elfio.hpp b/source/elfio/elfio.hpp index 1cf2b82..da25bb5 100644 --- a/source/elfio/elfio.hpp +++ b/source/elfio/elfio.hpp @@ -24,8 +24,6 @@ THE SOFTWARE. #define ELFIO_HPP #include -#include -#include #include #include #include @@ -131,38 +129,21 @@ class elfio } //------------------------------------------------------------------------------ - bool load( const std::string& file_name, bool is_lazy = false ) - { - pstream = std::make_unique(); - pstream->open( file_name.c_str(), std::ios::in | std::ios::binary ); - if ( pstream == nullptr || !*pstream ) { - return false; - } - - bool ret = load( *pstream, is_lazy ); - - if ( !is_lazy ) { - pstream.release(); - } - - return ret; - } - - //------------------------------------------------------------------------------ - bool load( std::istream& stream, bool is_lazy = false ) + bool load(const char * pBuffer, size_t pBufferSize) { sections_.clear(); segments_.clear(); - std::array e_ident = { 0 }; + std::array e_ident = { }; // Read ELF file signature - stream.seekg( 0 ); - stream.read( e_ident.data(), sizeof( e_ident ) ); + if(sizeof( e_ident ) > pBufferSize) { + return false; + } + memcpy( e_ident.data(), pBuffer, sizeof( e_ident ) ); // Is it ELF file? - if ( stream.gcount() != sizeof( e_ident ) || - e_ident[EI_MAG0] != ELFMAG0 || e_ident[EI_MAG1] != ELFMAG1 || - e_ident[EI_MAG2] != ELFMAG2 || e_ident[EI_MAG3] != ELFMAG3 ) { + if (e_ident[EI_MAG0] != ELFMAG0 || e_ident[EI_MAG1] != ELFMAG1 || + e_ident[EI_MAG2] != ELFMAG2 || e_ident[EI_MAG3] != ELFMAG3 ) { return false; } @@ -181,12 +162,12 @@ class elfio if ( nullptr == header ) { return false; } - if ( !header->load( stream ) ) { + if ( !header->load( pBuffer, pBufferSize ) ) { return false; } - load_sections( stream, is_lazy ); - bool is_still_good = load_segments( stream, is_lazy ); + load_sections( pBuffer, pBufferSize ); + bool is_still_good = load_segments( pBuffer, pBufferSize ); return is_still_good; } @@ -313,7 +294,7 @@ class elfio } //------------------------------------------------------------------------------ - bool load_sections( std::istream& stream, bool is_lazy ) + bool load_sections( const char * pBuffer, size_t pBufferSize ) { unsigned char file_class = header->get_class(); Elf_Half entry_size = header->get_section_entry_size(); @@ -329,10 +310,9 @@ class elfio for ( Elf_Half i = 0; i < num; ++i ) { section* sec = create_section(); - sec->load( stream, - static_cast( offset ) + - static_cast( i ) * entry_size, - is_lazy ); + sec->load( pBuffer, pBufferSize, + static_cast( offset ) + + static_cast( i ) * entry_size); // To mark that the section is not permitted to reassign address // during layout calculation sec->set_address( sec->get_address() ); @@ -372,7 +352,7 @@ class elfio } //------------------------------------------------------------------------------ - bool load_segments( std::istream& stream, bool is_lazy ) + bool load_segments( const char * pBuffer, size_t pBufferSize ) { unsigned char file_class = header->get_class(); Elf_Half entry_size = header->get_segment_entry_size(); @@ -404,11 +384,9 @@ class elfio segment* seg = segments_.back().get(); - if ( !seg->load( stream, - static_cast( offset ) + - static_cast( i ) * entry_size, - is_lazy ) || - stream.fail() ) { + if ( !seg->load( pBuffer, pBufferSize, + static_cast( offset ) + + static_cast( i ) * entry_size)) { segments_.pop_back(); return false; } @@ -580,7 +558,6 @@ class elfio //------------------------------------------------------------------------------ private: - std::unique_ptr pstream = nullptr; std::unique_ptr header = nullptr; std::vector> sections_; std::vector> segments_; diff --git a/source/elfio/elfio_dump.hpp b/source/elfio/elfio_dump.hpp index 3310511..30f2e86 100644 --- a/source/elfio/elfio_dump.hpp +++ b/source/elfio/elfio_dump.hpp @@ -25,8 +25,6 @@ THE SOFTWARE. #include #include -#include -#include #include #include diff --git a/source/elfio/elfio_header.hpp b/source/elfio/elfio_header.hpp index e89009a..f7d9356 100644 --- a/source/elfio/elfio_header.hpp +++ b/source/elfio/elfio_header.hpp @@ -23,7 +23,7 @@ THE SOFTWARE. #ifndef ELF_HEADER_HPP #define ELF_HEADER_HPP -#include +#include namespace ELFIO { @@ -32,7 +32,7 @@ class elf_header public: virtual ~elf_header() = default; - virtual bool load( std::istream& stream ) = 0; + virtual bool load( const char * pBuffer, size_t pBufferSize ) = 0; // ELF header functions ELFIO_GET_ACCESS_DECL( unsigned char, class ); @@ -98,12 +98,14 @@ template class elf_header_impl : public elf_header } //------------------------------------------------------------------------------ - bool load( std::istream& stream ) override + bool load( const char * pBuffer, size_t pBufferSize ) override { - stream.seekg(0); - stream.read( reinterpret_cast( &header ), sizeof( header ) ); + if(sizeof( header ) > pBufferSize) { + return false; + } + memcpy( reinterpret_cast( &header ), pBuffer, sizeof( header )); - return ( stream.gcount() == sizeof( header ) ); + return true; } //------------------------------------------------------------------------------ diff --git a/source/elfio/elfio_section.hpp b/source/elfio/elfio_section.hpp index 2789b2f..8e92773 100644 --- a/source/elfio/elfio_section.hpp +++ b/source/elfio/elfio_section.hpp @@ -24,7 +24,6 @@ THE SOFTWARE. #define ELFIO_SECTION_HPP #include -#include #include #include @@ -58,16 +57,13 @@ class section virtual void insert_data( Elf_Xword pos, const char* raw_data, Elf_Word size ) = 0; virtual void insert_data( Elf_Xword pos, const std::string& data ) = 0; - virtual size_t get_stream_size() const = 0; - virtual void set_stream_size( size_t value ) = 0; protected: ELFIO_SET_ACCESS_DECL( Elf64_Off, offset ); ELFIO_SET_ACCESS_DECL( Elf_Half, index ); - virtual bool load( std::istream& stream, - std::streampos header_offset, - bool is_lazy ) = 0; + virtual bool load( const char * pBuffer, size_t pBufferSize, + off_t header_offset) = 0; virtual bool is_address_initialized() const = 0; }; @@ -118,9 +114,6 @@ template class section_impl : public section //------------------------------------------------------------------------------ const char* get_data() const override { - if ( is_lazy ) { - load_data(); - } return data.get(); } @@ -198,11 +191,6 @@ template class section_impl : public section return insert_data( pos, str_data.c_str(), (Elf_Word)str_data.size() ); } - size_t get_stream_size() const override { return stream_size; } - - //------------------------------------------------------------------------------ - void set_stream_size( size_t value ) override { stream_size = value; } - //------------------------------------------------------------------------------ protected: //------------------------------------------------------------------------------ @@ -219,53 +207,46 @@ template class section_impl : public section } //------------------------------------------------------------------------------ - bool load( std::istream& stream, - std::streampos header_offset, - bool is_lazy_ ) override + bool load( const char * pBuffer, size_t pBufferSize, + off_t header_offset) override { - pstream = &stream; - is_lazy = is_lazy_; - header = { 0 }; + header = { }; - stream.seekg( header_offset); - stream.read( reinterpret_cast( &header ), sizeof( header ) ); + if( header_offset + sizeof( header ) > pBufferSize ) { + return false; + } + memcpy( reinterpret_cast( &header ), pBuffer + header_offset, sizeof( header ) ); - if ( !is_lazy || is_compressed() ) { + bool ret = load_data(pBuffer, pBufferSize); - 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 ); - } + if (ret && 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; + return ret; } - bool load_data() const + bool load_data(const char * pBuffer, size_t pBufferSize) const { - is_lazy = false; Elf_Xword size = get_size(); if ( nullptr == data && SHT_NULL != get_type() && - SHT_NOBITS != get_type() && size < get_stream_size() ) { + SHT_NOBITS != get_type() && size < pBufferSize ) { data.reset( new ( std::nothrow ) char[size_t( size ) + 1] ); if ( ( 0 != size ) && ( nullptr != data ) ) { - pstream->seekg(( *convertor )( header.sh_offset )); - pstream->read( data.get(), size ); - if ( static_cast( pstream->gcount() ) != size ) { + auto offset = ( *convertor )( header.sh_offset ); + if(offset + size > pBufferSize) { data = nullptr; return false; } + memcpy( data.get(), pBuffer + offset, size ); // refresh size because it may have changed if we had to decompress data size = get_size(); @@ -287,7 +268,6 @@ template class section_impl : public section //------------------------------------------------------------------------------ private: - mutable std::istream* pstream = nullptr; T header = {}; Elf_Half index = 0; std::string name; @@ -296,8 +276,6 @@ template class section_impl : public section const endianess_convertor* convertor = nullptr; const std::shared_ptr compression = nullptr; bool is_address_set = false; - size_t stream_size = 0; - mutable bool is_lazy = false; }; } // namespace ELFIO diff --git a/source/elfio/elfio_segment.hpp b/source/elfio/elfio_segment.hpp index 753639a..5e66f78 100644 --- a/source/elfio/elfio_segment.hpp +++ b/source/elfio/elfio_segment.hpp @@ -23,7 +23,6 @@ THE SOFTWARE. #ifndef ELFIO_SEGMENT_HPP #define ELFIO_SEGMENT_HPP -#include #include #include #include @@ -62,9 +61,8 @@ class segment virtual const std::vector& get_sections() const = 0; - virtual bool load( std::istream& stream, - std::streampos header_offset, - bool is_lazy ) = 0; + virtual bool load( const char * pBuffer, size_t pBufferSize, + off_t header_offset ) = 0; }; //------------------------------------------------------------------------------ @@ -94,9 +92,6 @@ template class segment_impl : public segment //------------------------------------------------------------------------------ const char* get_data() const override { - if ( is_lazy ) { - load_data(); - } return data.get(); } @@ -159,43 +154,35 @@ template class segment_impl : public segment void set_index( const Elf_Half& value ) override { index = value; } //------------------------------------------------------------------------------ - bool load( std::istream& stream, - std::streampos header_offset, - bool is_lazy_ ) override + bool load( const char * pBuffer, size_t pBufferSize, + off_t header_offset) override { - pstream = &stream; - is_lazy = is_lazy_; - - stream.seekg( header_offset); - stream.read( reinterpret_cast( &ph ), sizeof( ph ) ); + if( header_offset + sizeof( ph ) > pBufferSize ) { + return false; + } + memcpy( reinterpret_cast( &ph ), pBuffer + header_offset, sizeof( ph ) ); is_offset_set = true; - if ( !is_lazy ) { - return load_data(); - } - - return true; + return load_data(pBuffer, pBufferSize); } //------------------------------------------------------------------------------ - bool load_data() const + bool load_data(const char * pBuffer, size_t pBufferSize) const { - is_lazy = false; if ( PT_NULL == get_type() || 0 == get_file_size() ) { return true; } - - pstream->seekg(( *convertor )( ph.p_offset )); + auto offset = ( *convertor )( ph.p_offset ); Elf_Xword size = get_file_size(); - if ( size > get_stream_size() ) { + if ( size > pBufferSize ) { data = nullptr; } else { data.reset( new ( std::nothrow ) char[(size_t)size + 1] ); - if ( nullptr != data.get() && pstream->read( data.get(), size ) ) { - data.get()[size] = 0; + if ( nullptr != data.get()) { + memcpy(data.get(), pBuffer + offset, size); } else { data = nullptr; @@ -206,23 +193,14 @@ template class segment_impl : public segment return true; } - //------------------------------------------------------------------------------ - size_t get_stream_size() const { return stream_size; } - - //------------------------------------------------------------------------------ - void set_stream_size( size_t value ) { stream_size = value; } - //------------------------------------------------------------------------------ private: - mutable std::istream* pstream = nullptr; T ph = {}; Elf_Half index = 0; mutable std::unique_ptr data; std::vector sections; const endianess_convertor* convertor = nullptr; - size_t stream_size = 0; bool is_offset_set = false; - mutable bool is_lazy = false; }; } // namespace ELFIO diff --git a/source/elfio/elfio_symbols.hpp b/source/elfio/elfio_symbols.hpp index d868500..f2153f0 100644 --- a/source/elfio/elfio_symbols.hpp +++ b/source/elfio/elfio_symbols.hpp @@ -54,8 +54,7 @@ template class symbol_section_accessor_template return nRet; } - if ( symbol_section->get_entry_size() >= minimum_symbol_size && - symbol_section->get_size() <= symbol_section->get_stream_size() ) { + if ( symbol_section->get_entry_size() >= minimum_symbol_size ) { nRet = symbol_section->get_size() / symbol_section->get_entry_size(); } diff --git a/source/elfio/elfio_utils.hpp b/source/elfio/elfio_utils.hpp index 5741dfb..b248e42 100644 --- a/source/elfio/elfio_utils.hpp +++ b/source/elfio/elfio_utils.hpp @@ -24,7 +24,6 @@ THE SOFTWARE. #define ELFIO_UTILS_HPP #include -#include #define ELFIO_GET_ACCESS_DECL( TYPE, NAME ) virtual TYPE get_##NAME() const = 0 diff --git a/source/plugin/PluginInformationFactory.cpp b/source/plugin/PluginInformationFactory.cpp index 5cb998c..e7ecbf0 100644 --- a/source/plugin/PluginInformationFactory.cpp +++ b/source/plugin/PluginInformationFactory.cpp @@ -18,7 +18,6 @@ #include "PluginInformationFactory.h" #include "../utils/ElfUtils.h" #include "../utils/utils.h" -#include "utils/membuf.hpp" #include "utils/wiiu_zlib.hpp" #include #include @@ -36,10 +35,8 @@ PluginInformationFactory::load(const std::shared_ptr &pluginData, re return {}; } elfio reader(new wiiu_zlib); - membuf sbuf((char *) pluginData->buffer.get(), (char *) pluginData->buffer.get() + pluginData->length); - std::istream in(&sbuf); - if (!reader.load(in)) { + if (!reader.load(reinterpret_cast(pluginData->buffer.get()), pluginData->length)) { DEBUG_FUNCTION_LINE_ERR("Can't process PluginData in elfio"); return {}; } diff --git a/source/plugin/PluginMetaInformationFactory.cpp b/source/plugin/PluginMetaInformationFactory.cpp index d595554..b32129f 100644 --- a/source/plugin/PluginMetaInformationFactory.cpp +++ b/source/plugin/PluginMetaInformationFactory.cpp @@ -19,7 +19,6 @@ #include "elfio/elfio.hpp" #include "fs/FSUtils.h" #include "utils/logger.h" -#include "utils/membuf.hpp" #include "utils/wiiu_zlib.hpp" #include @@ -29,9 +28,7 @@ std::optional> PluginMetaInformationFacto return {}; } ELFIO::elfio reader(new wiiu_zlib); - membuf sbuf((char *) pluginData->buffer.get(), (char *) pluginData->buffer.get() + pluginData->length); - std::istream in(&sbuf); - if (!reader.load(in)) { + if (!reader.load(reinterpret_cast(pluginData->buffer.get()), pluginData->length)) { DEBUG_FUNCTION_LINE_ERR("Can't process PluginData in elfio"); return {}; } @@ -48,10 +45,7 @@ std::optional> PluginMetaInformationFacto return {}; } - membuf sbuf((char *) buffer, (char *) buffer + length); - std::istream in(&sbuf); - - if (!reader.load(in)) { + if (!reader.load(reinterpret_cast(buffer), length)) { DEBUG_FUNCTION_LINE_ERR("Can't process PluginData in elfio"); return {}; } @@ -63,10 +57,7 @@ std::optional> PluginMetaInformationFacto std::optional> PluginMetaInformationFactory::loadPlugin(char *buffer, size_t size) { ELFIO::elfio reader(new wiiu_zlib); - membuf sbuf((char *) buffer, (char *) buffer + size); - std::istream in(&sbuf); - - if (!reader.load(in)) { + if (!reader.load(reinterpret_cast(buffer), size)) { DEBUG_FUNCTION_LINE_ERR("Can't find or process ELF file"); return std::nullopt; } diff --git a/source/utils/membuf.hpp b/source/utils/membuf.hpp deleted file mode 100644 index cbc9011..0000000 --- a/source/utils/membuf.hpp +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include - -struct membuf : std::streambuf { - membuf(char *begin, char *end) { - this->setg(begin, begin, end); - } - - pos_type seekoff(off_type off, std::ios_base::seekdir dir, std::ios_base::openmode which = std::ios_base::in) override { - if (dir == std::ios_base::cur) - gbump(off); - else if (dir == std::ios_base::end) - setg(eback(), egptr() + off, egptr()); - else if (dir == std::ios_base::beg) - setg(eback(), eback() + off, egptr()); - return gptr() - eback(); - } - - pos_type seekpos(pos_type sp, std::ios_base::openmode which) override { - return seekoff(sp - pos_type(off_type(0)), std::ios_base::beg, which); - } -}; \ No newline at end of file diff --git a/source/utils/wiiu_zlib.hpp b/source/utils/wiiu_zlib.hpp index 4aff09f..c4c770e 100644 --- a/source/utils/wiiu_zlib.hpp +++ b/source/utils/wiiu_zlib.hpp @@ -34,7 +34,7 @@ public: } int z_ret; - z_stream s = {nullptr}; + z_stream s = {}; s.zalloc = Z_NULL; s.zfree = Z_NULL; @@ -66,8 +66,8 @@ public: return nullptr; } - int z_ret = 0; - z_stream s = {nullptr}; + int z_ret; + z_stream s = {}; s.zalloc = Z_NULL; s.zfree = Z_NULL;