Add ELF support, handle condcodes, test ZRSH
All checks were successful
Test / build (push) Successful in 14s

This commit is contained in:
shylie 2025-10-28 12:09:50 -04:00
parent e647b9e146
commit d271bdc959
25 changed files with 8586 additions and 41 deletions

54
.clang-format Normal file
View File

@ -0,0 +1,54 @@
# Generated from CLion C/C++ Code Style settings
---
Language: Cpp
BasedOnStyle: LLVM
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignOperands: false
AlignTrailingComments: false
AlwaysBreakTemplateDeclarations: Yes
BraceWrapping:
AfterCaseLabel: true
AfterClass: true
AfterControlStatement: true
AfterEnum: true
AfterFunction: true
AfterNamespace: true
AfterStruct: true
AfterUnion: true
AfterExternBlock: false
BeforeCatch: true
BeforeElse: true
BeforeLambdaBody: true
BeforeWhile: true
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBraces: Custom
BreakConstructorInitializers: AfterColon
BreakConstructorInitializersBeforeComma: false
ColumnLimit: 120
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ContinuationIndentWidth: 2
IncludeCategories:
- Regex: '^<.*'
Priority: 1
- Regex: '^".*'
Priority: 2
- Regex: '.*'
Priority: 3
IncludeIsMainRegex: '([-_](test|unittest))?$'
IndentCaseBlocks: true
InsertNewlineAtEOF: true
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 2
NamespaceIndentation: All
PointerAlignment: Left
SpaceInEmptyParentheses: false
SpacesInAngles: false
SpacesInConditionalStatement: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
TabWidth: 4
...

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
.cache/
.idea/
build/
emulator/customasm/*.bin

View File

@ -25,7 +25,7 @@
╠══════════╬══════════════════════╬════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠══════╬═════════════════════════╣
║ BXOR ║ Bitwise exclusive or ║ D = A ^ B ║ CCCR ║ 0100 ║ 0DDd ║ dddd ║ 0BBb ║ bbbb ║ 0AAa ║ aaaa ║ ║ 101 ║ A > B ║
╠══════════╬══════════════════════╬════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠══════╬═════════════════════════╣
RESERVED ║ ║ ║ ║ 0101 ║ ║ ║ ║ ║ ║ ║ ║ 110 ║ A != B ║
ZRSH ║ Pad zero right shift ║ D = A >> B ║ CCCR ║ 0101 ║ 0DDd ║ dddd ║ 0BBb ║ bbbb ║ 0AAa ║ aaaa ║ ║ 110 ║ A != B ║
╠══════════╬══════════════════════╬════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠══════╬═════════════════════════╣
║ SRSH ║ Signed right shift ║ D = A >> B ║ CCCR ║ 0110 ║ xDDd ║ dddd ║ 0BBb ║ bbbb ║ xAAa ║ aaaa ║ ║ 111 ║ Reserved ║
╠══════════╬══════════════════════╬════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠══════╩═════════════════════════╣

View File

@ -0,0 +1,21 @@
MIT License
Copyright (C) 2001-present by Serge Lamikhov-Center
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,119 @@
/*
Copyright (C) 2001-present by Serge Lamikhov-Center
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef ELFIO_ARRAY_HPP
#define ELFIO_ARRAY_HPP
#include <algorithm>
namespace ELFIO {
//------------------------------------------------------------------------------
// Template class for accessing array sections
template <class S, typename T> class array_section_accessor_template
{
public:
//------------------------------------------------------------------------------
// Constructor
explicit array_section_accessor_template( const elfio& elf_file,
S* section );
//------------------------------------------------------------------------------
// Returns the number of entries in the array section
Elf_Xword get_entries_num() const;
//------------------------------------------------------------------------------
// Retrieves an entry from the array section
bool get_entry( Elf_Xword index, Elf64_Addr& address ) const;
//------------------------------------------------------------------------------
// Adds an entry to the array section
void add_entry( Elf64_Addr address );
private:
//------------------------------------------------------------------------------
// Reference to the ELF file
const elfio& elf_file;
//------------------------------------------------------------------------------
// Pointer to the array section
S* array_section;
};
//------------------------------------------------------------------------------
// Constructor
template <class S, typename T>
array_section_accessor_template<S, T>::array_section_accessor_template(
const elfio& elf_file, S* section )
: elf_file( elf_file ), array_section( section )
{
}
//------------------------------------------------------------------------------
// Returns the number of entries in the array section
template <class S, typename T>
Elf_Xword array_section_accessor_template<S, T>::get_entries_num() const
{
Elf_Xword entry_size = sizeof( T );
return array_section->get_size() / entry_size;
}
//------------------------------------------------------------------------------
// Retrieves an entry from the array section
template <class S, typename T>
bool array_section_accessor_template<S, T>::get_entry(
Elf_Xword index, Elf64_Addr& address ) const
{
if ( index >= get_entries_num() ) { // Is index valid
return false;
}
const auto& convertor = elf_file.get_convertor();
const T temp = *reinterpret_cast<const T*>( array_section->get_data() +
index * sizeof( T ) );
address = ( *convertor )( temp );
return true;
}
//------------------------------------------------------------------------------
// Adds an entry to the array section
template <class S, typename T>
void array_section_accessor_template<S, T>::add_entry( Elf64_Addr address )
{
const auto& convertor = elf_file.get_convertor();
T temp = ( *convertor )( (T)address );
array_section->append_data( reinterpret_cast<char*>( &temp ),
sizeof( temp ) );
}
// Type aliases for array section accessors
template <typename T = Elf32_Word>
using array_section_accessor = array_section_accessor_template<section, T>;
template <typename T = Elf32_Word>
using const_array_section_accessor =
array_section_accessor_template<const section, T>;
} // namespace ELFIO
#endif // ELFIO_ARRAY_HPP

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,300 @@
/*
Copyright (C) 2001-present by Serge Lamikhov-Center
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef ELFIO_DYNAMIC_HPP
#define ELFIO_DYNAMIC_HPP
#include <algorithm>
namespace ELFIO {
//------------------------------------------------------------------------------
// Template class for accessing dynamic sections
template <class S> class dynamic_section_accessor_template
{
public:
//------------------------------------------------------------------------------
// Constructor
explicit dynamic_section_accessor_template( const elfio& elf_file,
S* section )
: elf_file( elf_file ), dynamic_section( section ), entries_num( 0 )
{
}
//------------------------------------------------------------------------------
// Returns the number of entries in the dynamic section
Elf_Xword get_entries_num() const
{
size_t needed_entry_size = -1;
if ( elf_file.get_class() == ELFCLASS32 ) {
needed_entry_size = sizeof( Elf32_Dyn );
}
else {
needed_entry_size = sizeof( Elf64_Dyn );
}
if ( ( 0 == entries_num ) &&
( 0 != dynamic_section->get_entry_size() &&
dynamic_section->get_entry_size() >= needed_entry_size ) ) {
entries_num =
dynamic_section->get_size() / dynamic_section->get_entry_size();
Elf_Xword i;
Elf_Xword tag = DT_NULL;
Elf_Xword value = 0;
std::string str;
for ( i = 0; i < entries_num; i++ ) {
get_entry( i, tag, value, str );
if ( tag == DT_NULL )
break;
}
entries_num = std::min<Elf_Xword>( entries_num, i + 1 );
}
return entries_num;
}
//------------------------------------------------------------------------------
// Retrieves an entry from the dynamic section
bool get_entry( Elf_Xword index,
Elf_Xword& tag,
Elf_Xword& value,
std::string& str ) const
{
if ( index >= get_entries_num() ) { // Is index valid
return false;
}
if ( elf_file.get_class() == ELFCLASS32 ) {
generic_get_entry_dyn<Elf32_Dyn>( index, tag, value );
}
else {
generic_get_entry_dyn<Elf64_Dyn>( index, tag, value );
}
// If the tag has a string table reference - prepare the string
if ( tag == DT_NEEDED || tag == DT_SONAME || tag == DT_RPATH ||
tag == DT_RUNPATH ) {
string_section_accessor strsec(
elf_file.sections[get_string_table_index()] );
const char* result = strsec.get_string( (Elf_Word)value );
if ( nullptr == result ) {
str.clear();
return false;
}
str = result;
}
else {
str.clear();
}
return true;
}
//------------------------------------------------------------------------------
// Adds an entry to the dynamic section
void add_entry( Elf_Xword tag, Elf_Xword value )
{
if ( elf_file.get_class() == ELFCLASS32 ) {
generic_add_entry_dyn<Elf32_Dyn>( tag, value );
}
else {
generic_add_entry_dyn<Elf64_Dyn>( tag, value );
}
}
//------------------------------------------------------------------------------
// Adds an entry with a string value to the dynamic section
void add_entry( Elf_Xword tag, const std::string& str )
{
string_section_accessor strsec(
elf_file.sections[get_string_table_index()] );
Elf_Xword value = strsec.add_string( str );
add_entry( tag, value );
}
private:
//------------------------------------------------------------------------------
// Returns the index of the string table
Elf_Half get_string_table_index() const
{
return (Elf_Half)dynamic_section->get_link();
}
//------------------------------------------------------------------------------
// Retrieves a generic entry from the dynamic section
template <class T>
void generic_get_entry_dyn( Elf_Xword index,
Elf_Xword& tag,
Elf_Xword& value ) const
{
const auto& convertor = elf_file.get_convertor();
// Check unusual case when dynamic section has no data
if ( dynamic_section->get_data() == nullptr ||
dynamic_section->get_entry_size() < sizeof( T ) ) {
tag = DT_NULL;
value = 0;
return;
}
// Check for integer overflow in size calculation
if ( index > ( dynamic_section->get_size() /
dynamic_section->get_entry_size() ) -
1 ) {
tag = DT_NULL;
value = 0;
return;
}
// Check for integer overflow in pointer arithmetic
Elf_Xword offset = index * dynamic_section->get_entry_size();
if ( offset > dynamic_section->get_size() - sizeof( T ) ) {
tag = DT_NULL;
value = 0;
return;
}
const T* pEntry =
reinterpret_cast<const T*>( dynamic_section->get_data() + offset );
tag = ( *convertor )( pEntry->d_tag );
switch ( tag ) {
case DT_NULL:
case DT_SYMBOLIC:
case DT_TEXTREL:
case DT_BIND_NOW:
value = 0;
break;
case DT_NEEDED:
case DT_PLTRELSZ:
case DT_RELASZ:
case DT_RELAENT:
case DT_STRSZ:
case DT_SYMENT:
case DT_SONAME:
case DT_RPATH:
case DT_RELSZ:
case DT_RELENT:
case DT_PLTREL:
case DT_INIT_ARRAYSZ:
case DT_FINI_ARRAYSZ:
case DT_RUNPATH:
case DT_FLAGS:
case DT_PREINIT_ARRAYSZ:
value = ( *convertor )( pEntry->d_un.d_val );
break;
case DT_PLTGOT:
case DT_HASH:
case DT_STRTAB:
case DT_SYMTAB:
case DT_RELA:
case DT_INIT:
case DT_FINI:
case DT_REL:
case DT_DEBUG:
case DT_JMPREL:
case DT_INIT_ARRAY:
case DT_FINI_ARRAY:
case DT_PREINIT_ARRAY:
default:
value = ( *convertor )( pEntry->d_un.d_ptr );
break;
}
}
//------------------------------------------------------------------------------
// Adds a generic entry to the dynamic section
template <class T>
void generic_add_entry_dyn( Elf_Xword tag, Elf_Xword value )
{
const auto& convertor = elf_file.get_convertor();
T entry;
switch ( tag ) {
case DT_NULL:
case DT_SYMBOLIC:
case DT_TEXTREL:
case DT_BIND_NOW:
entry.d_un.d_val =
( *convertor )( decltype( entry.d_un.d_val )( 0 ) );
break;
case DT_NEEDED:
case DT_PLTRELSZ:
case DT_RELASZ:
case DT_RELAENT:
case DT_STRSZ:
case DT_SYMENT:
case DT_SONAME:
case DT_RPATH:
case DT_RELSZ:
case DT_RELENT:
case DT_PLTREL:
case DT_INIT_ARRAYSZ:
case DT_FINI_ARRAYSZ:
case DT_RUNPATH:
case DT_FLAGS:
case DT_PREINIT_ARRAYSZ:
entry.d_un.d_val =
( *convertor )( decltype( entry.d_un.d_val )( value ) );
break;
case DT_PLTGOT:
case DT_HASH:
case DT_STRTAB:
case DT_SYMTAB:
case DT_RELA:
case DT_INIT:
case DT_FINI:
case DT_REL:
case DT_DEBUG:
case DT_JMPREL:
case DT_INIT_ARRAY:
case DT_FINI_ARRAY:
case DT_PREINIT_ARRAY:
default:
entry.d_un.d_ptr =
( *convertor )( decltype( entry.d_un.d_val )( value ) );
break;
}
entry.d_tag = ( *convertor )( decltype( entry.d_tag )( tag ) );
dynamic_section->append_data( reinterpret_cast<char*>( &entry ),
sizeof( entry ) );
}
private:
// Reference to the ELF file
const elfio& elf_file;
// Pointer to the dynamic section
S* dynamic_section;
// Number of entries in the dynamic section
mutable Elf_Xword entries_num;
};
// Type aliases for dynamic section accessors
using dynamic_section_accessor = dynamic_section_accessor_template<section>;
using const_dynamic_section_accessor =
dynamic_section_accessor_template<const section>;
} // namespace ELFIO
#endif // ELFIO_DYNAMIC_HPP

View File

@ -0,0 +1,192 @@
/*
Copyright (C) 2001-present by Serge Lamikhov-Center
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef ELF_HEADER_HPP
#define ELF_HEADER_HPP
#include <iostream>
namespace ELFIO {
/**
* @class elf_header
* @brief Abstract base class for ELF header.
*/
class elf_header
{
public:
/**
* @brief Virtual destructor.
*/
virtual ~elf_header() = default;
/**
* @brief Load ELF header from stream.
* @param stream Input stream.
* @return True if successful, false otherwise.
*/
virtual bool load( std::istream& stream ) = 0;
/**
* @brief Save ELF header to stream.
* @param stream Output stream.
* @return True if successful, false otherwise.
*/
virtual bool save( std::ostream& stream ) const = 0;
// ELF header functions
ELFIO_GET_ACCESS_DECL( unsigned char, class );
ELFIO_GET_ACCESS_DECL( unsigned char, elf_version );
ELFIO_GET_ACCESS_DECL( unsigned char, encoding );
ELFIO_GET_ACCESS_DECL( Elf_Half, header_size );
ELFIO_GET_ACCESS_DECL( Elf_Half, section_entry_size );
ELFIO_GET_ACCESS_DECL( Elf_Half, segment_entry_size );
ELFIO_GET_SET_ACCESS_DECL( Elf_Word, version );
ELFIO_GET_SET_ACCESS_DECL( unsigned char, os_abi );
ELFIO_GET_SET_ACCESS_DECL( unsigned char, abi_version );
ELFIO_GET_SET_ACCESS_DECL( Elf_Half, type );
ELFIO_GET_SET_ACCESS_DECL( Elf_Half, machine );
ELFIO_GET_SET_ACCESS_DECL( Elf_Word, flags );
ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, entry );
ELFIO_GET_SET_ACCESS_DECL( Elf_Half, sections_num );
ELFIO_GET_SET_ACCESS_DECL( Elf64_Off, sections_offset );
ELFIO_GET_SET_ACCESS_DECL( Elf_Half, segments_num );
ELFIO_GET_SET_ACCESS_DECL( Elf64_Off, segments_offset );
ELFIO_GET_SET_ACCESS_DECL( Elf_Half, section_name_str_index );
};
/**
* @struct elf_header_impl_types
* @brief Template specialization for ELF header implementation types.
*/
template <class T> struct elf_header_impl_types;
template <> struct elf_header_impl_types<Elf32_Ehdr>
{
using Phdr_type = Elf32_Phdr;
using Shdr_type = Elf32_Shdr;
static const unsigned char file_class = ELFCLASS32;
};
template <> struct elf_header_impl_types<Elf64_Ehdr>
{
using Phdr_type = Elf64_Phdr;
using Shdr_type = Elf64_Shdr;
static const unsigned char file_class = ELFCLASS64;
};
/**
* @class elf_header_impl
* @brief Template class for ELF header implementation.
*/
template <class T> class elf_header_impl : public elf_header
{
public:
/**
* @brief Constructor.
* @param convertor Endianness convertor.
* @param encoding Encoding type.
* @param translator Address translator.
*/
elf_header_impl( std::shared_ptr<endianness_convertor> convertor,
unsigned char encoding,
std::shared_ptr<address_translator> translator )
: convertor( convertor ), translator( translator )
{
header.e_ident[EI_MAG0] = ELFMAG0;
header.e_ident[EI_MAG1] = ELFMAG1;
header.e_ident[EI_MAG2] = ELFMAG2;
header.e_ident[EI_MAG3] = ELFMAG3;
header.e_ident[EI_CLASS] = elf_header_impl_types<T>::file_class;
header.e_ident[EI_DATA] = encoding;
header.e_ident[EI_VERSION] = EV_CURRENT;
header.e_version = ( *convertor )( (Elf_Word)EV_CURRENT );
header.e_ehsize = ( sizeof( header ) );
header.e_ehsize = ( *convertor )( header.e_ehsize );
header.e_shstrndx = ( *convertor )( (Elf_Half)1 );
header.e_phentsize =
sizeof( typename elf_header_impl_types<T>::Phdr_type );
header.e_shentsize =
sizeof( typename elf_header_impl_types<T>::Shdr_type );
header.e_phentsize = ( *convertor )( header.e_phentsize );
header.e_shentsize = ( *convertor )( header.e_shentsize );
}
/**
* @brief Load ELF header from stream.
* @param stream Input stream.
* @return True if successful, false otherwise.
*/
bool load( std::istream& stream ) override
{
stream.seekg( ( *translator )[0] );
stream.read( reinterpret_cast<char*>( &header ), sizeof( header ) );
return ( stream.gcount() == sizeof( header ) );
}
/**
* @brief Save ELF header to stream.
* @param stream Output stream.
* @return True if successful, false otherwise.
*/
bool save( std::ostream& stream ) const override
{
stream.seekp( ( *translator )[0] );
stream.write( reinterpret_cast<const char*>( &header ),
sizeof( header ) );
return stream.good();
}
//------------------------------------------------------------------------------
// ELF header functions
ELFIO_GET_ACCESS( unsigned char, class, header.e_ident[EI_CLASS] );
ELFIO_GET_ACCESS( unsigned char, elf_version, header.e_ident[EI_VERSION] );
ELFIO_GET_ACCESS( unsigned char, encoding, header.e_ident[EI_DATA] );
ELFIO_GET_ACCESS( Elf_Half, header_size, header.e_ehsize );
ELFIO_GET_ACCESS( Elf_Half, section_entry_size, header.e_shentsize );
ELFIO_GET_ACCESS( Elf_Half, segment_entry_size, header.e_phentsize );
ELFIO_GET_SET_ACCESS( Elf_Word, version, header.e_version );
ELFIO_GET_SET_ACCESS( unsigned char, os_abi, header.e_ident[EI_OSABI] );
ELFIO_GET_SET_ACCESS( unsigned char,
abi_version,
header.e_ident[EI_ABIVERSION] );
ELFIO_GET_SET_ACCESS( Elf_Half, type, header.e_type );
ELFIO_GET_SET_ACCESS( Elf_Half, machine, header.e_machine );
ELFIO_GET_SET_ACCESS( Elf_Word, flags, header.e_flags );
ELFIO_GET_SET_ACCESS( Elf_Half, section_name_str_index, header.e_shstrndx );
ELFIO_GET_SET_ACCESS( Elf64_Addr, entry, header.e_entry );
ELFIO_GET_SET_ACCESS( Elf_Half, sections_num, header.e_shnum );
ELFIO_GET_SET_ACCESS( Elf64_Off, sections_offset, header.e_shoff );
ELFIO_GET_SET_ACCESS( Elf_Half, segments_num, header.e_phnum );
ELFIO_GET_SET_ACCESS( Elf64_Off, segments_offset, header.e_phoff );
private:
T header = {};
std::shared_ptr<endianness_convertor> convertor = nullptr;
std::shared_ptr<address_translator> translator = nullptr;
};
} // namespace ELFIO
#endif // ELF_HEADER_HPP

