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
#include <string>
#include <iostream>
#include <fstream>
#include <functional>
#include <algorithm>
#include <array>
@ -131,38 +129,21 @@ class elfio
}
//------------------------------------------------------------------------------
bool load( const std::string& file_name, bool is_lazy = false )
{
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 )
bool load(const char * pBuffer, size_t pBufferSize)
{
sections_.clear();
segments_.clear();
std::array<char, EI_NIDENT> e_ident = { 0 };
std::array<char, EI_NIDENT> 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<std::streamoff>( offset ) +
static_cast<std::streampos>( i ) * entry_size,
is_lazy );
sec->load( pBuffer, pBufferSize,
static_cast<off_t>( offset ) +
static_cast<off_t>( 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<std::streamoff>( offset ) +
static_cast<std::streampos>( i ) * entry_size,
is_lazy ) ||
stream.fail() ) {
if ( !seg->load( pBuffer, pBufferSize,
static_cast<off_t>( offset ) +
static_cast<off_t>( i ) * entry_size)) {
segments_.pop_back();
return false;
}
@ -580,7 +558,6 @@ class elfio
//------------------------------------------------------------------------------
private:
std::unique_ptr<std::ifstream> pstream = nullptr;
std::unique_ptr<elf_header> header = nullptr;
std::vector<std::unique_ptr<section>> sections_;
std::vector<std::unique_ptr<segment>> segments_;

View File

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

View File

@ -23,7 +23,7 @@ THE SOFTWARE.
#ifndef ELF_HEADER_HPP
#define ELF_HEADER_HPP
#include <iostream>
#include <cstring>
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 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);
stream.read( reinterpret_cast<char*>( &header ), sizeof( header ) );
if(sizeof( header ) > pBufferSize) {
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
#include <string>
#include <iostream>
#include <new>
#include <limits>
@ -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 T> 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 T> 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 T> 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<char*>( &header ), sizeof( header ) );
if( header_offset + sizeof( header ) > pBufferSize ) {
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 ( 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<Elf_Xword>( 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 T> 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 T> class section_impl : public section
const endianess_convertor* convertor = 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

@ -23,7 +23,6 @@ THE SOFTWARE.
#ifndef ELFIO_SEGMENT_HPP
#define ELFIO_SEGMENT_HPP
#include <iostream>
#include <vector>
#include <new>
#include <limits>
@ -62,9 +61,8 @@ class segment
virtual const std::vector<Elf_Half>& 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 T> 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 T> 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<char*>( &ph ), sizeof( ph ) );
if( header_offset + sizeof( ph ) > pBufferSize ) {
return false;
}
memcpy( reinterpret_cast<char*>( &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 T> 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<char[]> data;
std::vector<Elf_Half> sections;
const endianess_convertor* convertor = nullptr;
size_t stream_size = 0;
bool is_offset_set = false;
mutable bool is_lazy = false;
};
} // namespace ELFIO

View File

@ -54,8 +54,7 @@ template <class S> 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();
}

View File

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

View File

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

View File

@ -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 <memory>
@ -29,9 +28,7 @@ std::optional<std::unique_ptr<PluginMetaInformation>> 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<const char *>(pluginData->buffer.get()), pluginData->length)) {
DEBUG_FUNCTION_LINE_ERR("Can't process PluginData in elfio");
return {};
}
@ -48,10 +45,7 @@ std::optional<std::unique_ptr<PluginMetaInformation>> PluginMetaInformationFacto
return {};
}
membuf sbuf((char *) buffer, (char *) buffer + length);
std::istream in(&sbuf);
if (!reader.load(in)) {
if (!reader.load(reinterpret_cast<const char *>(buffer), length)) {
DEBUG_FUNCTION_LINE_ERR("Can't process PluginData in elfio");
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) {
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<const char *>(buffer), size)) {
DEBUG_FUNCTION_LINE_ERR("Can't find or process ELF file");
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;
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;