Avoid using streams in ELFIO to massively reduce the binary size

This commit is contained in:
Maschell 2023-01-04 15:05:26 +01:00
parent be5574ee9f
commit 333359c75d
11 changed files with 73 additions and 177 deletions

View File

@ -24,8 +24,6 @@ THE SOFTWARE.
#define ELFIO_HPP #define ELFIO_HPP
#include <string> #include <string>
#include <iostream>
#include <fstream>
#include <functional> #include <functional>
#include <algorithm> #include <algorithm>
#include <array> #include <array>
@ -131,38 +129,21 @@ class elfio
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
bool load( const std::string& file_name, bool is_lazy = false ) bool load(const char * pBuffer, size_t pBufferSize)
{
pstream = std::make_unique<std::ifstream>();
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 )
{ {
sections_.clear(); sections_.clear();
segments_.clear(); segments_.clear();
std::array<char, EI_NIDENT> e_ident = { 0 }; std::array<char, EI_NIDENT> e_ident = { };
// Read ELF file signature // Read ELF file signature
stream.seekg( 0 ); if(sizeof( e_ident ) > pBufferSize) {
stream.read( e_ident.data(), sizeof( e_ident ) ); return false;
}
memcpy( e_ident.data(), pBuffer, sizeof( e_ident ) );
// Is it ELF file? // Is it ELF file?
if ( stream.gcount() != sizeof( e_ident ) || if (e_ident[EI_MAG0] != ELFMAG0 || e_ident[EI_MAG1] != ELFMAG1 ||
e_ident[EI_MAG0] != ELFMAG0 || e_ident[EI_MAG1] != ELFMAG1 || e_ident[EI_MAG2] != ELFMAG2 || e_ident[EI_MAG3] != ELFMAG3 ) {
e_ident[EI_MAG2] != ELFMAG2 || e_ident[EI_MAG3] != ELFMAG3 ) {
return false; return false;
} }
@ -181,12 +162,12 @@ class elfio
if ( nullptr == header ) { if ( nullptr == header ) {
return false; return false;
} }
if ( !header->load( stream ) ) { if ( !header->load( pBuffer, pBufferSize ) ) {
return false; return false;
} }
load_sections( stream, is_lazy ); load_sections( pBuffer, pBufferSize );
bool is_still_good = load_segments( stream, is_lazy ); bool is_still_good = load_segments( pBuffer, pBufferSize );
return is_still_good; 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(); unsigned char file_class = header->get_class();
Elf_Half entry_size = header->get_section_entry_size(); Elf_Half entry_size = header->get_section_entry_size();
@ -329,10 +310,9 @@ class elfio
for ( Elf_Half i = 0; i < num; ++i ) { for ( Elf_Half i = 0; i < num; ++i ) {
section* sec = create_section(); section* sec = create_section();
sec->load( stream, sec->load( pBuffer, pBufferSize,
static_cast<std::streamoff>( offset ) + static_cast<off_t>( offset ) +
static_cast<std::streampos>( i ) * entry_size, static_cast<off_t>( i ) * entry_size);
is_lazy );
// To mark that the section is not permitted to reassign address // To mark that the section is not permitted to reassign address
// during layout calculation // during layout calculation
sec->set_address( sec->get_address() ); 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(); unsigned char file_class = header->get_class();
Elf_Half entry_size = header->get_segment_entry_size(); Elf_Half entry_size = header->get_segment_entry_size();
@ -404,11 +384,9 @@ class elfio
segment* seg = segments_.back().get(); segment* seg = segments_.back().get();
if ( !seg->load( stream, if ( !seg->load( pBuffer, pBufferSize,
static_cast<std::streamoff>( offset ) + static_cast<off_t>( offset ) +
static_cast<std::streampos>( i ) * entry_size, static_cast<off_t>( i ) * entry_size)) {
is_lazy ) ||
stream.fail() ) {
segments_.pop_back(); segments_.pop_back();
return false; return false;
} }
@ -580,7 +558,6 @@ class elfio
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
private: private:
std::unique_ptr<std::ifstream> pstream = nullptr;
std::unique_ptr<elf_header> header = nullptr; std::unique_ptr<elf_header> header = nullptr;
std::vector<std::unique_ptr<section>> sections_; std::vector<std::unique_ptr<section>> sections_;
std::vector<std::unique_ptr<segment>> segments_; std::vector<std::unique_ptr<segment>> segments_;

View File

@ -25,8 +25,6 @@ THE SOFTWARE.
#include <algorithm> #include <algorithm>
#include <string> #include <string>
#include <ostream>
#include <sstream>
#include <iomanip> #include <iomanip>
#include <elfio/elfio.hpp> #include <elfio/elfio.hpp>

View File

@ -23,7 +23,7 @@ THE SOFTWARE.
#ifndef ELF_HEADER_HPP #ifndef ELF_HEADER_HPP
#define ELF_HEADER_HPP #define ELF_HEADER_HPP
#include <iostream> #include <cstring>
namespace ELFIO { namespace ELFIO {
@ -32,7 +32,7 @@ class elf_header
public: public:
virtual ~elf_header() = default; virtual ~elf_header() = default;
virtual bool load( std::istream& stream ) = 0; virtual bool load( const char * pBuffer, size_t pBufferSize ) = 0;
// ELF header functions // ELF header functions
ELFIO_GET_ACCESS_DECL( unsigned char, class ); ELFIO_GET_ACCESS_DECL( unsigned char, class );
@ -98,12 +98,14 @@ template <class T> 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); if(sizeof( header ) > pBufferSize) {
stream.read( reinterpret_cast<char*>( &header ), sizeof( header ) ); return false;
}
memcpy( reinterpret_cast<char*>( &header ), pBuffer, sizeof( header ));
return ( stream.gcount() == sizeof( header ) ); return true;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View File

@ -24,7 +24,6 @@ THE SOFTWARE.
#define ELFIO_SECTION_HPP #define ELFIO_SECTION_HPP
#include <string> #include <string>
#include <iostream>
#include <new> #include <new>
#include <limits> #include <limits>
@ -58,16 +57,13 @@ class section
virtual void virtual void
insert_data( Elf_Xword pos, const char* raw_data, Elf_Word size ) = 0; 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 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: protected:
ELFIO_SET_ACCESS_DECL( Elf64_Off, offset ); ELFIO_SET_ACCESS_DECL( Elf64_Off, offset );
ELFIO_SET_ACCESS_DECL( Elf_Half, index ); ELFIO_SET_ACCESS_DECL( Elf_Half, index );
virtual bool load( std::istream& stream, virtual bool load( const char * pBuffer, size_t pBufferSize,
std::streampos header_offset, off_t header_offset) = 0;
bool is_lazy ) = 0;
virtual bool is_address_initialized() const = 0; virtual bool is_address_initialized() const = 0;
}; };
@ -118,9 +114,6 @@ template <class T> class section_impl : public section
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
const char* get_data() const override const char* get_data() const override
{ {
if ( is_lazy ) {
load_data();
}
return data.get(); return data.get();
} }
@ -198,11 +191,6 @@ template <class T> class section_impl : public section
return insert_data( pos, str_data.c_str(), (Elf_Word)str_data.size() ); 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: protected:
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -219,53 +207,46 @@ template <class T> class section_impl : public section
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
bool load( std::istream& stream, bool load( const char * pBuffer, size_t pBufferSize,
std::streampos header_offset, off_t header_offset) override
bool is_lazy_ ) override
{ {
pstream = &stream; header = { };
is_lazy = is_lazy_;
header = { 0 };
stream.seekg( header_offset); if( header_offset + sizeof( header ) > pBufferSize ) {
stream.read( reinterpret_cast<char*>( &header ), sizeof( header ) ); return false;
}
memcpy( reinterpret_cast<char*>( &header ), pBuffer + header_offset, sizeof( header ) );
if ( !is_lazy || is_compressed() ) { bool ret = load_data(pBuffer, pBufferSize);
bool ret = load_data(); if (ret && is_compressed() ) {
Elf_Xword size = get_size();
if ( is_compressed() ) { Elf_Xword uncompressed_size = 0;
Elf_Xword size = get_size(); auto decompressed_data = compression->inflate(
Elf_Xword uncompressed_size = 0; data.get(), convertor, size, uncompressed_size );
auto decompressed_data = compression->inflate( if ( decompressed_data != nullptr ) {
data.get(), convertor, size, uncompressed_size ); set_size( uncompressed_size );
if ( decompressed_data != nullptr ) { data = std::move( decompressed_data );
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(); Elf_Xword size = get_size();
if ( nullptr == data && SHT_NULL != get_type() && 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] ); data.reset( new ( std::nothrow ) char[size_t( size ) + 1] );
if ( ( 0 != size ) && ( nullptr != data ) ) { if ( ( 0 != size ) && ( nullptr != data ) ) {
pstream->seekg(( *convertor )( header.sh_offset )); auto offset = ( *convertor )( header.sh_offset );
pstream->read( data.get(), size ); if(offset + size > pBufferSize) {
if ( static_cast<Elf_Xword>( pstream->gcount() ) != size ) {
data = nullptr; data = nullptr;
return false; return false;
} }
memcpy( data.get(), pBuffer + offset, size );
// refresh size because it may have changed if we had to decompress data // refresh size because it may have changed if we had to decompress data
size = get_size(); size = get_size();
@ -287,7 +268,6 @@ template <class T> class section_impl : public section
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
private: private:
mutable std::istream* pstream = nullptr;
T header = {}; T header = {};
Elf_Half index = 0; Elf_Half index = 0;
std::string name; std::string name;
@ -296,8 +276,6 @@ template <class T> class section_impl : public section
const endianess_convertor* convertor = nullptr; const endianess_convertor* convertor = nullptr;
const std::shared_ptr<compression_interface> compression = nullptr; const std::shared_ptr<compression_interface> compression = nullptr;
bool is_address_set = false; bool is_address_set = false;
size_t stream_size = 0;
mutable bool is_lazy = false;
}; };
} // namespace ELFIO } // namespace ELFIO

View File

@ -23,7 +23,6 @@ THE SOFTWARE.
#ifndef ELFIO_SEGMENT_HPP #ifndef ELFIO_SEGMENT_HPP
#define ELFIO_SEGMENT_HPP #define ELFIO_SEGMENT_HPP
#include <iostream>
#include <vector> #include <vector>
#include <new> #include <new>
#include <limits> #include <limits>
@ -62,9 +61,8 @@ class segment
virtual const std::vector<Elf_Half>& get_sections() const = 0; virtual const std::vector<Elf_Half>& get_sections() const = 0;
virtual bool load( std::istream& stream, virtual bool load( const char * pBuffer, size_t pBufferSize,
std::streampos header_offset, off_t header_offset ) = 0;
bool is_lazy ) = 0;
}; };
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -94,9 +92,6 @@ template <class T> class segment_impl : public segment
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
const char* get_data() const override const char* get_data() const override
{ {
if ( is_lazy ) {
load_data();
}
return data.get(); return data.get();
} }
@ -159,43 +154,35 @@ template <class T> class segment_impl : public segment
void set_index( const Elf_Half& value ) override { index = value; } void set_index( const Elf_Half& value ) override { index = value; }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
bool load( std::istream& stream, bool load( const char * pBuffer, size_t pBufferSize,
std::streampos header_offset, off_t header_offset) override
bool is_lazy_ ) override
{ {
pstream = &stream; if( header_offset + sizeof( ph ) > pBufferSize ) {
is_lazy = is_lazy_; return false;
}
stream.seekg( header_offset); memcpy( reinterpret_cast<char*>( &ph ), pBuffer + header_offset, sizeof( ph ) );
stream.read( reinterpret_cast<char*>( &ph ), sizeof( ph ) );
is_offset_set = true; is_offset_set = true;
if ( !is_lazy ) { return load_data(pBuffer, pBufferSize);
return load_data();
}
return true;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
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() ) { if ( PT_NULL == get_type() || 0 == get_file_size() ) {
return true; return true;
} }
auto offset = ( *convertor )( ph.p_offset );
pstream->seekg(( *convertor )( ph.p_offset ));
Elf_Xword size = get_file_size(); Elf_Xword size = get_file_size();
if ( size > get_stream_size() ) { if ( size > pBufferSize ) {
data = nullptr; data = nullptr;
} }
else { else {
data.reset( new ( std::nothrow ) char[(size_t)size + 1] ); data.reset( new ( std::nothrow ) char[(size_t)size + 1] );
if ( nullptr != data.get() && pstream->read( data.get(), size ) ) { if ( nullptr != data.get()) {
data.get()[size] = 0; memcpy(data.get(), pBuffer + offset, size);
} }
else { else {
data = nullptr; data = nullptr;
@ -206,23 +193,14 @@ template <class T> class segment_impl : public segment
return true; return true;
} }
//------------------------------------------------------------------------------
size_t get_stream_size() const { return stream_size; }
//------------------------------------------------------------------------------
void set_stream_size( size_t value ) { stream_size = value; }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
private: private:
mutable std::istream* pstream = nullptr;
T ph = {}; T ph = {};
Elf_Half index = 0; Elf_Half index = 0;
mutable std::unique_ptr<char[]> data; mutable std::unique_ptr<char[]> data;
std::vector<Elf_Half> sections; std::vector<Elf_Half> sections;
const endianess_convertor* convertor = nullptr; const endianess_convertor* convertor = nullptr;
size_t stream_size = 0;
bool is_offset_set = false; bool is_offset_set = false;
mutable bool is_lazy = false;
}; };
} // namespace ELFIO } // namespace ELFIO

View File

@ -54,8 +54,7 @@ template <class S> class symbol_section_accessor_template
return nRet; return nRet;
} }
if ( symbol_section->get_entry_size() >= minimum_symbol_size && if ( symbol_section->get_entry_size() >= minimum_symbol_size ) {
symbol_section->get_size() <= symbol_section->get_stream_size() ) {
nRet = nRet =
symbol_section->get_size() / symbol_section->get_entry_size(); symbol_section->get_size() / symbol_section->get_entry_size();
} }

View File

@ -24,7 +24,6 @@ THE SOFTWARE.
#define ELFIO_UTILS_HPP #define ELFIO_UTILS_HPP
#include <cstdint> #include <cstdint>
#include <ostream>
#define ELFIO_GET_ACCESS_DECL( TYPE, NAME ) virtual TYPE get_##NAME() const = 0 #define ELFIO_GET_ACCESS_DECL( TYPE, NAME ) virtual TYPE get_##NAME() const = 0

View File

@ -18,7 +18,6 @@
#include "PluginInformationFactory.h" #include "PluginInformationFactory.h"
#include "../utils/ElfUtils.h" #include "../utils/ElfUtils.h"
#include "../utils/utils.h" #include "../utils/utils.h"
#include "utils/membuf.hpp"
#include "utils/wiiu_zlib.hpp" #include "utils/wiiu_zlib.hpp"
#include <coreinit/cache.h> #include <coreinit/cache.h>
#include <map> #include <map>
@ -36,10 +35,8 @@ PluginInformationFactory::load(const std::shared_ptr<PluginData> &pluginData, re
return {}; return {};
} }
elfio reader(new wiiu_zlib); 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<const char *>(pluginData->buffer.get()), pluginData->length)) {
DEBUG_FUNCTION_LINE_ERR("Can't process PluginData in elfio"); DEBUG_FUNCTION_LINE_ERR("Can't process PluginData in elfio");
return {}; return {};
} }

