Generilize the section compression calls

This commit is contained in:
Serge Lamikhov-Center 2022-11-10 19:26:05 +02:00
parent 7608269069
commit 755f81351f
8 changed files with 180 additions and 129 deletions

View File

@ -491,50 +491,50 @@ constexpr Elf_Word SHN_XINDEX = 0xFFFF;
constexpr Elf_Word SHN_HIRESERVE = 0xFFFF;
// Section types
constexpr Elf_Word SHT_NULL = 0;
constexpr Elf_Word SHT_PROGBITS = 1;
constexpr Elf_Word SHT_SYMTAB = 2;
constexpr Elf_Word SHT_STRTAB = 3;
constexpr Elf_Word SHT_RELA = 4;
constexpr Elf_Word SHT_HASH = 5;
constexpr Elf_Word SHT_DYNAMIC = 6;
constexpr Elf_Word SHT_NOTE = 7;
constexpr Elf_Word SHT_NOBITS = 8;
constexpr Elf_Word SHT_REL = 9;
constexpr Elf_Word SHT_SHLIB = 10;
constexpr Elf_Word SHT_DYNSYM = 11;
constexpr Elf_Word SHT_INIT_ARRAY = 14;
constexpr Elf_Word SHT_FINI_ARRAY = 15;
constexpr Elf_Word SHT_PREINIT_ARRAY = 16;
constexpr Elf_Word SHT_GROUP = 17;
constexpr Elf_Word SHT_SYMTAB_SHNDX = 18;
constexpr Elf_Word SHT_GNU_ATTRIBUTES = 0x6ffffff5;
constexpr Elf_Word SHT_GNU_HASH = 0x6ffffff6;
constexpr Elf_Word SHT_GNU_LIBLIST = 0x6ffffff7;
constexpr Elf_Word SHT_CHECKSUM = 0x6ffffff8;
constexpr Elf_Word SHT_LOSUNW = 0x6ffffffa;
constexpr Elf_Word SHT_SUNW_move = 0x6ffffffa;
constexpr Elf_Word SHT_SUNW_COMDAT = 0x6ffffffb;
constexpr Elf_Word SHT_SUNW_syminfo = 0x6ffffffc;
constexpr Elf_Word SHT_GNU_verdef = 0x6ffffffd;
constexpr Elf_Word SHT_GNU_verneed = 0x6ffffffe;
constexpr Elf_Word SHT_GNU_versym = 0x6fffffff;
constexpr Elf_Word SHT_LOOS = 0x60000000;
constexpr Elf_Word SHT_HIOS = 0x6fffffff;
constexpr Elf_Word SHT_LOPROC = 0x70000000;
constexpr Elf_Word SHT_ARM_EXIDX = 0x70000001;
constexpr Elf_Word SHT_ARM_PREEMPTMAP = 0x70000002;
constexpr Elf_Word SHT_ARM_ATTRIBUTES = 0x70000003;
constexpr Elf_Word SHT_ARM_DEBUGOVERLAY = 0x70000004;
constexpr Elf_Word SHT_ARM_OVERLAYSECTION = 0x70000005;
constexpr Elf_Word SHT_HIPROC = 0x7FFFFFFF;
constexpr Elf_Word SHT_LOUSER = 0x80000000;
constexpr Elf_Word SHT_NULL = 0;
constexpr Elf_Word SHT_PROGBITS = 1;
constexpr Elf_Word SHT_SYMTAB = 2;
constexpr Elf_Word SHT_STRTAB = 3;
constexpr Elf_Word SHT_RELA = 4;
constexpr Elf_Word SHT_HASH = 5;
constexpr Elf_Word SHT_DYNAMIC = 6;
constexpr Elf_Word SHT_NOTE = 7;
constexpr Elf_Word SHT_NOBITS = 8;
constexpr Elf_Word SHT_REL = 9;
constexpr Elf_Word SHT_SHLIB = 10;
constexpr Elf_Word SHT_DYNSYM = 11;
constexpr Elf_Word SHT_INIT_ARRAY = 14;
constexpr Elf_Word SHT_FINI_ARRAY = 15;
constexpr Elf_Word SHT_PREINIT_ARRAY = 16;
constexpr Elf_Word SHT_GROUP = 17;
constexpr Elf_Word SHT_SYMTAB_SHNDX = 18;
constexpr Elf_Word SHT_GNU_ATTRIBUTES = 0x6ffffff5;
constexpr Elf_Word SHT_GNU_HASH = 0x6ffffff6;
constexpr Elf_Word SHT_GNU_LIBLIST = 0x6ffffff7;
constexpr Elf_Word SHT_CHECKSUM = 0x6ffffff8;
constexpr Elf_Word SHT_LOSUNW = 0x6ffffffa;
constexpr Elf_Word SHT_SUNW_move = 0x6ffffffa;
constexpr Elf_Word SHT_SUNW_COMDAT = 0x6ffffffb;
constexpr Elf_Word SHT_SUNW_syminfo = 0x6ffffffc;
constexpr Elf_Word SHT_GNU_verdef = 0x6ffffffd;
constexpr Elf_Word SHT_GNU_verneed = 0x6ffffffe;
constexpr Elf_Word SHT_GNU_versym = 0x6fffffff;
constexpr Elf_Word SHT_LOOS = 0x60000000;
constexpr Elf_Word SHT_HIOS = 0x6fffffff;
constexpr Elf_Word SHT_LOPROC = 0x70000000;
constexpr Elf_Word SHT_ARM_EXIDX = 0x70000001;
constexpr Elf_Word SHT_ARM_PREEMPTMAP = 0x70000002;
constexpr Elf_Word SHT_ARM_ATTRIBUTES = 0x70000003;
constexpr Elf_Word SHT_ARM_DEBUGOVERLAY = 0x70000004;
constexpr Elf_Word SHT_ARM_OVERLAYSECTION = 0x70000005;
constexpr Elf_Word SHT_HIPROC = 0x7FFFFFFF;
constexpr Elf_Word SHT_LOUSER = 0x80000000;
// Used by Nintendo Wii U
constexpr Elf_Word SHT_RPL_EXPORTS = 0x80000001;
constexpr Elf_Word SHT_RPL_IMPORTS = 0x80000002;
constexpr Elf_Word SHT_RPL_CRCS = 0x80000003;
constexpr Elf_Word SHT_RPL_FILEINFO = 0x80000004;
constexpr Elf_Word SHT_HIUSER = 0xFFFFFFFF;
constexpr Elf_Word SHT_RPL_EXPORTS = 0x80000001;
constexpr Elf_Word SHT_RPL_IMPORTS = 0x80000002;
constexpr Elf_Word SHT_RPL_CRCS = 0x80000003;
constexpr Elf_Word SHT_RPL_FILEINFO = 0x80000004;
constexpr Elf_Word SHT_HIUSER = 0xFFFFFFFF;
// Section attribute flags
constexpr Elf_Xword SHF_WRITE = 0x1;
@ -550,13 +550,13 @@ 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
constexpr Elf_Xword SHF_RPX_DEFLATE = 0x08000000;
constexpr Elf_Xword SHF_MASKOS = 0x0FF00000;
constexpr Elf_Xword SHF_MIPS_GPREL = 0x10000000;
constexpr Elf_Xword SHF_ORDERED = 0x40000000;
constexpr Elf_Xword SHF_EXCLUDE = 0x80000000;
constexpr Elf_Xword SHF_MASKPROC = 0xF0000000;
// 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;
constexpr Elf_Xword SHF_ORDERED = 0x40000000;
constexpr Elf_Xword SHF_EXCLUDE = 0x80000000;
constexpr Elf_Xword SHF_MASKPROC = 0xF0000000;
// Section group flags
constexpr Elf_Word GRP_COMDAT = 0x1;
@ -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