View File

@ -0,0 +1,168 @@
/*
Copyright (C) 2001-present by Serge Lamikhov-Center
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef ELFIO_MODINFO_HPP
#define ELFIO_MODINFO_HPP
#include <string_view>
#include <vector>
namespace ELFIO {
//------------------------------------------------------------------------------
/**
* @class modinfo_section_accessor_template
* @brief A template class to access modinfo section.
*
* @tparam S The section type.
*/
template <class S> class modinfo_section_accessor_template
{
public:
//------------------------------------------------------------------------------
/**
* @brief Construct a new modinfo section accessor template object.
*
* @param section The section to be accessed.
*/
explicit modinfo_section_accessor_template( S* section )
: modinfo_section( section )
{
process_section();
}
//------------------------------------------------------------------------------
/**
* @brief Get the number of attributes.
*
* @return Elf_Word The number of attributes.
*/
Elf_Word get_attribute_num() const { return (Elf_Word)content.size(); }
//------------------------------------------------------------------------------
/**
* @brief Get the attribute by index.
*
* @param no The index of the attribute.
* @param field The field name of the attribute.
* @param value The value of the attribute.
* @return true If the attribute is found.
* @return false If the attribute is not found.
*/
bool
get_attribute( Elf_Word no, std::string& field, std::string& value ) const
{
if ( no < content.size() ) {
field = content[no].first;
value = content[no].second;
return true;
}
return false;
}
//------------------------------------------------------------------------------
/**
* @brief Get the attribute by field name.
*
* @param field_name The field name of the attribute.
* @param value The value of the attribute.
* @return true If the attribute is found.
* @return false If the attribute is not found.
*/
bool get_attribute( const std::string_view& field_name,
std::string& value ) const
{
for ( const auto& [first, second] : content ) {
if ( field_name == first ) {
value = second;
return true;
}
}
return false;
}
//------------------------------------------------------------------------------
/**
* @brief Add a new attribute.
*
* @param field The field name of the attribute.
* @param value The value of the attribute.
* @return Elf_Word The position of the new attribute.
*/
Elf_Word add_attribute( const std::string& field, const std::string& value )
{
Elf_Word current_position = 0;
if ( modinfo_section ) {
// Strings are addeded to the end of the current section data
current_position = (Elf_Word)modinfo_section->get_size();
std::string attribute = field + "=" + value;
modinfo_section->append_data( attribute + '\0' );
content.emplace_back( field, value );
}
return current_position;
}
//------------------------------------------------------------------------------
private:
/**
* @brief Process the section to extract attributes.
*/
void process_section()
{
const char* pdata = modinfo_section->get_data();
if ( pdata ) {
ELFIO::Elf_Xword i = 0;
while ( i < modinfo_section->get_size() ) {
while ( i < modinfo_section->get_size() && !pdata[i] )
i++;
if ( i < modinfo_section->get_size() ) {
std::string info = pdata + i;
size_t loc = info.find( '=' );
content.emplace_back( info.substr( 0, loc ),
info.substr( loc + 1 ) );
i += info.length();
}
}
}
}
//------------------------------------------------------------------------------
private:
S* modinfo_section; ///< The section to be accessed.
std::vector<std::pair<std::string, std::string>>
content; ///< The list of attributes.
};
using modinfo_section_accessor = modinfo_section_accessor_template<section>;
using const_modinfo_section_accessor =
modinfo_section_accessor_template<const section>;
} // namespace ELFIO
#endif // ELFIO_MODINFO_HPP

View File