View File

@ -19,7 +19,6 @@
#include "elfio/elfio.hpp" #include "elfio/elfio.hpp"
#include "fs/FSUtils.h" #include "fs/FSUtils.h"
#include "utils/logger.h" #include "utils/logger.h"
#include "utils/membuf.hpp"
#include "utils/wiiu_zlib.hpp" #include "utils/wiiu_zlib.hpp"
#include <memory> #include <memory>
@ -29,9 +28,7 @@ std::optional<std::unique_ptr<PluginMetaInformation>> PluginMetaInformationFacto
return {}; return {};
} }
ELFIO::elfio reader(new wiiu_zlib); ELFIO::elfio reader(new wiiu_zlib);
membuf sbuf((char *) pluginData->buffer.get(), (char *) pluginData->buffer.get() + pluginData->length); if (!reader.load(reinterpret_cast<const char *>(pluginData->buffer.get()), pluginData->length)) {
std::istream in(&sbuf);
if (!reader.load(in)) {
DEBUG_FUNCTION_LINE_ERR("Can't process PluginData in elfio"); DEBUG_FUNCTION_LINE_ERR("Can't process PluginData in elfio");
return {}; return {};
} }
@ -48,10 +45,7 @@ std::optional<std::unique_ptr<PluginMetaInformation>> PluginMetaInformationFacto
return {}; return {};
} }
membuf sbuf((char *) buffer, (char *) buffer + length); if (!reader.load(reinterpret_cast<const char *>(buffer), length)) {
std::istream in(&sbuf);
if (!reader.load(in)) {
DEBUG_FUNCTION_LINE_ERR("Can't process PluginData in elfio"); DEBUG_FUNCTION_LINE_ERR("Can't process PluginData in elfio");
return {}; return {};
} }
@ -63,10 +57,7 @@ std::optional<std::unique_ptr<PluginMetaInformation>> PluginMetaInformationFacto
std::optional<std::unique_ptr<PluginMetaInformation>> PluginMetaInformationFactory::loadPlugin(char *buffer, size_t size) { std::optional<std::unique_ptr<PluginMetaInformation>> PluginMetaInformationFactory::loadPlugin(char *buffer, size_t size) {
ELFIO::elfio reader(new wiiu_zlib); ELFIO::elfio reader(new wiiu_zlib);
membuf sbuf((char *) buffer, (char *) buffer + size); if (!reader.load(reinterpret_cast<const char *>(buffer), size)) {
std::istream in(&sbuf);
if (!reader.load(in)) {
DEBUG_FUNCTION_LINE_ERR("Can't find or process ELF file"); DEBUG_FUNCTION_LINE_ERR("Can't find or process ELF file");
return std::nullopt; return std::nullopt;
} }

View File

@ -1,23 +0,0 @@
#pragma once
#include <iostream>
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);
}
};

View File

@ -34,7 +34,7 @@ public:
} }
int z_ret; int z_ret;
z_stream s = {nullptr}; z_stream s = {};
s.zalloc = Z_NULL; s.zalloc = Z_NULL;
s.zfree = Z_NULL; s.zfree = Z_NULL;
@ -66,8 +66,8 @@ public:
return nullptr; return nullptr;
} }
int z_ret = 0; int z_ret;
z_stream s = {nullptr}; z_stream s = {};
s.zalloc = Z_NULL; s.zalloc = Z_NULL;
s.zfree = Z_NULL; s.zfree = Z_NULL;