View File

@ -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();
@ -1058,12 +1061,12 @@ class elfio
//------------------------------------------------------------------------------
private:
std::unique_ptr<elf_header> header = nullptr;
std::vector<std::unique_ptr<section>> sections_;
std::vector<std::unique_ptr<segment>> segments_;
endianess_convertor convertor;
address_translator addr_translator;
std::shared_ptr<wiiu_zlib_interface> zlib = nullptr;
std::unique_ptr<elf_header> header = nullptr;
std::vector<std::unique_ptr<section>> sections_;
std::vector<std::unique_ptr<segment>> segments_;
endianess_convertor convertor;
address_translator addr_translator;
std::shared_ptr<compression_interface> compression = nullptr;
Elf_Xword current_file_pos = 0;
};

View File

@ -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;
}
//------------------------------------------------------------------------------
@ -979,7 +981,7 @@ class dump
Elf_Word no_notes = notes.get_notes_num();
if ( no_notes == 0 )
continue;
continue;
out << "Note segment (" << i << ")" << std::endl
<< " No Name Data size Description"

View File

@ -73,10 +73,11 @@ template <class T> class section_impl : public section
{
public:
//------------------------------------------------------------------------------
section_impl( const endianess_convertor* convertor,
const address_translator* translator,
const std::shared_ptr<wiiu_zlib_interface> &zlib )
: convertor( convertor ), translator( translator ), zlib(zlib)
section_impl( const endianess_convertor* convertor,
const address_translator* translator,
const std::shared_ptr<compression_interface>& compression )
: convertor( convertor ), translator( translator ),
compression( compression )
{
}
@ -221,28 +222,35 @@ 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);
if(decompressed_data == nullptr) {
std::cerr << "Failed to decompress section data." << std::endl;
auto decompressed_data = compression->inflate(
data.get(), convertor, size, uncompressed_size );
if ( decompressed_data == nullptr ) {
std::cerr << "Failed to decompress section data."
<< std::endl;
data = nullptr;
return false;
}
set_size(uncompressed_size);
set_size( uncompressed_size );
data = std::move(decompressed_data);
data = std::move( decompressed_data );
}
// 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,28 +293,32 @@ 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);
stream.write( compressed_ptr.get(), compressed_size);
} else {
Elf_Xword compressed_size = 0;
auto compressed_ptr = compression->deflate(
data.get(), convertor, decompressed_size, compressed_size );
stream.write( compressed_ptr.get(), compressed_size );
}
else {
stream.write( get_data(), get_size() );
}
}
//------------------------------------------------------------------------------
private:
T header = { 0 };
Elf_Half index = 0;
std::string name;
std::unique_ptr<char[]> data;
Elf_Word data_size = 0;
const endianess_convertor* convertor = nullptr;
const address_translator* translator = nullptr;
const std::shared_ptr<wiiu_zlib_interface> zlib = nullptr;
bool is_address_set = false;
size_t stream_size = 0;
T header = { 0 };
Elf_Half index = 0;
std::string name;
std::unique_ptr<char[]> data;
Elf_Word data_size = 0;
const endianess_convertor* convertor = nullptr;
const address_translator* translator = nullptr;
const std::shared_ptr<compression_interface> compression = nullptr;
bool is_address_set = false;
size_t stream_size = 0;
};
} // namespace ELFIO

View File

@ -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;
public:
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

View File

@ -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 );
}
}

View File

@ -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,40 +971,51 @@ TEST( ELFIOTest, test_dynamic_64_2 )
EXPECT_EQ( value, 0 );
}
class mock_wiiu_zlib : public wiiu_zlib_interface {
public:
std::unique_ptr<char[]> inflate(const char *data, const endianess_convertor *convertor, Elf_Xword compressed_size, Elf_Xword &uncompressed_size) const {
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 override
{
uncompressed_size = 2 * compressed_size;
return std::unique_ptr<char[]>(new char[uncompressed_size+1]);
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]);
return std::unique_ptr<char[]>( new char[compressed_size + 1] );
}
};
////////////////////////////////////////////////////////////////////////////////
// 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];
EXPECT_EQ( text1->get_size(), 36744);
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];
EXPECT_EQ(text2->get_size(), text1->get_size() * 2);
const section* text2 = reader.sections[1];
EXPECT_EQ( text2->get_size(), text1->get_size() * 2 );
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -2,7 +2,7 @@
int main()
{
std::cout << "Hello" << std::endl;
return 0;
std::cout << "Hello" << std::endl;
return 0;
}