@ -0,0 +1,208 @@
/*
Copyright (C) 2001-present by Serge Lamikhov-Center
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef ELFIO_NOTE_HPP
#define ELFIO_NOTE_HPP
namespace ELFIO {
//------------------------------------------------------------------------------
// There are discrepancies in documentations. SCO documentation
// (http://www.sco.com/developers/gabi/latest/ch5.pheader.html#note_section)
// requires 8 byte entries alignment for 64-bit ELF file,
// but Oracle's definition uses the same structure
// for 32-bit and 64-bit formats.
// (https://docs.oracle.com/cd/E23824_01/html/819-0690/chapter6-18048.html)
//
// It looks like EM_X86_64 Linux implementation is similar to Oracle's
// definition. Therefore, the same alignment works for both formats
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
//! \class note_section_accessor_template
//! \brief Class for accessing note section data
template <class S, Elf_Xword ( S::*F_get_size )() const>
class note_section_accessor_template
{
public:
//------------------------------------------------------------------------------
//! \brief Constructor
//! \param elf_file Reference to the ELF file
//! \param section Pointer to the section
explicit note_section_accessor_template( const elfio& elf_file, S* section )
: elf_file( elf_file ), notes( section )
{
process_section();
}
//------------------------------------------------------------------------------
//! \brief Get the number of notes
//! \return Number of notes
Elf_Word get_notes_num() const
{
return (Elf_Word)note_start_positions.size();
}
//------------------------------------------------------------------------------
//! \brief Get a note
//! \param index Index of the note
//! \param type Type of the note
//! \param name Name of the note
//! \param desc Pointer to the descriptor
//! \param descSize Size of the descriptor
//! \return True if successful, false otherwise
bool get_note( Elf_Word index,
Elf_Word& type,
std::string& name,
char*& desc,
Elf_Word& descSize ) const
{
if ( index >= ( notes->*F_get_size )() ) {
return false;
}
const char* pData = notes->get_data() + note_start_positions[index];
int align = sizeof( Elf_Word );
const auto& convertor = elf_file.get_convertor();
type =
( *convertor )( *(const Elf_Word*)( pData + 2 * (size_t)align ) );
Elf_Word namesz = ( *convertor )( *(const Elf_Word*)( pData ) );
descSize =
( *convertor )( *(const Elf_Word*)( pData + sizeof( namesz ) ) );
Elf_Xword max_name_size =
( notes->*F_get_size )() - note_start_positions[index];
if ( namesz < 1 || namesz > max_name_size ||
(Elf_Xword)namesz + descSize > max_name_size ) {
return false;
}
name.assign( pData + 3 * (size_t)align, namesz - 1 );
if ( 0 == descSize ) {
desc = nullptr;
}
else {
desc = const_cast<char*>( pData + 3 * (size_t)align +
( ( namesz + align - 1 ) / align ) *
(size_t)align );
}
return true;
}
//------------------------------------------------------------------------------
//! \brief Add a note
//! \param type Type of the note
//! \param name Name of the note
//! \param desc Pointer to the descriptor
//! \param descSize Size of the descriptor
void add_note( Elf_Word type,
const std::string& name,
const char* desc,
Elf_Word descSize )
{
const auto& convertor = elf_file.get_convertor();
int align = sizeof( Elf_Word );
Elf_Word nameLen = (Elf_Word)name.size() + 1;
Elf_Word nameLenConv = ( *convertor )( nameLen );
std::string buffer( reinterpret_cast<char*>( &nameLenConv ), align );
Elf_Word descSizeConv = ( *convertor )( descSize );
buffer.append( reinterpret_cast<char*>( &descSizeConv ), align );
type = ( *convertor )( type );
buffer.append( reinterpret_cast<char*>( &type ), align );
buffer.append( name );
buffer.append( 1, '\x00' );
const char pad[] = { '\0', '\0', '\0', '\0' };
if ( nameLen % align != 0 ) {
buffer.append( pad, (size_t)align - nameLen % align );
}
if ( desc != nullptr && descSize != 0 ) {
buffer.append( desc, descSize );
if ( descSize % align != 0 ) {
buffer.append( pad, (size_t)align - descSize % align );
}
}
note_start_positions.emplace_back( ( notes->*F_get_size )() );
notes->append_data( buffer );
}
private:
//------------------------------------------------------------------------------
//! \brief Process the section to extract note start positions
void process_section()
{
const auto& convertor = elf_file.get_convertor();
const char* data = notes->get_data();
Elf_Xword size = ( notes->*F_get_size )();
Elf_Xword current = 0;
note_start_positions.clear();
// Is it empty?
if ( nullptr == data || 0 == size ) {
return;
}
Elf_Word align = sizeof( Elf_Word );
while ( current + (Elf_Xword)3 * align <= size ) {
Elf_Word namesz =
( *convertor )( *(const Elf_Word*)( data + current ) );
Elf_Word descsz = ( *convertor )(
*(const Elf_Word*)( data + current + sizeof( namesz ) ) );
Elf_Word advance =
(Elf_Xword)3 * sizeof( Elf_Word ) +
( ( namesz + align - 1 ) / align ) * (Elf_Xword)align +
( ( descsz + align - 1 ) / align ) * (Elf_Xword)align;
if ( namesz < size && descsz < size && current + advance <= size ) {
note_start_positions.emplace_back( current );
}
else {
break;
}
current += advance;
}
}
//------------------------------------------------------------------------------
private:
const elfio& elf_file; //!< Reference to the ELF file
S* notes; //!< Pointer to the section or segment
std::vector<Elf_Xword>
note_start_positions; //!< Vector of note start positions
};
using note_section_accessor =
note_section_accessor_template<section, &section::get_size>;
using const_note_section_accessor =
note_section_accessor_template<const section, &section::get_size>;
using note_segment_accessor =
note_section_accessor_template<segment, &segment::get_file_size>;
using const_note_segment_accessor =
note_section_accessor_template<const segment, &segment::get_file_size>;
} // namespace ELFIO
#endif // ELFIO_NOTE_HPP

View File

@ -0,0 +1,596 @@
/*
Copyright (C) 2001-present by Serge Lamikhov-Center
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef ELFIO_RELOCATION_HPP
#define ELFIO_RELOCATION_HPP
namespace ELFIO {
template <typename T> struct get_sym_and_type;
template <> struct get_sym_and_type<Elf32_Rel>
{
//------------------------------------------------------------------------------
//! \brief Get the symbol from the relocation info
//! \param info Relocation info
//! \return Symbol
static int get_r_sym( Elf_Xword info )
{
return ELF32_R_SYM( (Elf_Word)info );
}
//------------------------------------------------------------------------------
//! \brief Get the type from the relocation info
//! \param info Relocation info
//! \return Type
static int get_r_type( Elf_Xword info )
{
return ELF32_R_TYPE( (Elf_Word)info );
}
};
template <> struct get_sym_and_type<Elf32_Rela>
{
//------------------------------------------------------------------------------
//! \brief Get the symbol from the relocation info
//! \param info Relocation info
//! \return Symbol
static int get_r_sym( Elf_Xword info )
{
return ELF32_R_SYM( (Elf_Word)info );
}
//------------------------------------------------------------------------------
//! \brief Get the type from the relocation info
//! \param info Relocation info
//! \return Type
static int get_r_type( Elf_Xword info )
{
return ELF32_R_TYPE( (Elf_Word)info );
}
};
template <> struct get_sym_and_type<Elf64_Rel>
{
//------------------------------------------------------------------------------
//! \brief Get the symbol from the relocation info
//! \param info Relocation info
//! \return Symbol
static int get_r_sym( Elf_Xword info ) { return ELF64_R_SYM( info ); }
//------------------------------------------------------------------------------
//! \brief Get the type from the relocation info
//! \param info Relocation info
//! \return Type
static int get_r_type( Elf_Xword info ) { return ELF64_R_TYPE( info ); }
};
template <> struct get_sym_and_type<Elf64_Rela>
{
//------------------------------------------------------------------------------
//! \brief Get the symbol from the relocation info
//! \param info Relocation info
//! \return Symbol
static int get_r_sym( Elf_Xword info ) { return ELF64_R_SYM( info ); }
//------------------------------------------------------------------------------
//! \brief Get the type from the relocation info
//! \param info Relocation info
//! \return Type
static int get_r_type( Elf_Xword info ) { return ELF64_R_TYPE( info ); }
};
//------------------------------------------------------------------------------
//! \class relocation_section_accessor_template
//! \brief Class for accessing relocation section data
template <class S> class relocation_section_accessor_template
{
public:
//------------------------------------------------------------------------------
//! \brief Constructor
//! \param elf_file Reference to the ELF file
//! \param section Pointer to the section
explicit relocation_section_accessor_template( const elfio& elf_file,
S* section )
: elf_file( elf_file ), relocation_section( section )
{
}
//------------------------------------------------------------------------------
//! \brief Get the number of entries
//! \return Number of entries
Elf_Xword get_entries_num() const
{
Elf_Xword nRet = 0;
if ( 0 != relocation_section->get_entry_size() ) {
nRet = relocation_section->get_size() /
relocation_section->get_entry_size();
}
return nRet;
}
//------------------------------------------------------------------------------
//! \brief Get an entry
//! \param index Index of the entry
//! \param offset Offset of the entry
//! \param symbol Symbol of the entry
//! \param type Type of the entry
//! \param addend Addend of the entry
//! \return True if successful, false otherwise
bool get_entry( Elf_Xword index,
Elf64_Addr& offset,
Elf_Word& symbol,
unsigned& type,
Elf_Sxword& addend ) const
{
if ( index >= get_entries_num() ) { // Is index valid
return false;
}
if ( elf_file.get_class() == ELFCLASS32 ) {
if ( SHT_REL == relocation_section->get_type() ) {
return generic_get_entry_rel<Elf32_Rel>( index, offset, symbol,
type, addend );
}
else if ( SHT_RELA == relocation_section->get_type() ) {
return generic_get_entry_rela<Elf32_Rela>(
index, offset, symbol, type, addend );
}
}
else {
if ( SHT_REL == relocation_section->get_type() ) {
return generic_get_entry_rel<Elf64_Rel>( index, offset, symbol,
type, addend );
}
else if ( SHT_RELA == relocation_section->get_type() ) {
return generic_get_entry_rela<Elf64_Rela>(
index, offset, symbol, type, addend );
}
}
// Unknown relocation section type.
return false;
}
//------------------------------------------------------------------------------
//! \brief Get an entry with additional information
//! \param index Index of the entry
//! \param offset Offset of the entry
//! \param symbolValue Value of the symbol
//! \param symbolName Name of the symbol
//! \param type Type of the entry
//! \param addend Addend of the entry
//! \param calcValue Calculated value
//! \return True if successful, false otherwise
bool get_entry( Elf_Xword index,
Elf64_Addr& offset,
Elf64_Addr& symbolValue,
std::string& symbolName,
unsigned& type,
Elf_Sxword& addend,
Elf_Sxword& calcValue ) const
{
// Do regular job
Elf_Word symbol = 0;
bool ret = get_entry( index, offset, symbol, type, addend );
// Find the symbol
Elf_Xword size;
unsigned char bind;
unsigned char symbolType;
Elf_Half section;
unsigned char other;
symbol_section_accessor symbols(
elf_file, elf_file.sections[get_symbol_table_index()] );
ret = ret && symbols.get_symbol( symbol, symbolName, symbolValue, size,
bind, symbolType, section, other );
if ( ret ) { // Was it successful?
switch ( type ) {
case R_386_NONE: // none
calcValue = 0;
break;
case R_386_32: // S + A
calcValue = symbolValue + addend;
break;
case R_386_PC32: // S + A - P
calcValue = symbolValue + addend - offset;
break;
case R_386_GOT32: // G + A - P
calcValue = 0;
break;
case R_386_PLT32: // L + A - P
calcValue = 0;
break;
case R_386_COPY: // none
calcValue = 0;
break;
case R_386_GLOB_DAT: // S
case R_386_JMP_SLOT: // S
calcValue = symbolValue;
break;
case R_386_RELATIVE: // B + A
calcValue = addend;
break;
case R_386_GOTOFF: // S + A - GOT
calcValue = 0;
break;
case R_386_GOTPC: // GOT + A - P
calcValue = 0;
break;
default: // Not recognized symbol!
calcValue = 0;
break;
}
}
return ret;
}
//------------------------------------------------------------------------------
//! \brief Set an entry
//! \param index Index of the entry
//! \param offset Offset of the entry
//! \param symbol Symbol of the entry
//! \param type Type of the entry
//! \param addend Addend of the entry
//! \return True if successful, false otherwise
bool set_entry( Elf_Xword index,
Elf64_Addr offset,
Elf_Word symbol,
unsigned type,
Elf_Sxword addend )
{
if ( index >= get_entries_num() ) { // Is index valid
return false;
}
if ( elf_file.get_class() == ELFCLASS32 ) {
if ( SHT_REL == relocation_section->get_type() ) {
generic_set_entry_rel<Elf32_Rel>( index, offset, symbol, type,
addend );
}
else if ( SHT_RELA == relocation_section->get_type() ) {
generic_set_entry_rela<Elf32_Rela>( index, offset, symbol, type,
addend );
}
}
else {
if ( SHT_REL == relocation_section->get_type() ) {
generic_set_entry_rel<Elf64_Rel>( index, offset, symbol, type,
addend );
}
else if ( SHT_RELA == relocation_section->get_type() ) {
generic_set_entry_rela<Elf64_Rela>( index, offset, symbol, type,
addend );
}
}
return true;
}
//------------------------------------------------------------------------------
//! \brief Add an entry
//! \param offset Offset of the entry
//! \param info Information of the entry
void add_entry( Elf64_Addr offset, Elf_Xword info )
{
if ( elf_file.get_class() == ELFCLASS32 ) {
generic_add_entry<Elf32_Rel>( offset, info );
}
else {
generic_add_entry<Elf64_Rel>( offset, info );
}
}
//------------------------------------------------------------------------------
//! \brief Add an entry
//! \param offset Offset of the entry
//! \param symbol Symbol of the entry
//! \param type Type of the entry
void add_entry( Elf64_Addr offset, Elf_Word symbol, unsigned type )
{
Elf_Xword info;
if ( elf_file.get_class() == ELFCLASS32 ) {
info = ELF32_R_INFO( (Elf_Xword)symbol, type );
}
else {
info = ELF64_R_INFO( (Elf_Xword)symbol, type );
}
add_entry( offset, info );
}
//------------------------------------------------------------------------------
//! \brief Add an entry
//! \param offset Offset of the entry
//! \param info Information of the entry
//! \param addend Addend of the entry
void add_entry( Elf64_Addr offset, Elf_Xword info, Elf_Sxword addend )
{
if ( elf_file.get_class() == ELFCLASS32 ) {
generic_add_entry<Elf32_Rela>( offset, info, addend );
}
else {
generic_add_entry<Elf64_Rela>( offset, info, addend );
}
}
//------------------------------------------------------------------------------
//! \brief Add an entry
//! \param offset Offset of the entry
//! \param symbol Symbol of the entry
//! \param type Type of the entry
//! \param addend Addend of the entry
void add_entry( Elf64_Addr offset,
Elf_Word symbol,
unsigned type,
Elf_Sxword addend )
{
Elf_Xword info;
if ( elf_file.get_class() == ELFCLASS32 ) {
info = ELF32_R_INFO( (Elf_Xword)symbol, type );
}
else {
info = ELF64_R_INFO( (Elf_Xword)symbol, type );
}
add_entry( offset, info, addend );
}
//------------------------------------------------------------------------------
//! \brief Add an entry with additional information
//! \param str_writer String section accessor
//! \param str String
//! \param sym_writer Symbol section accessor
//! \param value Value of the symbol
//! \param size Size of the symbol
//! \param sym_info Symbol information
//! \param other Other information
//! \param shndx Section index
//! \param offset Offset of the entry
//! \param type Type of the entry
void add_entry( string_section_accessor str_writer,
const char* str,
symbol_section_accessor sym_writer,
Elf64_Addr value,
Elf_Word size,
unsigned char sym_info,
unsigned char other,
Elf_Half shndx,
Elf64_Addr offset,
unsigned type )
{
Elf_Word str_index = str_writer.add_string( str );
Elf_Word sym_index = sym_writer.add_symbol( str_index, value, size,
sym_info, other, shndx );
add_entry( offset, sym_index, type );
}
//------------------------------------------------------------------------------
//! \brief Swap symbols
//! \param first First symbol
//! \param second Second symbol
void swap_symbols( Elf_Xword first, Elf_Xword second )
{
Elf64_Addr offset = 0;
Elf_Word symbol = 0;
unsigned rtype = 0;
Elf_Sxword addend = 0;
for ( Elf_Word i = 0; i < get_entries_num(); i++ ) {
get_entry( i, offset, symbol, rtype, addend );
if ( symbol == first ) {
set_entry( i, offset, (Elf_Word)second, rtype, addend );
}
if ( symbol == second ) {
set_entry( i, offset, (Elf_Word)first, rtype, addend );
}
}
}
//------------------------------------------------------------------------------
private:
//------------------------------------------------------------------------------
//! \brief Get the symbol table index
//! \return Symbol table index
Elf_Half get_symbol_table_index() const
{
return (Elf_Half)relocation_section->get_link();
}
//------------------------------------------------------------------------------
//! \brief Get a generic entry for REL type
//! \param index Index of the entry
//! \param offset Offset of the entry
//! \param symbol Symbol of the entry
//! \param type Type of the entry
//! \param addend Addend of the entry
//! \return True if successful, false otherwise
template <class T>
bool generic_get_entry_rel( Elf_Xword index,
Elf64_Addr& offset,
Elf_Word& symbol,
unsigned& type,
Elf_Sxword& addend ) const
{
const auto& convertor = elf_file.get_convertor();
if ( relocation_section->get_entry_size() < sizeof( T ) ) {
return false;
}
const T* pEntry = reinterpret_cast<const T*>(
relocation_section->get_data() +
index * relocation_section->get_entry_size() );
offset = ( *convertor )( pEntry->r_offset );
Elf_Xword tmp = ( *convertor )( pEntry->r_info );
symbol = get_sym_and_type<T>::get_r_sym( tmp );
type = get_sym_and_type<T>::get_r_type( tmp );
addend = 0;
return true;
}
//------------------------------------------------------------------------------
//! \brief Get a generic entry for RELA type
//! \param index Index of the entry
//! \param offset Offset of the entry
//! \param symbol Symbol of the entry
//! \param type Type of the entry
//! \param addend Addend of the entry
//! \return True if successful, false otherwise
template <class T>
bool generic_get_entry_rela( Elf_Xword index,
Elf64_Addr& offset,
Elf_Word& symbol,
unsigned& type,
Elf_Sxword& addend ) const
{
const auto& convertor = elf_file.get_convertor();
if ( relocation_section->get_entry_size() < sizeof( T ) ) {
return false;
}
const T* pEntry = reinterpret_cast<const T*>(
relocation_section->get_data() +
index * relocation_section->get_entry_size() );
offset = ( *convertor )( pEntry->r_offset );
Elf_Xword tmp = ( *convertor )( pEntry->r_info );
symbol = get_sym_and_type<T>::get_r_sym( tmp );
type = get_sym_and_type<T>::get_r_type( tmp );
addend = ( *convertor )( pEntry->r_addend );
return true;
}
//------------------------------------------------------------------------------
//! \brief Set a generic entry for REL type
//! \param index Index of the entry
//! \param offset Offset of the entry
//! \param symbol Symbol of the entry
//! \param type Type of the entry
//! \param addend Addend of the entry
template <class T>
void generic_set_entry_rel( Elf_Xword index,
Elf64_Addr offset,
Elf_Word symbol,
unsigned type,
Elf_Sxword )
{
const auto& convertor = elf_file.get_convertor();
T* pEntry = const_cast<T*>( reinterpret_cast<const T*>(
relocation_section->get_data() +
index * relocation_section->get_entry_size() ) );
if ( elf_file.get_class() == ELFCLASS32 ) {
pEntry->r_info = ELF32_R_INFO( (Elf_Xword)symbol, type );
}
else {
pEntry->r_info = ELF64_R_INFO( (Elf_Xword)symbol, type );
}
pEntry->r_offset = decltype( pEntry->r_offset )( offset );
pEntry->r_offset = ( *convertor )( pEntry->r_offset );
pEntry->r_info = ( *convertor )( pEntry->r_info );
}
//------------------------------------------------------------------------------
//! \brief Set a generic entry for RELA type
//! \param index Index of the entry
//! \param offset Offset of the entry
//! \param symbol Symbol of the entry
//! \param type Type of the entry
//! \param addend Addend of the entry
template <class T>
void generic_set_entry_rela( Elf_Xword index,
Elf64_Addr offset,
Elf_Word symbol,
unsigned type,
Elf_Sxword addend )
{
const auto& convertor = elf_file.get_convertor();
T* pEntry = const_cast<T*>( reinterpret_cast<const T*>(
relocation_section->get_data() +
index * relocation_section->get_entry_size() ) );
if ( elf_file.get_class() == ELFCLASS32 ) {
pEntry->r_info = ELF32_R_INFO( (Elf_Xword)symbol, type );
}
else {
pEntry->r_info = ELF64_R_INFO( (Elf_Xword)symbol, type );
}
pEntry->r_offset = decltype( pEntry->r_offset )( offset );
pEntry->r_addend = decltype( pEntry->r_addend )( addend );
pEntry->r_offset = ( *convertor )( pEntry->r_offset );
pEntry->r_info = ( *convertor )( pEntry->r_info );
pEntry->r_addend = ( *convertor )( pEntry->r_addend );
}
//------------------------------------------------------------------------------
//! \brief Add a generic entry for REL type
//! \param offset Offset of the entry
//! \param info Information of the entry
template <class T>
void generic_add_entry( Elf64_Addr offset, Elf_Xword info )
{
const auto& convertor = elf_file.get_convertor();
T entry;
entry.r_offset = decltype( entry.r_offset )( offset );
entry.r_info = decltype( entry.r_info )( info );
entry.r_offset = ( *convertor )( entry.r_offset );
entry.r_info = ( *convertor )( entry.r_info );
relocation_section->append_data( reinterpret_cast<char*>( &entry ),
sizeof( entry ) );
}
//------------------------------------------------------------------------------
//! \brief Add a generic entry for RELA type
//! \param offset Offset of the entry
//! \param info Information of the entry
//! \param addend Addend of the entry
template <class T>
void
generic_add_entry( Elf64_Addr offset, Elf_Xword info, Elf_Sxword addend )
{
const auto& convertor = elf_file.get_convertor();
T entry;
entry.r_offset = offset;
entry.r_info = info;
entry.r_addend = addend;
entry.r_offset = ( *convertor )( entry.r_offset );
entry.r_info = ( *convertor )( entry.r_info );
entry.r_addend = ( *convertor )( entry.r_addend );
relocation_section->append_data( reinterpret_cast<char*>( &entry ),
sizeof( entry ) );
}
//------------------------------------------------------------------------------
private:
const elfio& elf_file;
S* relocation_section = nullptr;
};
using relocation_section_accessor =
relocation_section_accessor_template<section>;
using const_relocation_section_accessor =
relocation_section_accessor_template<const section>;
} // namespace ELFIO
#endif // ELFIO_RELOCATION_HPP

View File

@ -0,0 +1,611 @@
/*
Copyright (C) 2001-present by Serge Lamikhov-Center
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef ELFIO_SECTION_HPP
#define ELFIO_SECTION_HPP
#include <string>
#include <iostream>
#include <new>
#include <limits>
namespace ELFIO {
/**
* @class section
* @brief Represents a section in an ELF file.
*/
class section
{
friend class elfio;
public:
virtual ~section() = default;
ELFIO_GET_ACCESS_DECL( Elf_Half, index );
ELFIO_GET_SET_ACCESS_DECL( std::string, name );
ELFIO_GET_SET_ACCESS_DECL( Elf_Word, type );
ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, flags );
ELFIO_GET_SET_ACCESS_DECL( Elf_Word, info );
ELFIO_GET_SET_ACCESS_DECL( Elf_Word, link );
ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, addr_align );
ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, entry_size );
ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, address );
ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, size );
ELFIO_GET_SET_ACCESS_DECL( Elf_Word, name_string_offset );
ELFIO_GET_ACCESS_DECL( Elf64_Off, offset );
/**
* @brief Get the data of the section.
* @return Pointer to the data.
*/
virtual const char* get_data() const = 0;
/**
* @brief Free the data of the section.
*/
virtual void free_data() const = 0;
/**
* @brief Set the data of the section.
* @param raw_data Pointer to the raw data.
* @param size Size of the data.
*/
virtual void set_data( const char* raw_data, Elf_Xword size ) = 0;
/**
* @brief Set the data of the section.
* @param data String containing the data.
*/
virtual void set_data( const std::string& data ) = 0;
/**
* @brief Append data to the section.
* @param raw_data Pointer to the raw data.
* @param size Size of the data.
*/
virtual void append_data( const char* raw_data, Elf_Xword size ) = 0;
/**
* @brief Append data to the section.
* @param data String containing the data.
*/
virtual void append_data( const std::string& data ) = 0;
/**
* @brief Insert data into the section at a specific position.
* @param pos Position to insert the data.
* @param raw_data Pointer to the raw data.
* @param size Size of the data.
*/
virtual void
insert_data( Elf_Xword pos, const char* raw_data, Elf_Xword size ) = 0;
/**
* @brief Insert data into the section at a specific position.
* @param pos Position to insert the data.
* @param data String containing the data.
*/
virtual void insert_data( Elf_Xword pos, const std::string& data ) = 0;
/**
* @brief Get the size of the stream.
* @return Size of the stream.
*/
virtual size_t get_stream_size() const = 0;
/**
* @brief Set the size of the stream.
* @param value Size of the stream.
*/
virtual void set_stream_size( size_t value ) = 0;
protected:
ELFIO_SET_ACCESS_DECL( Elf64_Off, offset );
ELFIO_SET_ACCESS_DECL( Elf_Half, index );
/**
* @brief Load the section from a stream.
* @param stream Input stream.
* @param header_offset Offset of the header.
* @param is_lazy Whether to load lazily.
* @return True if successful, false otherwise.
*/
virtual bool load( std::istream& stream,
std::streampos header_offset,
bool is_lazy ) = 0;
/**
* @brief Save the section to a stream.
* @param stream Output stream.
* @param header_offset Offset of the header.
* @param data_offset Offset of the data.
*/
virtual void save( std::ostream& stream,
std::streampos header_offset,
std::streampos data_offset ) = 0;
/**
* @brief Check if the address is initialized.
* @return True if initialized, false otherwise.
*/
virtual bool is_address_initialized() const = 0;
};
/**
* @class section_impl
* @brief Implementation of the section class.
* @tparam T Type of the section header.
*/
template <class T> class section_impl : public section
{
public:
/**
* @brief Constructor.
* @param convertor Pointer to the endianness convertor.
* @param translator Pointer to the address translator.
* @param compression Shared pointer to the compression interface.
*/
section_impl( std::shared_ptr<endianness_convertor> convertor,
std::shared_ptr<address_translator> translator,
std::shared_ptr<compression_interface> compression )
: convertor( convertor ), translator( translator ),
compression( compression )
{
}
// Section info functions
ELFIO_GET_SET_ACCESS( Elf_Word, type, header.sh_type );
ELFIO_GET_SET_ACCESS( Elf_Xword, flags, header.sh_flags );
ELFIO_GET_SET_ACCESS( Elf_Xword, size, header.sh_size );
ELFIO_GET_SET_ACCESS( Elf_Word, link, header.sh_link );
ELFIO_GET_SET_ACCESS( Elf_Word, info, header.sh_info );
ELFIO_GET_SET_ACCESS( Elf_Xword, addr_align, header.sh_addralign );
ELFIO_GET_SET_ACCESS( Elf_Xword, entry_size, header.sh_entsize );
ELFIO_GET_SET_ACCESS( Elf_Word, name_string_offset, header.sh_name );
ELFIO_GET_ACCESS( Elf64_Addr, address, header.sh_addr );
/**
* @brief Get the index of the section.
* @return Index of the section.
*/
Elf_Half get_index() const override { return index; }
/**
* @brief Get the name of the section.
* @return Name of the section.
*/
std::string get_name() const override { return name; }
/**
* @brief Set the name of the section.
* @param name_prm Name of the section.
*/
void set_name( const std::string& name_prm ) override
{
this->name = name_prm;
}
/**
* @brief Set the address of the section.
* @param value Address of the section.
*/
void set_address( const Elf64_Addr& value ) override
{
header.sh_addr = decltype( header.sh_addr )( value );
header.sh_addr = ( *convertor )( header.sh_addr );
is_address_set = true;
}
/**
* @brief Check if the address is initialized.
* @return True if initialized, false otherwise.
*/
bool is_address_initialized() const override { return is_address_set; }
/**
* @brief Get the data of the section.
* @return Pointer to the data.
*/
const char* get_data() const override
{
// If data load failed, the stream is corrupt
// When lazy loading, attempts to call get_data() on it after initial load are useless
// When loading non-lazily, that load_data() will attempt to read data from
// the stream specified on load() call, which might be freed by this point
if ( !is_loaded && can_be_loaded ) {
bool res = load_data();
if ( !res ) {
can_be_loaded = false;
}
}
return data.get();
}
/**
* @brief Free the data of the section.
*/
void free_data() const override
{
if ( is_lazy ) {
data.reset( nullptr );
is_loaded = false;
}
}
/**
* @brief Set the data of the section.
* @param raw_data Pointer to the raw data.
* @param size Size of the data.
*/
void set_data( const char* raw_data, Elf_Xword size ) override
{
if ( get_type() != SHT_NOBITS ) {
data = std::unique_ptr<char[]>(
new ( std::nothrow ) char[(size_t)size] );
if ( nullptr != data.get() && nullptr != raw_data ) {
data_size = size;
std::copy( raw_data, raw_data + size, data.get() );
}
else {
data_size = 0;
}
}
set_size( data_size );
if ( translator->empty() ) {
set_stream_size( (size_t)data_size );
}
}
/**
* @brief Set the data of the section.
* @param str_data String containing the data.
*/
void set_data( const std::string& str_data ) override
{
return set_data( str_data.c_str(), (Elf_Word)str_data.size() );
}
/**
* @brief Append data to the section.
* @param raw_data Pointer to the raw data.
* @param size Size of the data.
*/
void append_data( const char* raw_data, Elf_Xword size ) override
{
insert_data( get_size(), raw_data, size );
}
/**
* @brief Append data to the section.
* @param str_data String containing the data.
*/
void append_data( const std::string& str_data ) override
{
return append_data( str_data.c_str(), (Elf_Word)str_data.size() );
}
/**
* @brief Insert data into the section at a specific position.
* @param pos Position to insert the data.
* @param raw_data Pointer to the raw data.
* @param size Size of the data.
*/
void
insert_data( Elf_Xword pos, const char* raw_data, Elf_Xword size ) override
{
if ( get_type() != SHT_NOBITS ) {
// Check for valid position
if ( pos > get_size() ) {
return; // Invalid position
}
// Check for integer overflow in size calculation
Elf_Xword new_size = get_size();
if ( size > std::numeric_limits<Elf_Xword>::max() - new_size ) {
return; // Size would overflow
}
new_size += size;
if ( new_size <= data_size ) {
char* d = data.get();
std::copy_backward( d + pos, d + get_size(),
d + get_size() + size );
std::copy( raw_data, raw_data + size, d + pos );
}
else {
// Calculate new size with overflow check
Elf_Xword new_data_size = data_size;
if ( new_data_size >
std::numeric_limits<Elf_Xword>::max() / 2 ) {
return; // Multiplication would overflow
}
new_data_size *= 2;
if ( size >
std::numeric_limits<Elf_Xword>::max() - new_data_size ) {
return; // Addition would overflow
}
new_data_size += size;
// Check if the size would overflow size_t
if ( new_data_size > std::numeric_limits<size_t>::max() ) {
return; // Size would overflow size_t
}
std::unique_ptr<char[]> new_data(
new ( std::nothrow ) char[(size_t)new_data_size] );
if ( nullptr != new_data ) {
char* d = data.get();
std::copy( d, d + pos, new_data.get() );
std::copy( raw_data, raw_data + size,
new_data.get() + pos );
std::copy( d + pos, d + get_size(),
new_data.get() + pos + size );
data = std::move( new_data );
data_size = new_data_size;
}
else {
return; // Allocation failed
}
}
set_size( new_size );
if ( translator->empty() ) {
set_stream_size( get_stream_size() + (size_t)size );
}
}
}
/**
* @brief Insert data into the section at a specific position.
* @param pos Position to insert the data.
* @param str_data String containing the data.
*/
void insert_data( Elf_Xword pos, const std::string& str_data ) override
{
return insert_data( pos, str_data.c_str(), (Elf_Word)str_data.size() );
}
/**
* @brief Get the size of the stream.
* @return Size of the stream.
*/
size_t get_stream_size() const override { return stream_size; }
/**
* @brief Set the size of the stream.
* @param value Size of the stream.
*/
void set_stream_size( size_t value ) override { stream_size = value; }
protected:
ELFIO_GET_SET_ACCESS( Elf64_Off, offset, header.sh_offset );
/**
* @brief Set the index of the section.
* @param value Index of the section.
*/
void set_index( const Elf_Half& value ) override { index = value; }
/**
* @brief Check if the section is compressed.
* @return True if compressed, false otherwise.
*/
bool is_compressed() const
{
return ( ( get_flags() & SHF_RPX_DEFLATE ) ||
( get_flags() & SHF_COMPRESSED ) ) &&
compression != nullptr;
}
/**
* @brief Load the section from a stream.
* @param stream Input stream.
* @param header_offset Offset of the header.
* @param is_lazy_ Whether to load lazily.
* @return True if successful, false otherwise.
*/
bool load( std::istream& stream,
std::streampos header_offset,
bool is_lazy_ ) override
{
pstream = &stream;
is_lazy = is_lazy_;
if ( translator->empty() ) {
stream.seekg( 0, std::istream::end );
set_stream_size( size_t( stream.tellg() ) );
}
else {
set_stream_size( std::numeric_limits<size_t>::max() );
}
stream.seekg( ( *translator )[header_offset] );
stream.read( reinterpret_cast<char*>( &header ), sizeof( header ) );
if ( !( is_lazy || is_loaded ) ) {
bool ret = get_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 );
}
}
return ret;
}
return true;
}
/**
* @brief Load the data of the section.
* @return True if successful, false otherwise.
*/
bool load_data() const
{
Elf_Xword sh_offset =
( *translator )[( *convertor )( header.sh_offset )];
Elf_Xword size = get_size();
// Check for integer overflow in offset calculation
if ( sh_offset > get_stream_size() ) {
return false;
}
// Check for integer overflow in size calculation
if ( size > get_stream_size() ||
size > ( get_stream_size() - sh_offset ) ) {
return false;
}
// Check if we need to load data
if ( nullptr == data && SHT_NULL != get_type() &&
SHT_NOBITS != get_type() ) {
// Check if size can be safely converted to size_t
if ( size > std::numeric_limits<size_t>::max() - 1 ) {
return false;
}
data.reset( new ( std::nothrow ) char[size_t( size ) + 1] );
if ( ( 0 != size ) && ( nullptr != data ) ) {
pstream->seekg( sh_offset );
pstream->read( data.get(), size );
if ( static_cast<Elf_Xword>( pstream->gcount() ) != size ) {
data.reset( nullptr );
data_size = 0;
return false;
}
data_size = size;
data.get()[size] = 0; // Safe now as we allocated size + 1
}
else {
data_size = 0;
if ( size != 0 ) {
return false; // Failed to allocate required memory
}
}
is_loaded = true;
return true;
}
// Data already loaded or doesn't need loading
is_loaded = ( nullptr != data ) || ( SHT_NULL == get_type() ) ||
( SHT_NOBITS == get_type() );
return is_loaded;
}
/**
* @brief Save the section to a stream.
* @param stream Output stream.
* @param header_offset Offset of the header.
* @param data_offset Offset of the data.
*/
void save( std::ostream& stream,
std::streampos header_offset,
std::streampos data_offset ) override
{
if ( 0 != get_index() ) {
header.sh_offset = decltype( header.sh_offset )( data_offset );
header.sh_offset = ( *convertor )( header.sh_offset );
}
save_header( stream, header_offset );
if ( get_type() != SHT_NOBITS && get_type() != SHT_NULL &&
get_size() != 0 && data != nullptr ) {
save_data( stream, data_offset );
}
}
private:
/**
* @brief Save the header of the section to a stream.
* @param stream Output stream.
* @param header_offset Offset of the header.
*/
void save_header( std::ostream& stream, std::streampos header_offset ) const
{
adjust_stream_size( stream, header_offset );
stream.write( reinterpret_cast<const char*>( &header ),
sizeof( header ) );
}
/**
* @brief Save the data of the section to a stream.
* @param stream Output stream.
* @param data_offset Offset of the data.
*/
void save_data( std::ostream& stream, std::streampos data_offset )
{
adjust_stream_size( stream, data_offset );
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 = compression->deflate(
data.get(), convertor, decompressed_size, compressed_size );
stream.write( compressed_ptr.get(), compressed_size );
}
else {
stream.write( get_data(), get_size() );
}
}
private:
mutable std::istream* pstream =
nullptr; /**< Pointer to the input stream. */
T header = {}; /**< Section header. */
Elf_Half index = 0; /**< Index of the section. */
std::string name; /**< Name of the section. */
mutable std::unique_ptr<char[]> data; /**< Pointer to the data. */
mutable Elf_Xword data_size = 0; /**< Size of the data. */
std::shared_ptr<endianness_convertor> convertor =
nullptr; /**< Pointer to the endianness convertor. */
std::shared_ptr<address_translator> translator =
nullptr; /**< Pointer to the address translator. */
std::shared_ptr<compression_interface> compression =
nullptr; /**< Shared pointer to the compression interface. */
bool is_address_set = false; /**< Flag indicating if the address is set. */
size_t stream_size = 0; /**< Size of the stream. */
mutable bool is_lazy =
false; /**< Flag indicating if lazy loading is enabled. */
mutable bool is_loaded =
false; /**< Flag indicating if the data is loaded. */
mutable bool can_be_loaded =
true; /**< Flag indicating if the data can loaded. This is not the case if the section is corrupted. */
};
} // namespace ELFIO
#endif // ELFIO_SECTION_HPP

