mirror of
https://github.com/wiiu-env/WiiUPluginLoaderBackend.git
synced 2024-11-22 04:39:17 +01:00
Avoid using streams in ELFIO to massively reduce the binary size
This commit is contained in:
parent
be5574ee9f
commit
333359c75d
@ -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_;
|
||||
|
@ -25,8 +25,6 @@ THE SOFTWARE.
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <elfio/elfio.hpp>
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 {};
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
};
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user