mirror of
https://github.com/serge1/ELFIO.git
synced 2024-12-26 18:15:40 +00:00
Generilize the section compression calls
This commit is contained in:
parent
7608269069
commit
755f81351f
@ -550,7 +550,7 @@ constexpr Elf_Xword SHF_TLS = 0x400;
|
||||
constexpr Elf_Xword SHF_COMPRESSED = 0x800;
|
||||
constexpr Elf_Xword SHF_GNU_RETAIN = 0x200000;
|
||||
constexpr Elf_Xword SHF_GNU_MBIND = 0x01000000;
|
||||
// flag used in Nintendo RPX/RPL to indicate section data is zlib-compressed
|
||||
// flag used in Nintendo RPX/RPL to indicate section data is compressed
|
||||
constexpr Elf_Xword SHF_RPX_DEFLATE = 0x08000000;
|
||||
constexpr Elf_Xword SHF_MASKOS = 0x0FF00000;
|
||||
constexpr Elf_Xword SHF_MIPS_GPREL = 0x10000000;
|
||||
@ -1323,6 +1323,23 @@ struct Elf64_auxv
|
||||
} a_un;
|
||||
};
|
||||
|
||||
struct Elf32_Chdr
|
||||
{
|
||||
Elf32_Word ch_type; // The compression algorithm used
|
||||
Elf32_Word ch_size; //The size, in bytes, of the uncompressed section data
|
||||
Elf32_Word
|
||||
ch_addralign; // The address alignment of the uncompressed section data
|
||||
};
|
||||
|
||||
struct Elf64_Chdr
|
||||
{
|
||||
Elf64_Word ch_type; //The compression algorithm used
|
||||
Elf64_Word ch_reserved; // Reserved
|
||||
Elf_Xword ch_size; //The size, in bytes, of the uncompressed section data
|
||||
Elf_Xword
|
||||
ch_addralign; //The address alignment of the uncompressed section data
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // namespace ELFIO
|
||||
#endif
|
||||
|
@ -63,12 +63,15 @@ class elfio
|
||||
{
|
||||
public:
|
||||
//------------------------------------------------------------------------------
|
||||
elfio() noexcept : sections( this ), segments( this ), zlib( nullptr )
|
||||
elfio() noexcept
|
||||
: sections( this ), segments( this ), compression( nullptr )
|
||||
{
|
||||
create( ELFCLASS32, ELFDATA2LSB );
|
||||
}
|
||||
|
||||
elfio( wiiu_zlib_interface *zlib ) noexcept : sections( this ), segments( this ), zlib( std::shared_ptr<wiiu_zlib_interface>(zlib) )
|
||||
elfio( compression_interface* compression ) noexcept
|
||||
: sections( this ), segments( this ),
|
||||
compression( std::shared_ptr<compression_interface>( compression ) )
|
||||
{
|
||||
elfio();
|
||||
}
|
||||
@ -82,12 +85,12 @@ class elfio
|
||||
segments_ = std::move( other.segments_ );
|
||||
convertor = std::move( other.convertor );
|
||||
addr_translator = std::move( other.addr_translator );
|
||||
zlib = std::move( other.zlib );
|
||||
compression = std::move( other.compression );
|
||||
|
||||
other.header = nullptr;
|
||||
other.sections_.clear();
|
||||
other.segments_.clear();
|
||||
other.zlib = nullptr;
|
||||
other.compression = nullptr;
|
||||
}
|
||||
|
||||
elfio& operator=( elfio&& other ) noexcept
|
||||
@ -99,11 +102,11 @@ class elfio
|
||||
convertor = std::move( other.convertor );
|
||||
addr_translator = std::move( other.addr_translator );
|
||||
current_file_pos = other.current_file_pos;
|
||||
zlib = std::move( other.zlib );
|
||||
compression = std::move( other.compression );
|
||||
|
||||
other.current_file_pos = 0;
|
||||
other.header = nullptr;
|
||||
other.zlib = nullptr;
|
||||
other.compression = nullptr;
|
||||
other.sections_.clear();
|
||||
other.segments_.clear();
|
||||
}
|
||||
@ -413,12 +416,12 @@ class elfio
|
||||
unsigned char file_class = get_class();
|
||||
|
||||
if ( file_class == ELFCLASS64 ) {
|
||||
sections_.emplace_back(
|
||||
new section_impl<Elf64_Shdr>( &convertor, &addr_translator, zlib ) );
|
||||
sections_.emplace_back( new section_impl<Elf64_Shdr>(
|
||||
&convertor, &addr_translator, compression ) );
|
||||
}
|
||||
else if ( file_class == ELFCLASS32 ) {
|
||||
sections_.emplace_back(
|
||||
new section_impl<Elf32_Shdr>( &convertor, &addr_translator, zlib ) );
|
||||
sections_.emplace_back( new section_impl<Elf32_Shdr>(
|
||||
&convertor, &addr_translator, compression ) );
|
||||
}
|
||||
else {
|
||||
sections_.pop_back();
|
||||
@ -1063,7 +1066,7 @@ class elfio
|
||||
std::vector<std::unique_ptr<segment>> segments_;
|
||||
endianess_convertor convertor;
|
||||
address_translator addr_translator;
|
||||
std::shared_ptr<wiiu_zlib_interface> zlib = nullptr;
|
||||
std::shared_ptr<compression_interface> compression = nullptr;
|
||||
|
||||
Elf_Xword current_file_pos = 0;
|
||||
};
|
||||
|
@ -741,8 +741,10 @@ class dump
|
||||
|
||||
out << "Key to Flags: W (write), A (alloc), X (execute), " << std::endl;
|
||||
out << " M (merge), S (strings), I (info)," << std::endl;
|
||||
out << " L (link order), O (extra OS processing required)," << std::endl;
|
||||
out << " G (group), T (TLS), C (compressed), E (exclude)" << std::endl;
|
||||
out << " L (link order), O (extra OS processing required),"
|
||||
<< std::endl;
|
||||
out << " G (group), T (TLS), C (compressed), E (exclude)"
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
@ -75,8 +75,9 @@ template <class T> class section_impl : public section
|
||||
//------------------------------------------------------------------------------
|
||||
section_impl( const endianess_convertor* convertor,
|
||||
const address_translator* translator,
|
||||
const std::shared_ptr<wiiu_zlib_interface> &zlib )
|
||||
: convertor( convertor ), translator( translator ), zlib(zlib)
|
||||
const std::shared_ptr<compression_interface>& compression )
|
||||
: convertor( convertor ), translator( translator ),
|
||||
compression( compression )
|
||||
{
|
||||
}
|
||||
|
||||
@ -221,17 +222,23 @@ template <class T> class section_impl : public section
|
||||
return false;
|
||||
}
|
||||
|
||||
if(get_flags() & SHF_RPX_DEFLATE) {
|
||||
if(zlib == nullptr) {
|
||||
std::cerr << "WARN: compressed section found but no zlib implementation provided. Skipping." << std::endl;
|
||||
if ( ( get_flags() & SHF_RPX_DEFLATE ) ||
|
||||
( get_flags() & SHF_COMPRESSED ) ) {
|
||||
if ( compression == nullptr ) {
|
||||
std::cerr
|
||||
<< "WARN: compressed section found but no "
|
||||
"compression implementation provided. Skipping."
|
||||
<< std::endl;
|
||||
data = nullptr;
|
||||
return false;
|
||||
}
|
||||
// at this point, data holds the whole compressed stream
|
||||
Elf_Xword uncompressed_size = 0;
|
||||
auto decompressed_data = zlib->inflate(data.get(), convertor, size, uncompressed_size);
|
||||
auto decompressed_data = compression->inflate(
|
||||
data.get(), convertor, size, uncompressed_size );
|
||||
if ( decompressed_data == nullptr ) {
|
||||
std::cerr << "Failed to decompress section data." << std::endl;
|
||||
std::cerr << "Failed to decompress section data."
|
||||
<< std::endl;
|
||||
data = nullptr;
|
||||
return false;
|
||||
}
|
||||
@ -242,7 +249,8 @@ template <class T> class section_impl : public section
|
||||
}
|
||||
// refresh size because it may have changed if we had to decompress data
|
||||
size = get_size();
|
||||
data.get()[size] = 0; // Ensure data is ended with 0 to avoid oob read
|
||||
data.get()[size] =
|
||||
0; // Ensure data is ended with 0 to avoid oob read
|
||||
data_size = decltype( data_size )( size );
|
||||
}
|
||||
else {
|
||||
@ -285,12 +293,16 @@ template <class T> class section_impl : public section
|
||||
{
|
||||
adjust_stream_size( stream, data_offset );
|
||||
|
||||
if( (get_flags() & SHF_RPX_DEFLATE) && zlib != nullptr) {
|
||||
if ( ( ( get_flags() & SHF_COMPRESSED ) ||
|
||||
( get_flags() & SHF_RPX_DEFLATE ) ) &&
|
||||
compression != nullptr ) {
|
||||
Elf_Xword decompressed_size = get_size();
|
||||
Elf_Xword compressed_size = 0;
|
||||
auto compressed_ptr = zlib->deflate(data.get(), convertor, decompressed_size, compressed_size);
|
||||
auto compressed_ptr = compression->deflate(
|
||||
data.get(), convertor, decompressed_size, compressed_size );
|
||||
stream.write( compressed_ptr.get(), compressed_size );
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
stream.write( get_data(), get_size() );
|
||||
}
|
||||
}
|
||||
@ -304,7 +316,7 @@ template <class T> class section_impl : public section
|
||||
Elf_Word data_size = 0;
|
||||
const endianess_convertor* convertor = nullptr;
|
||||
const address_translator* translator = nullptr;
|
||||
const std::shared_ptr<wiiu_zlib_interface> zlib = nullptr;
|
||||
const std::shared_ptr<compression_interface> compression = nullptr;
|
||||
bool is_address_set = false;
|
||||
size_t stream_size = 0;
|
||||
};
|
||||
|
@ -263,12 +263,12 @@ inline void adjust_stream_size( std::ostream& stream, std::streamsize offset )
|
||||
/**
|
||||
* Consumers should write an implementation of this class and pass an instance of it to the ELFIO::elfio constructor.
|
||||
*/
|
||||
class wiiu_zlib_interface
|
||||
class compression_interface
|
||||
{
|
||||
public:
|
||||
virtual ~wiiu_zlib_interface() = default;
|
||||
virtual ~compression_interface() = default;
|
||||
/**
|
||||
* decompresses a RPX/RPL zlib-compressed section.
|
||||
* decompresses a compressed section
|
||||
*
|
||||
* @param data the buffer of compressed data
|
||||
* @param endianness_convertor pointer to an endianness_convertor instance, used to convert numbers to/from the target endianness.
|
||||
@ -276,10 +276,14 @@ class wiiu_zlib_interface
|
||||
* @param decompressed_size a reference to a variable where the decompressed buffer size will be stored.
|
||||
* @returns a smart pointer to the decompressed data.
|
||||
*/
|
||||
virtual std::unique_ptr<char[]> inflate(const char *data, const endianess_convertor *convertor, Elf_Xword compressed_size, Elf_Xword &uncompressed_size) const = 0;
|
||||
virtual std::unique_ptr<char[]>
|
||||
inflate( const char* data,
|
||||
const endianess_convertor* convertor,
|
||||
Elf_Xword compressed_size,
|
||||
Elf_Xword& uncompressed_size ) const = 0;
|
||||
|
||||
/**
|
||||
* compresses a RPX/RPL zlib-compressed section.
|
||||
* compresses a section
|
||||
*
|
||||
* @param data the buffer of uncompressed data
|
||||
* @param endianness_convertor pointer to an endianness_convertor instance, used to convert numbers to/from the target endianness.
|
||||
@ -287,10 +291,13 @@ class wiiu_zlib_interface
|
||||
* @param compressed_size a reference to a variable where the compressed buffer size will be stored.
|
||||
* @returns a smart pointer to the compressed data.
|
||||
*/
|
||||
virtual std::unique_ptr<char[]> deflate(const char *data, const endianess_convertor *convertor, Elf_Xword decompressed_size, Elf_Xword &compressed_size) const = 0;
|
||||
virtual std::unique_ptr<char[]>
|
||||
deflate( const char* data,
|
||||
const endianess_convertor* convertor,
|
||||
Elf_Xword decompressed_size,
|
||||
Elf_Xword& compressed_size ) const = 0;
|
||||
};
|
||||
|
||||
|
||||
} // namespace ELFIO
|
||||
|
||||
#endif // ELFIO_UTILS_HPP
|
||||
|
@ -94,8 +94,7 @@ int main( int argc, char** argv )
|
||||
|
||||
for ( const auto& section : reader.sections ) {
|
||||
if ( section->get_type() == SHT_STRTAB &&
|
||||
std::string( section->get_name() ) ==
|
||||
std::string( ".strtab" ) ) {
|
||||
std::string( section->get_name() ) == std::string( ".strtab" ) ) {
|
||||
process_string_table( section.get(), filename );
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ THE SOFTWARE.
|
||||
using namespace ELFIO;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void checkHeader( elfio& reader,
|
||||
void checkHeader( const elfio& reader,
|
||||
unsigned char nClass,
|
||||
unsigned char encoding,
|
||||
unsigned char elfVersion,
|
||||
@ -971,14 +971,24 @@ TEST( ELFIOTest, test_dynamic_64_2 )
|
||||
EXPECT_EQ( value, 0 );
|
||||
}
|
||||
|
||||
class mock_wiiu_zlib : public wiiu_zlib_interface {
|
||||
class mock_wiiu_compression : public compression_interface
|
||||
{
|
||||
public:
|
||||
std::unique_ptr<char[]> inflate(const char *data, const endianess_convertor *convertor, Elf_Xword compressed_size, Elf_Xword &uncompressed_size) const {
|
||||
std::unique_ptr<char[]>
|
||||
inflate( const char* data,
|
||||
const endianess_convertor* convertor,
|
||||
Elf_Xword compressed_size,
|
||||
Elf_Xword& uncompressed_size ) const override
|
||||
{
|
||||
uncompressed_size = 2 * compressed_size;
|
||||
return std::unique_ptr<char[]>( new char[uncompressed_size + 1] );
|
||||
}
|
||||
|
||||
std::unique_ptr<char[]> deflate(const char *data, const endianess_convertor *convertor, Elf_Xword decompressed_size, Elf_Xword &compressed_size) const {
|
||||
std::unique_ptr<char[]> deflate( const char* data,
|
||||
const endianess_convertor* convertor,
|
||||
Elf_Xword decompressed_size,
|
||||
Elf_Xword& compressed_size ) const override
|
||||
{
|
||||
compressed_size = decompressed_size / 2;
|
||||
return std::unique_ptr<char[]>( new char[compressed_size + 1] );
|
||||
}
|
||||
@ -986,24 +996,25 @@ class mock_wiiu_zlib : public wiiu_zlib_interface {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Given: a valid RPX file
|
||||
// When: we load it with no zlib implementation
|
||||
// When: we load it with no compression implementation
|
||||
// Then: the size returns the raw section size (compressed size)
|
||||
// When: we load it with a mock zlib implementation
|
||||
// Then: the size changes to reflect the mock zlib implementation is being called
|
||||
// When: we load it with a mock compression implementation
|
||||
// Then: the size changes to reflect the mock compression implementation is being called
|
||||
//
|
||||
// This test does not do any further validation because doing so would require providing
|
||||
// a real zlib implementation
|
||||
// a real compression implementation
|
||||
TEST( ELFIOTest, test_rpx )
|
||||
{
|
||||
elfio reader(new mock_wiiu_zlib());
|
||||
elfio reader_no_zlib;
|
||||
elfio reader( new mock_wiiu_compression() );
|
||||
elfio reader_no_compression;
|
||||
|
||||
ASSERT_EQ( reader_no_zlib.load( "elf_examples/helloworld.rpx" ), true );
|
||||
section *text1 = reader_no_zlib.sections[1];
|
||||
ASSERT_EQ( reader_no_compression.load( "elf_examples/helloworld.rpx" ),
|
||||
true );
|
||||
const section* text1 = reader_no_compression.sections[1];
|
||||
EXPECT_EQ( text1->get_size(), 36744 );
|
||||
|
||||
ASSERT_EQ( reader.load( "elf_examples/helloworld.rpx" ), true );
|
||||
section *text2 = reader.sections[1];
|
||||
const section* text2 = reader.sections[1];
|
||||
EXPECT_EQ( text2->get_size(), text1->get_size() * 2 );
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user