View File

@ -0,0 +1,405 @@
/*
Copyright (C) 2001-present by Serge Lamikhov-Center
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef ELFIO_SEGMENT_HPP
#define ELFIO_SEGMENT_HPP
#include <iostream>
#include <vector>
#include <new>
#include <limits>
namespace ELFIO {
//------------------------------------------------------------------------------
//! \class segment
//! \brief Class for accessing segment data
class segment
{
friend class elfio;
public:
virtual ~segment() = default;
//------------------------------------------------------------------------------
//! \brief Get the index of the segment
//! \return Index of the segment
ELFIO_GET_ACCESS_DECL( Elf_Half, index );
//------------------------------------------------------------------------------
//! \brief Get the type of the segment
//! \return Type of the segment
ELFIO_GET_SET_ACCESS_DECL( Elf_Word, type );
//------------------------------------------------------------------------------
//! \brief Get the flags of the segment
//! \return Flags of the segment
ELFIO_GET_SET_ACCESS_DECL( Elf_Word, flags );
//------------------------------------------------------------------------------
//! \brief Get the alignment of the segment
//! \return Alignment of the segment
ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, align );
//------------------------------------------------------------------------------
//! \brief Get the virtual address of the segment
//! \return Virtual address of the segment
ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, virtual_address );
//------------------------------------------------------------------------------
//! \brief Get the physical address of the segment
//! \return Physical address of the segment
ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, physical_address );
//------------------------------------------------------------------------------
//! \brief Get the file size of the segment
//! \return File size of the segment
ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, file_size );
//------------------------------------------------------------------------------
//! \brief Get the memory size of the segment
//! \return Memory size of the segment
ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, memory_size );
//------------------------------------------------------------------------------
//! \brief Get the offset of the segment
//! \return Offset of the segment
ELFIO_GET_ACCESS_DECL( Elf64_Off, offset );
//------------------------------------------------------------------------------
//! \brief Get the data of the segment
//! \return Pointer to the data
virtual const char* get_data() const = 0;
//------------------------------------------------------------------------------
//! \brief Free the data of the segment
virtual void free_data() const = 0;
//------------------------------------------------------------------------------
//! \brief Add a section to the segment
//! \param psec Pointer to the section
//! \param addr_align Alignment of the section
//! \return Index of the added section
virtual Elf_Half add_section( section* psec, Elf_Xword addr_align ) = 0;
//------------------------------------------------------------------------------
//! \brief Add a section index to the segment
//! \param index Index of the section
//! \param addr_align Alignment of the section
//! \return Index of the added section
virtual Elf_Half add_section_index( Elf_Half index,
Elf_Xword addr_align ) = 0;
//------------------------------------------------------------------------------
//! \brief Get the number of sections in the segment
//! \return Number of sections in the segment
virtual Elf_Half get_sections_num() const = 0;
//------------------------------------------------------------------------------
//! \brief Get the index of a section at a given position
//! \param num Position of the section
//! \return Index of the section
virtual Elf_Half get_section_index_at( Elf_Half num ) const = 0;
//------------------------------------------------------------------------------
//! \brief Check if the offset is initialized
//! \return True if the offset is initialized, false otherwise
virtual bool is_offset_initialized() const = 0;
protected:
//------------------------------------------------------------------------------
//! \brief Set the offset of the segment
//! \param offset Offset of the segment
ELFIO_SET_ACCESS_DECL( Elf64_Off, offset );
//------------------------------------------------------------------------------
//! \brief Set the index of the segment
//! \param index Index of the segment
ELFIO_SET_ACCESS_DECL( Elf_Half, index );
//------------------------------------------------------------------------------
//! \brief Get the sections of the segment
//! \return Vector of section indices
virtual const std::vector<Elf_Half>& get_sections() const = 0;
//------------------------------------------------------------------------------
//! \brief Load the segment from a stream
//! \param stream Input stream
//! \param header_offset Offset of the segment header
//! \param is_lazy Whether to load the segment lazily
//! \return True if successful, false otherwise
virtual bool load( std::istream& stream,
std::streampos header_offset,
bool is_lazy ) = 0;
//------------------------------------------------------------------------------
//! \brief Save the segment to a stream
//! \param stream Output stream
//! \param header_offset Offset of the segment header
//! \param data_offset Offset of the segment data
virtual void save( std::ostream& stream,
std::streampos header_offset,
std::streampos data_offset ) = 0;
};
//------------------------------------------------------------------------------
//! \class segment_impl
//! \brief Implementation of the segment class
template <class T> class segment_impl : public segment
{
public:
//------------------------------------------------------------------------------
//! \brief Constructor
//! \param convertor Pointer to the endianness convertor
//! \param translator Pointer to the address translator
segment_impl( std::shared_ptr<endianness_convertor> convertor,
std::shared_ptr<address_translator> translator )
: convertor( convertor ), translator( translator )
{
}
//------------------------------------------------------------------------------
// Section info functions
ELFIO_GET_SET_ACCESS( Elf_Word, type, ph.p_type );
ELFIO_GET_SET_ACCESS( Elf_Word, flags, ph.p_flags );
ELFIO_GET_SET_ACCESS( Elf_Xword, align, ph.p_align );
ELFIO_GET_SET_ACCESS( Elf64_Addr, virtual_address, ph.p_vaddr );
ELFIO_GET_SET_ACCESS( Elf64_Addr, physical_address, ph.p_paddr );
ELFIO_GET_SET_ACCESS( Elf_Xword, file_size, ph.p_filesz );
ELFIO_GET_SET_ACCESS( Elf_Xword, memory_size, ph.p_memsz );
ELFIO_GET_ACCESS( Elf64_Off, offset, ph.p_offset );
//------------------------------------------------------------------------------
//! \brief Get the index of the segment
//! \return Index of the segment
Elf_Half get_index() const override { return index; }
//------------------------------------------------------------------------------
//! \brief Get the data of the segment
//! \return Pointer to the data
const char* get_data() const override
{
if ( !is_loaded ) {
load_data();
}
return data.get();
}
//------------------------------------------------------------------------------
//! \brief Free the data of the segment
void free_data() const override
{
if ( is_lazy ) {
data.reset( nullptr );
is_loaded = false;
}
}
//------------------------------------------------------------------------------
//! \brief Add a section index to the segment
//! \param sec_index Index of the section
//! \param addr_align Alignment of the section
//! \return Index of the added section
Elf_Half add_section_index( Elf_Half sec_index,
Elf_Xword addr_align ) override
{
sections.emplace_back( sec_index );
if ( addr_align > get_align() ) {
set_align( addr_align );
}
return (Elf_Half)sections.size();
}
//------------------------------------------------------------------------------
//! \brief Add a section to the segment
//! \param psec Pointer to the section
//! \param addr_align Alignment of the section
//! \return Index of the added section
Elf_Half add_section( section* psec, Elf_Xword addr_align ) override
{
return add_section_index( psec->get_index(), addr_align );
}
//------------------------------------------------------------------------------
//! \brief Get the number of sections in the segment
//! \return Number of sections in the segment
Elf_Half get_sections_num() const override
{
return (Elf_Half)sections.size();
}
//------------------------------------------------------------------------------
//! \brief Get the index of a section at a given position
//! \param num Position of the section
//! \return Index of the section
Elf_Half get_section_index_at( Elf_Half num ) const override
{
if ( num < sections.size() ) {
return sections[num];
}
return Elf_Half( -1 );
}
//------------------------------------------------------------------------------
protected:
//------------------------------------------------------------------------------
//! \brief Set the offset of the segment
//! \param value Offset of the segment
void set_offset( const Elf64_Off& value ) override
{
ph.p_offset = decltype( ph.p_offset )( value );
ph.p_offset = ( *convertor )( ph.p_offset );
is_offset_set = true;
}
//------------------------------------------------------------------------------
//! \brief Check if the offset is initialized
//! \return True if the offset is initialized, false otherwise
bool is_offset_initialized() const override { return is_offset_set; }
//------------------------------------------------------------------------------
//! \brief Get the sections of the segment
//! \return Vector of section indices
const std::vector<Elf_Half>& get_sections() const override
{
return sections;
}
//------------------------------------------------------------------------------
//! \brief Set the index of the segment
//! \param value Index of the segment
void set_index( const Elf_Half& value ) override { index = value; }
//------------------------------------------------------------------------------
//! \brief Load the segment from a stream
//! \param stream Input stream
//! \param header_offset Offset of the segment header
//! \param is_lazy_ Whether to load the segment lazily
//! \return True if successful, false otherwise
bool load( std::istream& stream,
std::streampos header_offset,
bool is_lazy_ ) override
{
pstream = &stream;
is_lazy = is_lazy_;
if ( translator->empty() ) {
stream.seekg( 0, std::istream::end );
set_stream_size( size_t( stream.tellg() ) );
}
else {
set_stream_size( std::numeric_limits<size_t>::max() );
}
stream.seekg( ( *translator )[header_offset] );
stream.read( reinterpret_cast<char*>( &ph ), sizeof( ph ) );
is_offset_set = true;
if ( !( is_lazy || is_loaded ) ) {
return load_data();
}
return true;
}
//------------------------------------------------------------------------------
//! \brief Load the data of the segment
//! \return True if successful, false otherwise
bool load_data() const
{
if ( PT_NULL == get_type() || 0 == get_file_size() ) {
return true;
}
Elf_Xword p_offset = ( *translator )[( *convertor )( ph.p_offset )];
Elf_Xword size = get_file_size();
// Check for integer overflow in offset calculation
if ( p_offset > get_stream_size() ) {
data = nullptr;
return false;
}
// Check for integer overflow in size calculation
if ( size > get_stream_size() ||
size > ( get_stream_size() - p_offset ) ) {
data = nullptr;
return false;
}
// Check if size can be safely converted to size_t
if ( size > std::numeric_limits<size_t>::max() - 1 ) {
data = nullptr;
return false;
}
data.reset( new ( std::nothrow ) char[(size_t)size + 1] );
pstream->seekg( p_offset );
if ( nullptr != data.get() && pstream->read( data.get(), size ) ) {
data.get()[size] = 0;
}
else {
data = nullptr;
return false;
}
is_loaded = true;
return true;
}
//------------------------------------------------------------------------------
//! \brief Save the segment to a stream
//! \param stream Output stream
//! \param header_offset Offset of the segment header
//! \param data_offset Offset of the segment data
void save( std::ostream& stream,
std::streampos header_offset,
std::streampos data_offset ) override
{
ph.p_offset = decltype( ph.p_offset )( data_offset );
ph.p_offset = ( *convertor )( ph.p_offset );
adjust_stream_size( stream, header_offset );
stream.write( reinterpret_cast<const char*>( &ph ), sizeof( ph ) );
}
//------------------------------------------------------------------------------
//! \brief Get the stream size
//! \return Stream size
size_t get_stream_size() const { return stream_size; }
//------------------------------------------------------------------------------
//! \brief Set the stream size
//! \param value Stream size
void set_stream_size( size_t value ) { stream_size = value; }
//------------------------------------------------------------------------------
private:
mutable std::istream* pstream = nullptr; //!< Pointer to the input stream
T ph = {}; //!< Segment header
Elf_Half index = 0; //!< Index of the segment
mutable std::unique_ptr<char[]> data; //!< Pointer to the segment data
std::vector<Elf_Half> sections; //!< Vector of section indices
std::shared_ptr<endianness_convertor> convertor =
nullptr; //!< Pointer to the endianness convertor
std::shared_ptr<address_translator> translator =
nullptr; //!< Pointer to the address translator
size_t stream_size = 0; //!< Stream size
bool is_offset_set = false; //!< Flag indicating if the offset is set
mutable bool is_lazy =
false; //!< Flag indicating if the segment is loaded lazily
mutable bool is_loaded =
false; //!< Flag indicating if the segment is loaded
};
} // namespace ELFIO
#endif // ELFIO_SEGMENT_HPP

View File

@ -0,0 +1,143 @@
/*
Copyright (C) 2001-present by Serge Lamikhov-Center
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef ELFIO_STRINGS_HPP
#define ELFIO_STRINGS_HPP
#include <cstdlib>
#include <cstring>
#include <string>
#include <limits>
namespace ELFIO {
//------------------------------------------------------------------------------
//! \class string_section_accessor_template
//! \brief Class for accessing string section data
template <class S> class string_section_accessor_template
{
public:
//------------------------------------------------------------------------------
//! \brief Constructor
//! \param section Pointer to the section
explicit string_section_accessor_template( S* section )
: string_section( section )
{
}
//------------------------------------------------------------------------------
//! \brief Get a string from the section
//! \param index Index of the string
//! \return Pointer to the string, or nullptr if not found
const char* get_string( Elf_Word index ) const
{
if ( string_section ) {
const char* data = string_section->get_data();
size_t section_size =
static_cast<size_t>( string_section->get_size() );
// Check if index is within bounds
if ( index >= section_size || nullptr == data ) {
return nullptr;
}
// Check for integer overflow in size calculation
size_t remaining_size = section_size - index;
if ( remaining_size > section_size ) { // Check for underflow
return nullptr;
}
// Use standard C++ functions to find string length
const char* str = data + index;
const char* end =
(const char*)std::memchr( str, '\0', remaining_size );
if ( end != nullptr && end < str + remaining_size ) {
return str;
}
}
return nullptr;
}
//------------------------------------------------------------------------------
//! \brief Add a string to the section
//! \param str Pointer to the string
//! \return Index of the added string
Elf_Word add_string( const char* str )
{
if ( !str ) {
return 0; // Return index of empty string for null input
}
Elf_Word current_position = 0;
if ( string_section ) {
// Strings are added to the end of the current section data
current_position =
static_cast<Elf_Word>( string_section->get_size() );
if ( current_position == 0 ) {
char empty_string = '\0';
string_section->append_data( &empty_string, 1 );
current_position++;
}
// Calculate string length and check for overflow
size_t str_len = std::strlen( str );
if ( str_len > std::numeric_limits<Elf_Word>::max() - 1 ) {
return 0; // String too long
}
// Check if appending would overflow section size
Elf_Word append_size = static_cast<Elf_Word>( str_len + 1 );
if ( append_size >
std::numeric_limits<Elf_Word>::max() - current_position ) {
return 0; // Would overflow section size
}
string_section->append_data( str, append_size );
}
return current_position;
}
//------------------------------------------------------------------------------
//! \brief Add a string to the section
//! \param str The string to add
//! \return Index of the added string
Elf_Word add_string( const std::string& str )
{
return add_string( str.c_str() );
}
//------------------------------------------------------------------------------
private:
S* string_section; //!< Pointer to the section
};
using string_section_accessor = string_section_accessor_template<section>;
using const_string_section_accessor =
string_section_accessor_template<const section>;
} // namespace ELFIO
#endif // ELFIO_STRINGS_HPP

View File

@ -0,0 +1,716 @@
/*
Copyright (C) 2001-present by Serge Lamikhov-Center
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef ELFIO_SYMBOLS_HPP
#define ELFIO_SYMBOLS_HPP
namespace ELFIO {
//------------------------------------------------------------------------------
// @class symbol_section_accessor_template
// @brief A template class for accessing symbol sections in an ELF file.
//------------------------------------------------------------------------------
template <class S> class symbol_section_accessor_template
{
public:
//------------------------------------------------------------------------------
// @brief Constructor
// @param elf_file Reference to the ELF file
// @param symbol_section Pointer to the symbol section
//------------------------------------------------------------------------------
explicit symbol_section_accessor_template( const elfio& elf_file,
S* symbol_section )
: elf_file( elf_file ), symbol_section( symbol_section )
{
find_hash_section();
}
//------------------------------------------------------------------------------
// @brief Get the number of symbols in the section
// @return Number of symbols
//------------------------------------------------------------------------------
Elf_Xword get_symbols_num() const
{
Elf_Xword nRet = 0;
size_t minimum_symbol_size;
switch ( elf_file.get_class() ) {
case ELFCLASS32:
minimum_symbol_size = sizeof( Elf32_Sym );
break;
case ELFCLASS64:
minimum_symbol_size = sizeof( Elf64_Sym );
break;
default:
return nRet;
}
if ( symbol_section->get_entry_size() >= minimum_symbol_size &&
symbol_section->get_size() <= symbol_section->get_stream_size() ) {
nRet =
symbol_section->get_size() / symbol_section->get_entry_size();
}
return nRet;
}
//------------------------------------------------------------------------------
// @brief Get the symbol at the specified index
// @param index Index of the symbol
// @param name Name of the symbol
// @param value Value of the symbol
// @param size Size of the symbol
// @param bind Binding of the symbol
// @param type Type of the symbol
// @param section_index Section index of the symbol
// @param other Other attributes of the symbol
// @return True if the symbol is found, false otherwise
//------------------------------------------------------------------------------
bool get_symbol( Elf_Xword index,
std::string& name,
Elf64_Addr& value,
Elf_Xword& size,
unsigned char& bind,
unsigned char& type,
Elf_Half& section_index,
unsigned char& other ) const
{
bool ret = false;
if ( elf_file.get_class() == ELFCLASS32 ) {
ret = generic_get_symbol<Elf32_Sym>( index, name, value, size, bind,
type, section_index, other );
}
else {
ret = generic_get_symbol<Elf64_Sym>( index, name, value, size, bind,
type, section_index, other );
}
return ret;
}
//------------------------------------------------------------------------------
// @brief Get the symbol with the specified name
// @param name Name of the symbol
// @param value Value of the symbol
// @param size Size of the symbol
// @param bind Binding of the symbol
// @param type Type of the symbol
// @param section_index Section index of the symbol
// @param other Other attributes of the symbol
// @return True if the symbol is found, false otherwise
//------------------------------------------------------------------------------
bool get_symbol( const std::string& name,
Elf64_Addr& value,
Elf_Xword& size,
unsigned char& bind,
unsigned char& type,
Elf_Half& section_index,
unsigned char& other ) const
{
bool ret = false;
if ( 0 != get_hash_table_index() ) {
if ( hash_section->get_type() == SHT_HASH ) {
ret = hash_lookup( name, value, size, bind, type, section_index,
other );
}
if ( hash_section->get_type() == SHT_GNU_HASH ||
hash_section->get_type() == DT_GNU_HASH ) {
if ( elf_file.get_class() == ELFCLASS32 ) {
ret = gnu_hash_lookup<std::uint32_t>(
name, value, size, bind, type, section_index, other );
}
else {
ret = gnu_hash_lookup<std::uint64_t>(
name, value, size, bind, type, section_index, other );
}
}
}
if ( !ret ) {
for ( Elf_Xword i = 0; !ret && i < get_symbols_num(); i++ ) {
std::string symbol_name;
if ( get_symbol( i, symbol_name, value, size, bind, type,
section_index, other ) &&
( symbol_name == name ) ) {
ret = true;
}
}
}
return ret;
}
//------------------------------------------------------------------------------
// @brief Get the symbol with the specified value
// @param value Value of the symbol
// @param name Name of the symbol
// @param size Size of the symbol
// @param bind Binding of the symbol
// @param type Type of the symbol
// @param section_index Section index of the symbol
// @param other Other attributes of the symbol
// @return True if the symbol is found, false otherwise
//------------------------------------------------------------------------------
bool get_symbol( const Elf64_Addr& value,
std::string& name,
Elf_Xword& size,
unsigned char& bind,
unsigned char& type,
Elf_Half& section_index,
unsigned char& other ) const
{
const auto& convertor = elf_file.get_convertor();
Elf_Xword idx = 0;
bool match = false;
Elf64_Addr v = 0;
if ( elf_file.get_class() == ELFCLASS32 ) {
match = generic_search_symbols<Elf32_Sym>(
[&]( const Elf32_Sym* sym ) {
return ( *convertor )( sym->st_value ) == value;
},
idx );
}
else {
match = generic_search_symbols<Elf64_Sym>(
[&]( const Elf64_Sym* sym ) {
return ( *convertor )( sym->st_value ) == value;
},
idx );
}
if ( match ) {
return get_symbol( idx, name, v, size, bind, type, section_index,
other );
}
return false;
}
//------------------------------------------------------------------------------
// @brief Add a symbol to the section
// @param name Name of the symbol
// @param value Value of the symbol
// @param size Size of the symbol
// @param info Info of the symbol
// @param other Other attributes of the symbol
// @param shndx Section index of the symbol
// @return Index of the added symbol
//------------------------------------------------------------------------------
Elf_Word add_symbol( Elf_Word name,
Elf64_Addr value,
Elf_Xword size,
unsigned char info,
unsigned char other,
Elf_Half shndx )
{
Elf_Word nRet;
if ( symbol_section->get_size() == 0 ) {
if ( elf_file.get_class() == ELFCLASS32 ) {
nRet = generic_add_symbol<Elf32_Sym>( 0, 0, 0, 0, 0, 0 );
}
else {
nRet = generic_add_symbol<Elf64_Sym>( 0, 0, 0, 0, 0, 0 );
}
}
if ( elf_file.get_class() == ELFCLASS32 ) {
nRet = generic_add_symbol<Elf32_Sym>( name, value, size, info,
other, shndx );
}
else {
nRet = generic_add_symbol<Elf64_Sym>( name, value, size, info,
other, shndx );
}
return nRet;
}
//------------------------------------------------------------------------------
// @brief Add a symbol to the section
// @param name Name of the symbol
// @param value Value of the symbol
// @param size Size of the symbol
// @param bind Binding of the symbol
// @param type Type of the symbol
// @param other Other attributes of the symbol
// @param shndx Section index of the symbol
// @return Index of the added symbol
//------------------------------------------------------------------------------
Elf_Word add_symbol( Elf_Word name,
Elf64_Addr value,
Elf_Xword size,
unsigned char bind,
unsigned char type,
unsigned char other,
Elf_Half shndx )
{
return add_symbol( name, value, size, ELF_ST_INFO( bind, type ), other,
shndx );
}
//------------------------------------------------------------------------------
// @brief Add a symbol to the section
// @param pStrWriter String section accessor
// @param str Name of the symbol
// @param value Value of the symbol
// @param size Size of the symbol
// @param info Info of the symbol
// @param other Other attributes of the symbol
// @param shndx Section index of the symbol
// @return Index of the added symbol
//------------------------------------------------------------------------------
Elf_Word add_symbol( string_section_accessor& pStrWriter,
const char* str,
Elf64_Addr value,
Elf_Xword size,
unsigned char info,
unsigned char other,
Elf_Half shndx )
{
Elf_Word index = pStrWriter.add_string( str );
return add_symbol( index, value, size, info, other, shndx );
}
//------------------------------------------------------------------------------
// @brief Add a symbol to the section
// @param pStrWriter String section accessor
// @param str Name of the symbol
// @param value Value of the symbol
// @param size Size of the symbol
// @param bind Binding of the symbol
// @param type Type of the symbol
// @param other Other attributes of the symbol
// @param shndx Section index of the symbol
// @return Index of the added symbol
//------------------------------------------------------------------------------
Elf_Word add_symbol( string_section_accessor& pStrWriter,
const char* str,
Elf64_Addr value,
Elf_Xword size,
unsigned char bind,
unsigned char type,
unsigned char other,
Elf_Half shndx )
{
return add_symbol( pStrWriter, str, value, size,
ELF_ST_INFO( bind, type ), other, shndx );
}
//------------------------------------------------------------------------------
// @brief Arrange local symbols in the section
// @param func Function to be called for each pair of symbols
// @return Number of local symbols
//------------------------------------------------------------------------------
Elf_Xword arrange_local_symbols(
std::function<void( Elf_Xword first, Elf_Xword second )> func =
nullptr )
{
Elf_Xword nRet = 0;
if ( elf_file.get_class() == ELFCLASS32 ) {
nRet = generic_arrange_local_symbols<Elf32_Sym>( func );
}
else {
nRet = generic_arrange_local_symbols<Elf64_Sym>( func );
}
return nRet;
}
//------------------------------------------------------------------------------
private:
//------------------------------------------------------------------------------
// @brief Find the hash section
//------------------------------------------------------------------------------
void find_hash_section()
{
Elf_Half nSecNo = elf_file.sections.size();
for ( Elf_Half i = 0; i < nSecNo; ++i ) {
const section* sec = elf_file.sections[i];
if ( sec->get_link() == symbol_section->get_index() &&
( sec->get_type() == SHT_HASH ||
sec->get_type() == SHT_GNU_HASH ||
sec->get_type() == DT_GNU_HASH ) ) {
hash_section = sec;
hash_section_index = i;
break;
}
}
}
//------------------------------------------------------------------------------
// @brief Get the index of the string table
// @return Index of the string table
//------------------------------------------------------------------------------
Elf_Half get_string_table_index() const
{
return (Elf_Half)symbol_section->get_link();
}
//------------------------------------------------------------------------------
// @brief Get the index of the hash table
// @return Index of the hash table
//------------------------------------------------------------------------------
Elf_Half get_hash_table_index() const { return hash_section_index; }
//------------------------------------------------------------------------------
// @brief Lookup a symbol in the hash table
// @param name Name of the symbol
// @param value Value of the symbol
// @param size Size of the symbol
// @param bind Binding of the symbol
// @param type Type of the symbol
// @param section_index Section index of the symbol
// @param other Other attributes of the symbol
// @return True if the symbol is found, false otherwise
//------------------------------------------------------------------------------
bool hash_lookup( const std::string& name,
Elf64_Addr& value,
Elf_Xword& size,
unsigned char& bind,
unsigned char& type,
Elf_Half& section_index,
unsigned char& other ) const
{
bool ret = false;
const auto& convertor = elf_file.get_convertor();
Elf_Word nbucket = *(const Elf_Word*)hash_section->get_data();
nbucket = ( *convertor )( nbucket );
Elf_Word nchain =
*(const Elf_Word*)( hash_section->get_data() + sizeof( Elf_Word ) );
nchain = ( *convertor )( nchain );
Elf_Word val = elf_hash( (const unsigned char*)name.c_str() );
Elf_Word y =
*(const Elf_Word*)( hash_section->get_data() +
( 2 + val % nbucket ) * sizeof( Elf_Word ) );
y = ( *convertor )( y );
std::string str;
get_symbol( y, str, value, size, bind, type, section_index, other );
while ( str != name && STN_UNDEF != y && y < nchain ) {
y = *(const Elf_Word*)( hash_section->get_data() +
( 2 + nbucket + y ) * sizeof( Elf_Word ) );
y = ( *convertor )( y );
get_symbol( y, str, value, size, bind, type, section_index, other );
}
if ( str == name ) {
ret = true;
}
return ret;
}
//------------------------------------------------------------------------------
// @brief Lookup a symbol in the GNU hash table
// @param name Name of the symbol
// @param value Value of the symbol
// @param size Size of the symbol
// @param bind Binding of the symbol
// @param type Type of the symbol
// @param section_index Section index of the symbol
// @param other Other attributes of the symbol
// @return True if the symbol is found, false otherwise
//------------------------------------------------------------------------------
template <class T>
bool gnu_hash_lookup( const std::string& name,
Elf64_Addr& value,
Elf_Xword& size,
unsigned char& bind,
unsigned char& type,
Elf_Half& section_index,
unsigned char& other ) const
{
bool ret = false;
const auto& convertor = elf_file.get_convertor();
std::uint32_t nbuckets =
*( (std::uint32_t*)hash_section->get_data() + 0 );
std::uint32_t symoffset =
*( (std::uint32_t*)hash_section->get_data() + 1 );
std::uint32_t bloom_size =
*( (std::uint32_t*)hash_section->get_data() + 2 );
std::uint32_t bloom_shift =
*( (std::uint32_t*)hash_section->get_data() + 3 );
nbuckets = ( *convertor )( nbuckets );
symoffset = ( *convertor )( symoffset );
bloom_size = ( *convertor )( bloom_size );
bloom_shift = ( *convertor )( bloom_shift );
auto* bloom_filter =
(T*)( hash_section->get_data() + 4 * sizeof( std::uint32_t ) );
std::uint32_t hash = elf_gnu_hash( (const unsigned char*)name.c_str() );
std::uint32_t bloom_index = ( hash / ( 8 * sizeof( T ) ) ) % bloom_size;
T bloom_bits =
( (T)1 << ( hash % ( 8 * sizeof( T ) ) ) ) |
( (T)1 << ( ( hash >> bloom_shift ) % ( 8 * sizeof( T ) ) ) );
if ( ( ( *convertor )( bloom_filter[bloom_index] ) & bloom_bits ) !=
bloom_bits )
return ret;
std::uint32_t bucket = hash % nbuckets;
auto* buckets = (std::uint32_t*)( hash_section->get_data() +
4 * sizeof( std::uint32_t ) +
bloom_size * sizeof( T ) );
auto* chains = (std::uint32_t*)( hash_section->get_data() +
4 * sizeof( std::uint32_t ) +
bloom_size * sizeof( T ) +
nbuckets * sizeof( std::uint32_t ) );
if ( ( *convertor )( buckets[bucket] ) >= symoffset ) {
std::uint32_t chain_index =
( *convertor )( buckets[bucket] ) - symoffset;
std::uint32_t chain_hash = ( *convertor )( chains[chain_index] );
std::string symname;
while ( true ) {
if ( ( chain_hash >> 1 ) == ( hash >> 1 ) &&
get_symbol( chain_index + symoffset, symname, value, size,
bind, type, section_index, other ) &&
( name == symname ) ) {
ret = true;
break;
}
if ( chain_hash & 1 )
break;
chain_hash = ( *convertor )( chains[++chain_index] );
}
}
return ret;
}
//------------------------------------------------------------------------------
// @brief Get the symbol at the specified index
// @param index Index of the symbol
// @return Pointer to the symbol
//------------------------------------------------------------------------------
template <class T> const T* generic_get_symbol_ptr( Elf_Xword index ) const
{
if ( 0 != symbol_section->get_data() && index < get_symbols_num() ) {
if ( symbol_section->get_entry_size() < sizeof( T ) ) {
return nullptr;
}
const auto* pSym = reinterpret_cast<const T*>(
symbol_section->get_data() +
index * symbol_section->get_entry_size() );
return pSym;
}
return nullptr;
}
//------------------------------------------------------------------------------
// @brief Search for a symbol in the section
// @param match Function to be called for each symbol
// @param idx Index of the found symbol
// @return True if the symbol is found, false otherwise
//------------------------------------------------------------------------------
template <class T>
bool generic_search_symbols( std::function<bool( const T* )> match,
Elf_Xword& idx ) const
{
for ( Elf_Xword i = 0; i < get_symbols_num(); i++ ) {
const T* symPtr = generic_get_symbol_ptr<T>( i );
if ( symPtr == nullptr )
return false;
if ( match( symPtr ) ) {
idx = i;
return true;
}
}
return false;
}
//------------------------------------------------------------------------------
// @brief Get the symbol at the specified index
// @param index Index of the symbol
// @param name Name of the symbol
// @param value Value of the symbol
// @param size Size of the symbol
// @param bind Binding of the symbol
// @param type Type of the symbol
// @param section_index Section index of the symbol
// @param other Other attributes of the symbol
// @return True if the symbol is found, false otherwise
//------------------------------------------------------------------------------
template <class T>
bool generic_get_symbol( Elf_Xword index,
std::string& name,
Elf64_Addr& value,
Elf_Xword& size,
unsigned char& bind,
unsigned char& type,
Elf_Half& section_index,
unsigned char& other ) const
{
bool ret = false;
if ( nullptr != symbol_section->get_data() &&
index < get_symbols_num() ) {
const auto* pSym = reinterpret_cast<const T*>(
symbol_section->get_data() +
index * symbol_section->get_entry_size() );
const auto& convertor = elf_file.get_convertor();
section* string_section =
elf_file.sections[get_string_table_index()];
string_section_accessor str_reader( string_section );
const char* pStr =
str_reader.get_string( ( *convertor )( pSym->st_name ) );
if ( nullptr != pStr ) {
name = pStr;
}
value = ( *convertor )( pSym->st_value );
size = ( *convertor )( pSym->st_size );
bind = ELF_ST_BIND( pSym->st_info );
type = ELF_ST_TYPE( pSym->st_info );
section_index = ( *convertor )( pSym->st_shndx );
other = pSym->st_other;
ret = true;
}
return ret;
}
//------------------------------------------------------------------------------
// @brief Add a symbol to the section
// @param name Name of the symbol
// @param value Value of the symbol
// @param size Size of the symbol
// @param info Info of the symbol
// @param other Other attributes of the symbol
// @param shndx Section index of the symbol
// @return Index of the added symbol
//------------------------------------------------------------------------------
template <class T>
Elf_Word generic_add_symbol( Elf_Word name,
Elf64_Addr value,
Elf_Xword size,
unsigned char info,
unsigned char other,
Elf_Half shndx )
{
const auto& convertor = elf_file.get_convertor();
T entry;
entry.st_name = ( *convertor )( name );
entry.st_value = decltype( entry.st_value )( value );
entry.st_value = ( *convertor )( entry.st_value );
entry.st_size = decltype( entry.st_size )( size );
entry.st_size = ( *convertor )( entry.st_size );
entry.st_info = ( *convertor )( info );
entry.st_other = ( *convertor )( other );
entry.st_shndx = ( *convertor )( shndx );
symbol_section->append_data( reinterpret_cast<char*>( &entry ),
sizeof( entry ) );
Elf_Word nRet =
Elf_Word( symbol_section->get_size() / sizeof( entry ) - 1 );
return nRet;
}
//------------------------------------------------------------------------------
// @brief Arrange local symbols in the section
// @param func Function to be called for each pair of symbols
// @return Number of local symbols
//------------------------------------------------------------------------------
template <class T>
Elf_Xword generic_arrange_local_symbols(
std::function<void( Elf_Xword first, Elf_Xword second )> func )
{
const auto& convertor = elf_file.get_convertor();
Elf_Word first_not_local =
1; // Skip the first entry. It is always NOTYPE
Elf_Xword current = 0;
Elf_Xword count = get_symbols_num();
while ( true ) {
T* p1 = nullptr;
T* p2 = nullptr;
while ( first_not_local < count ) {
p1 = const_cast<T*>(
generic_get_symbol_ptr<T>( first_not_local ) );
if ( ELF_ST_BIND( ( *convertor )( p1->st_info ) ) != STB_LOCAL )
break;
++first_not_local;
}
current = first_not_local + 1;
while ( current < count ) {
p2 = const_cast<T*>( generic_get_symbol_ptr<T>( current ) );
if ( ELF_ST_BIND( ( *convertor )( p2->st_info ) ) == STB_LOCAL )
break;
++current;
}
if ( first_not_local < count && current < count ) {
if ( func )
func( first_not_local, current );
std::swap( *p1, *p2 );
}
else {
// Update 'info' field of the section
symbol_section->set_info( first_not_local );
break;
}
}
return first_not_local;
}
//------------------------------------------------------------------------------
private:
const elfio& elf_file; ///< Reference to the ELF file
S* symbol_section; ///< Pointer to the symbol section
Elf_Half hash_section_index{ 0 }; ///< Index of the hash section
const section* hash_section{ nullptr }; ///< Pointer to the hash section
};
using symbol_section_accessor = symbol_section_accessor_template<section>;
using const_symbol_section_accessor =
symbol_section_accessor_template<const section>;
} // namespace ELFIO
#endif // ELFIO_SYMBOLS_HPP

View File

@ -0,0 +1,373 @@
/*
Copyright (C) 2001-present by Serge Lamikhov-Center
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef ELFIO_UTILS_HPP
#define ELFIO_UTILS_HPP
#include <cstdint>
#include <ostream>
#include <cstring>
#define ELFIO_GET_ACCESS_DECL( TYPE, NAME ) virtual TYPE get_##NAME() const = 0
#define ELFIO_SET_ACCESS_DECL( TYPE, NAME ) \
virtual void set_##NAME( const TYPE& value ) = 0
#define ELFIO_GET_SET_ACCESS_DECL( TYPE, NAME ) \
virtual TYPE get_##NAME() const = 0; \
virtual void set_##NAME( const TYPE& value ) = 0
#define ELFIO_GET_ACCESS( TYPE, NAME, FIELD ) \
TYPE get_##NAME() const override { return ( *convertor )( FIELD ); }
#define ELFIO_SET_ACCESS( TYPE, NAME, FIELD ) \
void set_##NAME( const TYPE& value ) override \
{ \
FIELD = decltype( FIELD )( value ); \
FIELD = ( *convertor )( FIELD ); \
}
#define ELFIO_GET_SET_ACCESS( TYPE, NAME, FIELD ) \
TYPE get_##NAME() const override { return ( *convertor )( FIELD ); } \
void set_##NAME( const TYPE& value ) override \
{ \
FIELD = decltype( FIELD )( value ); \
FIELD = ( *convertor )( FIELD ); \
}
namespace ELFIO {
//------------------------------------------------------------------------------
//! \class endianness_convertor
//! \brief Class for converting endianness of data
class endianness_convertor
{
public:
//------------------------------------------------------------------------------
//! \brief Setup the endianness convertor
//! \param elf_file_encoding The encoding of the ELF file
void setup( unsigned char elf_file_encoding )
{
need_conversion = ( elf_file_encoding != get_host_encoding() );
}
//------------------------------------------------------------------------------
//! \brief Convert a 64-bit unsigned integer
//! \param value The value to convert
//! \return The converted value
std::uint64_t operator()( std::uint64_t value ) const
{
if ( !need_conversion ) {
return value;
}
value = ( ( value & 0x00000000000000FFuLL ) << 56 ) |
( ( value & 0x000000000000FF00uLL ) << 40 ) |
( ( value & 0x0000000000FF0000uLL ) << 24 ) |
( ( value & 0x00000000FF000000uLL ) << 8 ) |
( ( value & 0x000000FF00000000uLL ) >> 8 ) |
( ( value & 0x0000FF0000000000uLL ) >> 24 ) |
( ( value & 0x00FF000000000000uLL ) >> 40 ) |
( ( value & 0xFF00000000000000uLL ) >> 56 );
return value;
}
//------------------------------------------------------------------------------
//! \brief Convert a 64-bit signed integer
//! \param value The value to convert
//! \return The converted value
std::int64_t operator()( std::int64_t value ) const
{
if ( !need_conversion ) {
return value;
}
return ( std::int64_t )( *this )( (std::uint64_t)value );
}
//------------------------------------------------------------------------------
//! \brief Convert a 32-bit unsigned integer
//! \param value The value to convert
//! \return The converted value
std::uint32_t operator()( std::uint32_t value ) const
{
if ( !need_conversion ) {
return value;
}
value =
( ( value & 0x000000FF ) << 24 ) | ( ( value & 0x0000FF00 ) << 8 ) |
( ( value & 0x00FF0000 ) >> 8 ) | ( ( value & 0xFF000000 ) >> 24 );
return value;
}
//------------------------------------------------------------------------------
//! \brief Convert a 32-bit signed integer
//! \param value The value to convert
//! \return The converted value
std::int32_t operator()( std::int32_t value ) const
{
if ( !need_conversion ) {
return value;
}
return ( std::int32_t )( *this )( (std::uint32_t)value );
}
//------------------------------------------------------------------------------
//! \brief Convert a 16-bit unsigned integer
//! \param value The value to convert
//! \return The converted value
std::uint16_t operator()( std::uint16_t value ) const
{
if ( !need_conversion ) {
return value;
}
value = ( std::uint16_t )( ( value & 0x00FF ) << 8 ) |
( ( value & 0xFF00 ) >> 8 );
return value;
}
//------------------------------------------------------------------------------
//! \brief Convert a 16-bit signed integer
//! \param value The value to convert
//! \return The converted value
std::int16_t operator()( std::int16_t value ) const
{
if ( !need_conversion ) {
return value;
}
return ( std::int16_t )( *this )( (std::uint16_t)value );
}
//------------------------------------------------------------------------------
//! \brief Convert an 8-bit signed integer
//! \param value The value to convert
//! \return The converted value
std::int8_t operator()( std::int8_t value ) const { return value; }
//------------------------------------------------------------------------------
//! \brief Convert an 8-bit unsigned integer
//! \param value The value to convert
//! \return The converted value
std::uint8_t operator()( std::uint8_t value ) const { return value; }
//------------------------------------------------------------------------------
private:
//------------------------------------------------------------------------------
//! \brief Get the host encoding
//! \return The host encoding
unsigned char get_host_encoding() const
{
static const int tmp = 1;
if ( 1 == *reinterpret_cast<const char*>( &tmp ) ) {
return ELFDATA2LSB;
}
else {
return ELFDATA2MSB;
}
}
//------------------------------------------------------------------------------
bool need_conversion = false; //!< Flag indicating if conversion is needed
};
//------------------------------------------------------------------------------
//! \struct address_translation
//! \brief Structure for address translation
struct address_translation
{
//------------------------------------------------------------------------------
//! \brief Constructor
//! \param start The start address
//! \param size The size of the address range
//! \param mapped_to The mapped address
address_translation( std::uint64_t start,
std::uint64_t size,
std::uint64_t mapped_to )
: start( start ), size( size ), mapped_to( mapped_to ){};
std::streampos start; //!< Start address
std::streampos size; //!< Size of the address range
std::streampos mapped_to; //!< Mapped address
};
//------------------------------------------------------------------------------
//! \class address_translator
//! \brief Class for translating addresses
class address_translator
{
public:
//------------------------------------------------------------------------------
//! \brief Set address translation
//! \param addr_trans Vector of address translations
void set_address_translation( std::vector<address_translation>& addr_trans )
{
addr_translations = addr_trans;
std::sort( addr_translations.begin(), addr_translations.end(),
[]( const address_translation& a,
const address_translation& b ) -> bool {
return a.start < b.start;
} );
}
//------------------------------------------------------------------------------
//! \brief Translate an address
//! \param value The address to translate
//! \return The translated address
std::streampos operator[]( std::streampos value ) const
{
if ( addr_translations.empty() ) {
return value;
}
for ( auto& t : addr_translations ) {
if ( ( t.start <= value ) && ( ( value - t.start ) < t.size ) ) {
return value - t.start + t.mapped_to;
}
}
return value;
}
//------------------------------------------------------------------------------
//! \brief Check if the address translator is empty
//! \return True if empty, false otherwise
bool empty() const { return addr_translations.empty(); }
private:
std::vector<address_translation>
addr_translations; //!< Vector of address translations
};
//------------------------------------------------------------------------------
//! \brief Calculate the ELF hash of a name
//! \param name The name to hash
//! \return The ELF hash
inline std::uint32_t elf_hash( const unsigned char* name )
{
std::uint32_t h = 0;
std::uint32_t g = 0;
while ( *name != '\0' ) {
h = ( h << 4 ) + *name++;
g = h & 0xf0000000;
if ( g != 0 )
h ^= g >> 24;
h &= ~g;
}
return h;
}
//------------------------------------------------------------------------------
//! \brief Calculate the GNU hash of a name
//! \param s The name to hash
//! \return The GNU hash
inline std::uint32_t elf_gnu_hash( const unsigned char* s )
{
std::uint32_t h = 0x1505;
for ( unsigned char c = *s; c != '\0'; c = *++s )
h = ( h << 5 ) + h + c;
return h;
}
//------------------------------------------------------------------------------
//! \brief Convert a value to a hexadecimal string
//! \param value The value to convert
//! \return The hexadecimal string
inline std::string to_hex_string( std::uint64_t value )
{
std::string str;
while ( value ) {
if ( auto digit = value & 0xF; digit < 0xA ) {
str = char( '0' + digit ) + str;
}
else {
str = char( 'A' + digit - 0xA ) + str;
}
value >>= 4;
}
return "0x" + str;
}
//------------------------------------------------------------------------------
//! \brief Adjust the size of a stream
//! \param stream The stream to adjust
//! \param offset The offset to adjust to
inline void adjust_stream_size( std::ostream& stream, std::streamsize offset )
{
stream.seekp( 0, std::ios_base::end );
if ( stream.tellp() < offset ) {
std::streamsize size = offset - stream.tellp();
stream.write( std::string( size_t( size ), '\0' ).c_str(), size );
}
stream.seekp( offset );
}
//------------------------------------------------------------------------------
//! \brief Get the length of a string with a maximum length
//! \param s The string
//! \param n The maximum length
//! \return The length of the string
inline static size_t strnlength( const char* s, size_t n )
{
auto found = (const char*)std::memchr( s, '\0', n );
return found ? (size_t)( found - s ) : n;
}
//------------------------------------------------------------------------------
//! \class compression_interface
//! \brief Interface for compression and decompression
class compression_interface
{
public:
virtual ~compression_interface() = default;
//------------------------------------------------------------------------------
//! \brief Decompress a compressed section
//! \param data The buffer of compressed data
//! \param convertor Pointer to an endianness convertor instance
//! \param compressed_size The size of the compressed data buffer
//! \param uncompressed_size Reference to a variable to store the decompressed buffer size
//! \return A smart pointer to the decompressed data
virtual std::unique_ptr<char[]>
inflate( const char* data,
std::shared_ptr<const endianness_convertor> convertor,
Elf_Xword compressed_size,
Elf_Xword& uncompressed_size ) const = 0;
//------------------------------------------------------------------------------
//! \brief Compress a section
//! \param data The buffer of uncompressed data
//! \param convertor Pointer to an endianness convertor instance
//! \param decompressed_size The size of the uncompressed data buffer
//! \param compressed_size Reference to a variable to store the compressed buffer size
//! \return A smart pointer to the compressed data
virtual std::unique_ptr<char[]>
deflate( const char* data,
std::shared_ptr<const endianness_convertor> convertor,
Elf_Xword decompressed_size,
Elf_Xword& compressed_size ) const = 0;
};
} // namespace ELFIO
#endif // ELFIO_UTILS_HPP

View File

@ -0,0 +1,4 @@
//------------------------------------------------------------------------------
//! \def ELFIO_VERSION
//! \brief Defines the version of the ELFIO library
#define ELFIO_VERSION "3.14"

View File

@ -0,0 +1,310 @@
/*
Copyright (C) 2001-present by Serge Lamikhov-Center
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef ELFIO_VERSYM_HPP
#define ELFIO_VERSYM_HPP
namespace ELFIO {
//------------------------------------------------------------------------------
//! \class versym_section_accessor_template
//! \brief Class for accessing version symbol section data
template <class S> class versym_section_accessor_template
{
public:
//------------------------------------------------------------------------------
//! \brief Constructor
//! \param section Pointer to the section
explicit versym_section_accessor_template( S* section )
: versym_section( section )
{
if ( section != nullptr ) {
entries_num = decltype( entries_num )( section->get_size() /
sizeof( Elf_Half ) );
}
}
//------------------------------------------------------------------------------
//! \brief Get the number of entries
//! \return Number of entries
Elf_Word get_entries_num() const
{
if ( versym_section ) {
return entries_num;
}
return 0;
}
//------------------------------------------------------------------------------
//! \brief Get an entry
//! \param no Index of the entry
//! \param value Value of the entry
//! \return True if successful, false otherwise
bool get_entry( Elf_Word no, Elf_Half& value ) const
{
if ( versym_section && ( no < get_entries_num() ) ) {
value = ( (Elf_Half*)versym_section->get_data() )[no];
return true;
}
return false;
}
//------------------------------------------------------------------------------
//! \brief Modify an entry
//! \param no Index of the entry
//! \param value New value of the entry
//! \return True if successful, false otherwise
bool modify_entry( Elf_Word no, Elf_Half value )
{
if ( versym_section && ( no < get_entries_num() ) ) {
( (Elf_Half*)versym_section->get_data() )[no] = value;
return true;
}
return false;
}
//------------------------------------------------------------------------------
//! \brief Add an entry
//! \param value Value of the entry
//! \return True if successful, false otherwise
bool add_entry( Elf_Half value )
{
if ( !versym_section ) {
return false;
}
versym_section->append_data( (const char*)&value, sizeof( Elf_Half ) );
++entries_num;
return true;
}
//------------------------------------------------------------------------------
private:
S* versym_section = nullptr; //!< Pointer to the section
Elf_Word entries_num = 0; //!< Number of entries
};
using versym_section_accessor = versym_section_accessor_template<section>;
using const_versym_section_accessor =
versym_section_accessor_template<const section>;
//------------------------------------------------------------------------------
//! \class versym_r_section_accessor_template
//! \brief Class for accessing version requirement section data
template <class S> class versym_r_section_accessor_template
{
public:
//------------------------------------------------------------------------------
//! \brief Constructor
//! \param elf_file Reference to the ELF file
//! \param versym_r_section Pointer to the version requirement section
versym_r_section_accessor_template( const elfio& elf_file,
S* versym_r_section )
: elf_file( elf_file ), versym_r_section( versym_r_section ),
entries_num( 0 )
{
// Find .dynamic section
const section* dynamic_section = elf_file.sections[".dynamic"];
if ( dynamic_section == nullptr ) {
return;
}
const_dynamic_section_accessor dynamic_section_acc( elf_file,
dynamic_section );
Elf_Xword dyn_sec_num = dynamic_section_acc.get_entries_num();
for ( Elf_Xword i = 0; i < dyn_sec_num; ++i ) {
Elf_Xword tag;
Elf_Xword value;
std::string str;
if ( dynamic_section_acc.get_entry( i, tag, value, str ) &&
tag == DT_VERNEEDNUM ) {
entries_num = (Elf_Word)value;
break;
}
}
}
//------------------------------------------------------------------------------
//! \brief Get the number of entries
//! \return Number of entries
Elf_Word get_entries_num() const { return entries_num; }
//------------------------------------------------------------------------------
//! \brief Get an entry
//! \param no Index of the entry
//! \param version Version of the entry
//! \param file_name File name of the entry
//! \param hash Hash of the entry
//! \param flags Flags of the entry
//! \param other Other information of the entry
//! \param dep_name Dependency name of the entry
//! \return True if successful, false otherwise
bool get_entry( Elf_Word no,
Elf_Half& version,
std::string& file_name,
Elf_Word& hash,
Elf_Half& flags,
Elf_Half& other,
std::string& dep_name ) const
{
if ( versym_r_section == nullptr || ( no >= get_entries_num() ) ) {
return false;
}
const_string_section_accessor string_section_acc(
elf_file.sections[versym_r_section->get_link()] );
Elfxx_Verneed* verneed = (Elfxx_Verneed*)versym_r_section->get_data();
Elfxx_Vernaux* veraux =
(Elfxx_Vernaux*)( (char*)verneed + verneed->vn_aux );
for ( Elf_Word i = 0; i < no; ++i ) {
verneed = (Elfxx_Verneed*)( (char*)verneed + verneed->vn_next );
veraux = (Elfxx_Vernaux*)( (char*)verneed + verneed->vn_aux );
}
version = verneed->vn_version;
file_name = string_section_acc.get_string( verneed->vn_file );
hash = veraux->vna_hash;
flags = veraux->vna_flags;
other = veraux->vna_other;
dep_name = string_section_acc.get_string( veraux->vna_name );
return true;
}
//------------------------------------------------------------------------------
private:
const elfio& elf_file;
S* versym_r_section =
nullptr; //!< Pointer to the version requirement section
Elf_Word entries_num = 0; //!< Number of entries
};
using versym_r_section_accessor = versym_r_section_accessor_template<section>;
using const_versym_r_section_accessor =
versym_r_section_accessor_template<const section>;
//------------------------------------------------------------------------------
//! \class versym_d_section_accessor_template
//! \brief Class for accessing version definition section data
template <class S> class versym_d_section_accessor_template
{
public:
//------------------------------------------------------------------------------
//! \brief Constructor
//! \param elf_file Reference to the ELF file
//! \param versym_d_section Pointer to the version definition section
versym_d_section_accessor_template( const elfio& elf_file,
S* versym_d_section )
: elf_file( elf_file ), versym_d_section( versym_d_section ),
entries_num( 0 )
{
// Find .dynamic section
const section* dynamic_section = elf_file.sections[".dynamic"];
if ( dynamic_section == nullptr ) {
return;
}
const_dynamic_section_accessor dynamic_section_acc( elf_file,
dynamic_section );
Elf_Xword dyn_sec_num = dynamic_section_acc.get_entries_num();
for ( Elf_Xword i = 0; i < dyn_sec_num; ++i ) {
Elf_Xword tag;
Elf_Xword value;
std::string str;
if ( dynamic_section_acc.get_entry( i, tag, value, str ) &&
tag == DT_VERDEFNUM ) {
entries_num = (Elf_Word)value;
break;
}
}
}
//------------------------------------------------------------------------------
//! \brief Get the number of entries
//! \return Number of entries
Elf_Word get_entries_num() const { return entries_num; }
//------------------------------------------------------------------------------
//! \brief Get an entry
//! \param no Index of the entry
//! \param flags Flags of the entry
//! \param version_index Version index of the entry
//! \param hash Hash of the entry
//! \param dep_name Dependency name of the entry
//! \return True if successful, false otherwise
bool get_entry( Elf_Word no,
Elf_Half& flags,
Elf_Half& version_index,
Elf_Word& hash,
std::string& dep_name ) const
{
if ( versym_d_section == nullptr || ( no >= get_entries_num() ) ) {
return false;
}
const_string_section_accessor string_section_acc(
elf_file.sections[versym_d_section->get_link()] );
Elfxx_Verdef* verdef = (Elfxx_Verdef*)versym_d_section->get_data();
Elfxx_Verdaux* verdaux =
(Elfxx_Verdaux*)( (char*)verdef + verdef->vd_aux );
for ( Elf_Word i = 0; i < no; ++i ) {
verdef = (Elfxx_Verdef*)( (char*)verdef + verdef->vd_next );
verdaux = (Elfxx_Verdaux*)( (char*)verdef + verdef->vd_aux );
}
// verdef->vd_version should always be 1
// see https://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA.junk/symversion.html#VERDEFENTRIES
// verdef->vd_cnt should always be 1.
// see https://maskray.me/blog/2020-11-26-all-about-symbol-versioning
flags = verdef->vd_flags;
version_index = verdef->vd_ndx;
hash = verdef->vd_hash;
dep_name = string_section_acc.get_string( verdaux->vda_name );
return true;
}
//------------------------------------------------------------------------------
private:
const elfio& elf_file;
S* versym_d_section =
nullptr; //!< Pointer to the version definition section
Elf_Word entries_num = 0; //!< Number of entries
};
using versym_d_section_accessor = versym_d_section_accessor_template<section>;
using const_versym_d_section_accessor =
versym_d_section_accessor_template<const section>;
} // namespace ELFIO
#endif // ELFIO_VERSYM_HPP

View File

@ -47,20 +47,24 @@ class Emulator
public:
static constexpr uint8_t PC = 31;
static constexpr uint8_t LC = 30;
static constexpr uint8_t RA = 29;
static constexpr uint8_t SP = 28;
Emulator();
void run(const std::vector<uint32_t>& program);
void run(std::istream& program);
void map_device(std::unique_ptr<Device>&& device);
uint32_t& memory_at(uint16_t address);
uint32_t& memory_at(uint32_t address);
uint32_t& decode_operand(Operand operand);
uint32_t& register_at(uint8_t index);
void run_instruction();
private:
std::array<uint32_t, 1 << 16> memory;
std::array<uint32_t, 1 << 17> memory;
std::array<uint32_t, 1 << 5> registers;
enum class Status
{
@ -72,9 +76,10 @@ private:
uint32_t configuration;
uint32_t dummy_value;
std::vector<std::unique_ptr<Device>> devices;
uint16_t mapped_base;
uint32_t mapped_base;
bool keep_running;
void run_internal();
void read_instruction();
void CNST();
@ -86,6 +91,7 @@ private:
void BWOR();
void BAND();
void BXOR();
void ZRSH();
void SRSH();
void ZLSH();
void CLSH();
@ -95,6 +101,7 @@ private:
void DIVI();
void MODU();
bool should_run() const;
bool repeats() const;
uint8_t simd_elements() const;
uint8_t shift() const;
@ -104,6 +111,7 @@ private:
uint32_t op_arithmetic_negate(uint32_t a) const;
uint32_t op_logical_negate(uint32_t a) const;
uint32_t op_pad_zero_right_shift(uint32_t a, uint32_t b) const;
uint32_t op_signed_right_shift(uint32_t a, uint32_t b) const;
uint32_t op_pad_zero_left_shift(uint32_t a, uint32_t b) const;
uint32_t op_circular_left_shift(uint32_t a, uint32_t b) const;

View File

@ -2,6 +2,8 @@
#include <stdexcept>
#include <elfio/elfio.hpp>
namespace foot
{
@ -28,36 +30,52 @@ Emulator::Emulator() :
memory{},
registers{},
configuration(0),
mapped_base(0)
{}
mapped_base(0x00010000)
{
registers[SP] = 0xFFFF; // stack pointer
}
void Emulator::run(const std::vector<uint32_t>& program)
{
std::copy(program.begin(), program.end(), memory.begin());
keep_running = true;
while (keep_running)
run_internal();
}
void Emulator::run(std::istream& program)
{
ELFIO::elfio reader;
reader.load(program);
for (const auto& seg : reader.segments)
{
run_instruction();
for (auto& device : devices)
uint64_t dest = seg->get_virtual_address();
uint64_t msize = seg->get_memory_size();
uint64_t fsize = seg->get_file_size();
const char* data = seg->get_data();
if (seg->get_type() != ELFIO::PT_LOAD)
{
if (device->update())
{
keep_running = false;
}
continue;
}
memcpy(reinterpret_cast<char*>(memory.data()) + dest, data, fsize);
}
registers[PC] = reader.get_entry() / 4;
run_internal();
}
void Emulator::map_device(std::unique_ptr<Device>&& device)
{
mapped_base -= device->mapped_memory_size();
device->assigned_memory_base = &memory[mapped_base];
mapped_base += device->mapped_memory_size();
devices.push_back(std::move(device));
}
uint32_t& Emulator::memory_at(uint16_t address)
uint32_t& Emulator::memory_at(uint32_t address)
{
return memory[address];
}
@ -77,7 +95,7 @@ uint32_t& Emulator::decode_operand(Operand operand)
return memory[registers[operand.register_index]++];
case Operand::AddressingMode::Indirect:
return memory[registers[operand.register_index]];
return memory[registers[operand.register_index]];
default:
return dummy_value;
@ -93,6 +111,11 @@ void Emulator::run_instruction()
{
read_instruction();
if (!should_run())
{
return;
}
const bool rep = repeats();
const uint32_t loop_count = rep ? registers[LC] : 1;
@ -143,6 +166,10 @@ void Emulator::run_instruction()
BXOR();
break;
case 5:
ZRSH();
break;
case 6:
SRSH();
break;
@ -183,6 +210,22 @@ void Emulator::run_instruction()
if (rep) { registers[LC] = loop_count; }
}
void Emulator::run_internal()
{
keep_running = true;
while (keep_running)
{
run_instruction();
for (const auto& device : devices)
{
if (device->update())
{
keep_running = false;
}
}
}
}
void Emulator::read_instruction()
{
instruction = memory[registers[PC]++];
@ -272,6 +315,15 @@ void Emulator::BXOR()
d = a ^ b;
}
void Emulator::ZRSH()
{
uint32_t a = decode_operand(instruction & 0x000000FF);
uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8);
uint32_t& d = decode_operand((instruction & 0x00FF0000) >> 16);
d = apply_many_binary(a, b, &Emulator::op_pad_zero_right_shift);
}
void Emulator::SRSH()
{
uint32_t a = decode_operand(instruction & 0x000000FF);
@ -344,6 +396,36 @@ void Emulator::MODU()
d = apply_many_binary(a, b, &Emulator::op_mod);
}
bool Emulator::should_run() const
{
switch ((instruction & 0xE0000000) >> 29)
{
case 0:
return true;
case 1:
return status_register == Status::Less;
case 2:
return status_register == Status::Less || status_register == Status::Equal;
case 3:
return status_register == Status::Equal;
case 4:
return status_register == Status::Greater || status_register == Status::Equal;
case 5:
return status_register == Status::Greater;
case 6:
return status_register == Status::Less || status_register == Status::Greater;
default:
return false;
}
}
bool Emulator::repeats() const
{
return instruction & 0x10000000;
@ -404,6 +486,11 @@ uint32_t Emulator::op_logical_negate(uint32_t a) const
return !a;
}
uint32_t Emulator::op_pad_zero_right_shift(uint32_t a, uint32_t b) const
{
return a >> b;
}
uint32_t Emulator::op_signed_right_shift(uint32_t a, uint32_t b) const
{
return int32_t(a) >> b;

View File

@ -8,26 +8,6 @@
namespace
{
std::vector<uint32_t> read_file(std::istream& stream)
{
std::vector<uint32_t> buf;
std::streampos pos = stream.tellg();
stream.seekg(0, std::ios::end);
pos = stream.tellg() - pos;
buf.resize(pos / 4);
stream.seekg(0, std::ios::beg);
for (int i = 0; i < buf.size(); i++)
{
unsigned char value[4] = {};
stream.read((char*)value, 4);
buf[i] = uint32_t(value[0]) | (uint32_t(value[1]) << 8) | (uint32_t(value[2]) << 16) | (uint32_t(value[3]) << 24);
}
return buf;
}
class PrintDevice : public foot::Device
{
public:
@ -41,7 +21,7 @@ public:
uint32_t& value = memory(0);
if (value != 0)
{
std::cout << char(value);
SDL_Log("%1s", (char*)&value);
value = 0;
}
@ -134,7 +114,7 @@ int main(int argc, char** argv)
emu.map_device(std::make_unique<PrintDevice>());
emu.map_device(std::make_unique<MemoryViewDevice>(render, WIDTH, HEIGHT));
emu.run(read_file(file));
emu.run(file);
SDL_DestroyRenderer(render);
SDL_DestroyWindow(window);

View File

@ -15,6 +15,7 @@ test(long-instruction)
test(bwor-instruction)
test(band-instruction)
test(bxor-instruction)
test(zrsh-instruction)
test(srsh-instruction)
test(zlsh-instruction)
test(clsh-instruction)
@ -22,4 +23,4 @@ test(addi-instruction)
test(subt-instruction)
test(mult-instruction)
test(divi-instruction)
test(modu-instruction)
test(modu-instruction)

View File

@ -0,0 +1,36 @@
#include "test-common.h"
int main(int argc, char** argv)
{
// CNST
// dst - 0, Direct
// imm - 0x4567
//
// ZRSH
// dst - 0, Direct
// a - 0, Direct
// b - 2, Immediate
{
foot::Emulator emu = run_instructions({ 0x00204567, 0x05200220 });
if (!check(0x1159, emu.register_at(0))) { return 1; }
}
// CNST
// dst - 0, Direct
// imm - 0x4343
//
// CNST
// dst - 1, Direct
// imm - 0x1122
//
// ZRSH - 4-bit SIMD
// dst - 0, Direct
// a - 0, Direct
// b - 1, Direct
{
foot::Emulator emu = run_instructions({ 0x00204343, 0x00211122, 0x05A021A0 });
if (!check(0x2110, emu.register_at(0))) { return 1; }
}
return 0;
}