Remove the IR for know for simplicity
This commit is contained in:
parent
4d46fc6b4d
commit
223f54d38d
@ -19,7 +19,8 @@ add_library(elna
|
||||
source/lexer.cpp include/elna/lexer.hpp
|
||||
source/result.cpp include/elna/result.hpp
|
||||
source/riscv.cpp include/elna/riscv.hpp
|
||||
source/parser.cpp include/elna/parser.hpp
|
||||
source/ir.cpp include/elna/ir.hpp
|
||||
include/elna/parser.hpp
|
||||
source/cl.cpp include/elna/cl.hpp
|
||||
)
|
||||
target_include_directories(elna PRIVATE include)
|
||||
|
1347
include/elfio/elf_types.hpp
Normal file
1347
include/elfio/elf_types.hpp
Normal file
File diff suppressed because it is too large
Load Diff
1096
include/elfio/elfio.hpp
Normal file
1096
include/elfio/elfio.hpp
Normal file
File diff suppressed because it is too large
Load Diff
88
include/elfio/elfio_array.hpp
Normal file
88
include/elfio/elfio_array.hpp
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
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 S, typename T> class array_section_accessor_template
|
||||
{
|
||||
public:
|
||||
//------------------------------------------------------------------------------
|
||||
explicit array_section_accessor_template( const elfio& elf_file,
|
||||
S* section )
|
||||
: elf_file( elf_file ), array_section( section )
|
||||
{
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Elf_Xword get_entries_num() const
|
||||
{
|
||||
Elf_Xword entry_size = sizeof( T );
|
||||
return array_section->get_size() / entry_size;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool get_entry( Elf_Xword index, Elf64_Addr& address ) const
|
||||
{
|
||||
if ( index >= get_entries_num() ) { // Is index valid
|
||||
return false;
|
||||
}
|
||||
|
||||
const endianess_convertor& convertor = elf_file.get_convertor();
|
||||
|
||||
const T temp = *reinterpret_cast<const T*>( array_section->get_data() +
|
||||
index * sizeof( T ) );
|
||||
address = convertor( temp );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void add_entry( Elf64_Addr address )
|
||||
{
|
||||
const endianess_convertor& convertor = elf_file.get_convertor();
|
||||
|
||||
T temp = convertor( (T)address );
|
||||
array_section->append_data( reinterpret_cast<char*>( &temp ),
|
||||
sizeof( temp ) );
|
||||
}
|
||||
|
||||
private:
|
||||
//------------------------------------------------------------------------------
|
||||
const elfio& elf_file;
|
||||
S* array_section;
|
||||
};
|
||||
|
||||
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
|
1346
include/elfio/elfio_dump.hpp
Normal file
1346
include/elfio/elfio_dump.hpp
Normal file
File diff suppressed because it is too large
Load Diff
274
include/elfio/elfio_dynamic.hpp
Normal file
274
include/elfio/elfio_dynamic.hpp
Normal file
@ -0,0 +1,274 @@
|
||||
/*
|
||||
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 S> class dynamic_section_accessor_template
|
||||
{
|
||||
public:
|
||||
//------------------------------------------------------------------------------
|
||||
explicit dynamic_section_accessor_template( const elfio& elf_file,
|
||||
S* section )
|
||||
: elf_file( elf_file ), dynamic_section( section ), entries_num( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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:
|
||||
//------------------------------------------------------------------------------
|
||||
Elf_Half get_string_table_index() const
|
||||
{
|
||||
return (Elf_Half)dynamic_section->get_link();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class T>
|
||||
void generic_get_entry_dyn( Elf_Xword index,
|
||||
Elf_Xword& tag,
|
||||
Elf_Xword& value ) const
|
||||
{
|
||||
const endianess_convertor& convertor = elf_file.get_convertor();
|
||||
|
||||
// Check unusual case when dynamic section has no data
|
||||
if ( dynamic_section->get_data() == nullptr ||
|
||||
( index + 1 ) * dynamic_section->get_entry_size() >
|
||||
dynamic_section->get_size() ||
|
||||
dynamic_section->get_entry_size() < sizeof( T ) ) {
|
||||
tag = DT_NULL;
|
||||
value = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
const T* pEntry = reinterpret_cast<const T*>(
|
||||
dynamic_section->get_data() +
|
||||
index * dynamic_section->get_entry_size() );
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class T>
|
||||
void generic_add_entry_dyn( Elf_Xword tag, Elf_Xword value )
|
||||
{
|
||||
const endianess_convertor& 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:
|
||||
const elfio& elf_file;
|
||||
S* dynamic_section;
|
||||
mutable Elf_Xword entries_num;
|
||||
};
|
||||
|
||||
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
|
153
include/elfio/elfio_header.hpp
Normal file
153
include/elfio/elfio_header.hpp
Normal file
@ -0,0 +1,153 @@
|
||||
/*
|
||||
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
|
||||
{
|
||||
public:
|
||||
virtual ~elf_header() = default;
|
||||
|
||||
virtual bool load( std::istream& stream ) = 0;
|
||||
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 );
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
template <class T> class elf_header_impl : public elf_header
|
||||
{
|
||||
public:
|
||||
//------------------------------------------------------------------------------
|
||||
elf_header_impl( endianess_convertor* convertor,
|
||||
unsigned char encoding,
|
||||
const 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 );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool load( std::istream& stream ) override
|
||||
{
|
||||
stream.seekg( ( *translator )[0] );
|
||||
stream.read( reinterpret_cast<char*>( &header ), sizeof( header ) );
|
||||
|
||||
return ( stream.gcount() == sizeof( header ) );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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 = {};
|
||||
endianess_convertor* convertor = nullptr;
|
||||
const address_translator* translator = nullptr;
|
||||
};
|
||||
|
||||
} // namespace ELFIO
|
||||
|
||||
#endif // ELF_HEADER_HPP
|
124
include/elfio/elfio_modinfo.hpp
Normal file
124
include/elfio/elfio_modinfo.hpp
Normal file
@ -0,0 +1,124 @@
|
||||
/*
|
||||
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 {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class S> class modinfo_section_accessor_template
|
||||
{
|
||||
public:
|
||||
//------------------------------------------------------------------------------
|
||||
explicit modinfo_section_accessor_template( S* section )
|
||||
: modinfo_section( section )
|
||||
{
|
||||
process_section();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Elf_Word get_attribute_num() const { return (Elf_Word)content.size(); }
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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:
|
||||
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;
|
||||
std::vector<std::pair<std::string, std::string>> content;
|
||||
};
|
||||
|
||||
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
|
184
include/elfio/elfio_note.hpp
Normal file
184
include/elfio/elfio_note.hpp
Normal file
@ -0,0 +1,184 @@
|
||||
/*
|
||||
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
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class S, Elf_Xword ( S::*F_get_size )() const>
|
||||
class note_section_accessor_template
|
||||
{
|
||||
public:
|
||||
//------------------------------------------------------------------------------
|
||||
explicit note_section_accessor_template( const elfio& elf_file, S* section )
|
||||
: elf_file( elf_file ), notes( section )
|
||||
{
|
||||
process_section();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Elf_Word get_notes_num() const
|
||||
{
|
||||
return (Elf_Word)note_start_positions.size();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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 endianess_convertor& 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;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void add_note( Elf_Word type,
|
||||
const std::string& name,
|
||||
const char* desc,
|
||||
Elf_Word descSize )
|
||||
{
|
||||
const endianess_convertor& 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:
|
||||
//------------------------------------------------------------------------------
|
||||
void process_section()
|
||||
{
|
||||
const endianess_convertor& 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;
|
||||
S* notes;
|
||||
std::vector<Elf_Xword> note_start_positions;
|
||||
};
|
||||
|
||||
using note_section_accessor =
|
||||
note_section_accessor_template<section, §ion::get_size>;
|
||||
using const_note_section_accessor =
|
||||
note_section_accessor_template<const section, §ion::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
|
460
include/elfio/elfio_relocation.hpp
Normal file
460
include/elfio/elfio_relocation.hpp
Normal file
@ -0,0 +1,460 @@
|
||||
/*
|
||||
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>
|
||||
{
|
||||
static int get_r_sym( Elf_Xword info )
|
||||
{
|
||||
return ELF32_R_SYM( (Elf_Word)info );
|
||||
}
|
||||
static int get_r_type( Elf_Xword info )
|
||||
{
|
||||
return ELF32_R_TYPE( (Elf_Word)info );
|
||||
}
|
||||
};
|
||||
template <> struct get_sym_and_type<Elf32_Rela>
|
||||
{
|
||||
static int get_r_sym( Elf_Xword info )
|
||||
{
|
||||
return ELF32_R_SYM( (Elf_Word)info );
|
||||
}
|
||||
static int get_r_type( Elf_Xword info )
|
||||
{
|
||||
return ELF32_R_TYPE( (Elf_Word)info );
|
||||
}
|
||||
};
|
||||
template <> struct get_sym_and_type<Elf64_Rel>
|
||||
{
|
||||
static int get_r_sym( Elf_Xword info ) { return ELF64_R_SYM( info ); }
|
||||
static int get_r_type( Elf_Xword info ) { return ELF64_R_TYPE( info ); }
|
||||
};
|
||||
template <> struct get_sym_and_type<Elf64_Rela>
|
||||
{
|
||||
static int get_r_sym( Elf_Xword info ) { return ELF64_R_SYM( info ); }
|
||||
static int get_r_type( Elf_Xword info ) { return ELF64_R_TYPE( info ); }
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class S> class relocation_section_accessor_template
|
||||
{
|
||||
public:
|
||||
//------------------------------------------------------------------------------
|
||||
explicit relocation_section_accessor_template( const elfio& elf_file,
|
||||
S* section )
|
||||
: elf_file( elf_file ), relocation_section( section )
|
||||
{
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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() ) {
|
||||
generic_get_entry_rel<Elf32_Rel>( index, offset, symbol, type,
|
||||
addend );
|
||||
}
|
||||
else if ( SHT_RELA == relocation_section->get_type() ) {
|
||||
generic_get_entry_rela<Elf32_Rela>( index, offset, symbol, type,
|
||||
addend );
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ( SHT_REL == relocation_section->get_type() ) {
|
||||
generic_get_entry_rel<Elf64_Rel>( index, offset, symbol, type,
|
||||
addend );
|
||||
}
|
||||
else if ( SHT_RELA == relocation_section->get_type() ) {
|
||||
generic_get_entry_rela<Elf64_Rela>( index, offset, symbol, type,
|
||||
addend );
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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 );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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 );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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 );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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:
|
||||
//------------------------------------------------------------------------------
|
||||
Elf_Half get_symbol_table_index() const
|
||||
{
|
||||
return (Elf_Half)relocation_section->get_link();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class T>
|
||||
void generic_get_entry_rel( Elf_Xword index,
|
||||
Elf64_Addr& offset,
|
||||
Elf_Word& symbol,
|
||||
unsigned& type,
|
||||
Elf_Sxword& addend ) const
|
||||
{
|
||||
const endianess_convertor& convertor = elf_file.get_convertor();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class T>
|
||||
void generic_get_entry_rela( Elf_Xword index,
|
||||
Elf64_Addr& offset,
|
||||
Elf_Word& symbol,
|
||||
unsigned& type,
|
||||
Elf_Sxword& addend ) const
|
||||
{
|
||||
const endianess_convertor& convertor = elf_file.get_convertor();
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class T>
|
||||
void generic_set_entry_rel( Elf_Xword index,
|
||||
Elf64_Addr offset,
|
||||
Elf_Word symbol,
|
||||
unsigned type,
|
||||
Elf_Sxword )
|
||||
{
|
||||
const endianess_convertor& 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 );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class T>
|
||||
void generic_set_entry_rela( Elf_Xword index,
|
||||
Elf64_Addr offset,
|
||||
Elf_Word symbol,
|
||||
unsigned type,
|
||||
Elf_Sxword addend )
|
||||
{
|
||||
const endianess_convertor& 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 );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class T>
|
||||
void generic_add_entry( Elf64_Addr offset, Elf_Xword info )
|
||||
{
|
||||
const endianess_convertor& 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 ) );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class T>
|
||||
void
|
||||
generic_add_entry( Elf64_Addr offset, Elf_Xword info, Elf_Sxword addend )
|
||||
{
|
||||
const endianess_convertor& 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
|
367
include/elfio/elfio_section.hpp
Normal file
367
include/elfio/elfio_section.hpp
Normal file
@ -0,0 +1,367 @@
|
||||
/*
|
||||
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
|
||||
{
|
||||
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 );
|
||||
|
||||
virtual const char* get_data() const = 0;
|
||||
virtual void set_data( const char* raw_data, Elf_Word size ) = 0;
|
||||
virtual void set_data( const std::string& data ) = 0;
|
||||
virtual void append_data( const char* raw_data, Elf_Word size ) = 0;
|
||||
virtual void append_data( const std::string& data ) = 0;
|
||||
virtual void
|
||||
insert_data( Elf_Xword pos, const char* raw_data, Elf_Word size ) = 0;
|
||||
virtual void insert_data( Elf_Xword pos, const std::string& data ) = 0;
|
||||
virtual size_t get_stream_size() const = 0;
|
||||
virtual void set_stream_size( size_t value ) = 0;
|
||||
|
||||
protected:
|
||||
ELFIO_SET_ACCESS_DECL( Elf64_Off, offset );
|
||||
ELFIO_SET_ACCESS_DECL( Elf_Half, index );
|
||||
|
||||
virtual bool load( std::istream& stream,
|
||||
std::streampos header_offset,
|
||||
bool is_lazy ) = 0;
|
||||
virtual void save( std::ostream& stream,
|
||||
std::streampos header_offset,
|
||||
std::streampos data_offset ) = 0;
|
||||
virtual bool is_address_initialized() const = 0;
|
||||
};
|
||||
|
||||
template <class T> class section_impl : public section
|
||||
{
|
||||
public:
|
||||
//------------------------------------------------------------------------------
|
||||
section_impl( const endianess_convertor* convertor,
|
||||
const address_translator* translator,
|
||||
const 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 );
|
||||
//------------------------------------------------------------------------------
|
||||
Elf_Half get_index() const override { return index; }
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
std::string get_name() const override { return name; }
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void set_name( const std::string& name_prm ) override
|
||||
{
|
||||
this->name = name_prm;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool is_address_initialized() const override { return is_address_set; }
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
const char* get_data() const override
|
||||
{
|
||||
if ( is_lazy ) {
|
||||
load_data();
|
||||
}
|
||||
return data.get();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void set_data( const char* raw_data, Elf_Word size ) override
|
||||
{
|
||||
if ( get_type() != SHT_NOBITS ) {
|
||||
data = std::unique_ptr<char[]>( new ( std::nothrow ) char[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( data_size );
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void set_data( const std::string& str_data ) override
|
||||
{
|
||||
return set_data( str_data.c_str(), (Elf_Word)str_data.size() );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void append_data( const char* raw_data, Elf_Word size ) override
|
||||
{
|
||||
insert_data( get_size(), raw_data, size );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void append_data( const std::string& str_data ) override
|
||||
{
|
||||
return append_data( str_data.c_str(), (Elf_Word)str_data.size() );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void
|
||||
insert_data( Elf_Xword pos, const char* raw_data, Elf_Word size ) override
|
||||
{
|
||||
if ( get_type() != SHT_NOBITS ) {
|
||||
if ( get_size() + 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 {
|
||||
data_size = 2 * ( data_size + size );
|
||||
std::unique_ptr<char[]> new_data(
|
||||
new ( std::nothrow ) char[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 );
|
||||
}
|
||||
else {
|
||||
size = 0;
|
||||
}
|
||||
}
|
||||
set_size( get_size() + size );
|
||||
if ( translator->empty() ) {
|
||||
set_stream_size( get_stream_size() + size );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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() );
|
||||
}
|
||||
|
||||
size_t get_stream_size() const override { return stream_size; }
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void set_stream_size( size_t value ) override { stream_size = value; }
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
protected:
|
||||
//------------------------------------------------------------------------------
|
||||
ELFIO_GET_SET_ACCESS( Elf64_Off, offset, header.sh_offset );
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void set_index( const Elf_Half& value ) override { index = value; }
|
||||
|
||||
bool is_compressed() const
|
||||
{
|
||||
return ( ( get_flags() & SHF_RPX_DEFLATE ) ||
|
||||
( get_flags() & SHF_COMPRESSED ) ) &&
|
||||
compression != nullptr;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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_compressed() ) {
|
||||
|
||||
bool ret = load_data();
|
||||
|
||||
if ( is_compressed() ) {
|
||||
Elf_Xword size = get_size();
|
||||
Elf_Xword uncompressed_size = 0;
|
||||
auto decompressed_data = compression->inflate(
|
||||
data.get(), convertor, size, uncompressed_size );
|
||||
if ( decompressed_data != nullptr ) {
|
||||
set_size( uncompressed_size );
|
||||
data = std::move( decompressed_data );
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool load_data() const
|
||||
{
|
||||
is_lazy = false;
|
||||
Elf_Xword size = get_size();
|
||||
if ( nullptr == data && SHT_NULL != get_type() &&
|
||||
SHT_NOBITS != get_type() && size < get_stream_size() ) {
|
||||
data.reset( new ( std::nothrow ) char[size_t( size ) + 1] );
|
||||
|
||||
if ( ( 0 != size ) && ( nullptr != data ) ) {
|
||||
pstream->seekg(
|
||||
( *translator )[( *convertor )( header.sh_offset )] );
|
||||
pstream->read( data.get(), size );
|
||||
if ( static_cast<Elf_Xword>( pstream->gcount() ) != size ) {
|
||||
data = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
// refresh size because it may have changed if we had to decompress data
|
||||
size = get_size();
|
||||
data.get()[size] =
|
||||
0; // Ensure data is ended with 0 to avoid oob read
|
||||
data_size = decltype( data_size )( size );
|
||||
}
|
||||
else {
|
||||
data_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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:
|
||||
//------------------------------------------------------------------------------
|
||||
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 ) );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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;
|
||||
T header = {};
|
||||
Elf_Half index = 0;
|
||||
std::string name;
|
||||
mutable std::unique_ptr<char[]> data;
|
||||
mutable Elf_Word data_size = 0;
|
||||
const endianess_convertor* convertor = nullptr;
|
||||
const address_translator* translator = nullptr;
|
||||
const std::shared_ptr<compression_interface> compression = nullptr;
|
||||
bool is_address_set = false;
|
||||
size_t stream_size = 0;
|
||||
mutable bool is_lazy = false;
|
||||
};
|
||||
|
||||
} // namespace ELFIO
|
||||
|
||||
#endif // ELFIO_SECTION_HPP
|
254
include/elfio/elfio_segment.hpp
Normal file
254
include/elfio/elfio_segment.hpp
Normal file
@ -0,0 +1,254 @@
|
||||
/*
|
||||
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
|
||||
{
|
||||
friend class elfio;
|
||||
|
||||
public:
|
||||
virtual ~segment() = default;
|
||||
|
||||
ELFIO_GET_ACCESS_DECL( Elf_Half, index );
|
||||
ELFIO_GET_SET_ACCESS_DECL( Elf_Word, type );
|
||||
ELFIO_GET_SET_ACCESS_DECL( Elf_Word, flags );
|
||||
ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, align );
|
||||
ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, virtual_address );
|
||||
ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, physical_address );
|
||||
ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, file_size );
|
||||
ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, memory_size );
|
||||
ELFIO_GET_ACCESS_DECL( Elf64_Off, offset );
|
||||
|
||||
virtual const char* get_data() const = 0;
|
||||
|
||||
virtual Elf_Half add_section( section* psec, Elf_Xword addr_align ) = 0;
|
||||
virtual Elf_Half add_section_index( Elf_Half index,
|
||||
Elf_Xword addr_align ) = 0;
|
||||
virtual Elf_Half get_sections_num() const = 0;
|
||||
virtual Elf_Half get_section_index_at( Elf_Half num ) const = 0;
|
||||
virtual bool is_offset_initialized() const = 0;
|
||||
|
||||
protected:
|
||||
ELFIO_SET_ACCESS_DECL( Elf64_Off, offset );
|
||||
ELFIO_SET_ACCESS_DECL( Elf_Half, index );
|
||||
|
||||
virtual const std::vector<Elf_Half>& get_sections() const = 0;
|
||||
|
||||
virtual bool load( std::istream& stream,
|
||||
std::streampos header_offset,
|
||||
bool is_lazy ) = 0;
|
||||
virtual void save( std::ostream& stream,
|
||||
std::streampos header_offset,
|
||||
std::streampos data_offset ) = 0;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class T> class segment_impl : public segment
|
||||
{
|
||||
public:
|
||||
//------------------------------------------------------------------------------
|
||||
segment_impl( const endianess_convertor* convertor,
|
||||
const 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 );
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Elf_Half get_index() const override { return index; }
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
const char* get_data() const override
|
||||
{
|
||||
if ( is_lazy ) {
|
||||
load_data();
|
||||
}
|
||||
return data.get();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Elf_Half add_section( section* psec, Elf_Xword addr_align ) override
|
||||
{
|
||||
return add_section_index( psec->get_index(), addr_align );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Elf_Half get_sections_num() const override
|
||||
{
|
||||
return (Elf_Half)sections.size();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Elf_Half get_section_index_at( Elf_Half num ) const override
|
||||
{
|
||||
if ( num < sections.size() ) {
|
||||
return sections[num];
|
||||
}
|
||||
|
||||
return Elf_Half( -1 );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
protected:
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool is_offset_initialized() const override { return is_offset_set; }
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
const std::vector<Elf_Half>& get_sections() const override
|
||||
{
|
||||
return sections;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void set_index( const Elf_Half& value ) override { index = value; }
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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 ) {
|
||||
return load_data();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool load_data() const
|
||||
{
|
||||
is_lazy = false;
|
||||
if ( PT_NULL == get_type() || 0 == get_file_size() ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
pstream->seekg( ( *translator )[( *convertor )( ph.p_offset )] );
|
||||
Elf_Xword size = get_file_size();
|
||||
|
||||
if ( size > get_stream_size() ) {
|
||||
data = nullptr;
|
||||
}
|
||||
else {
|
||||
data.reset( new ( std::nothrow ) char[(size_t)size + 1] );
|
||||
|
||||
if ( nullptr != data.get() && pstream->read( data.get(), size ) ) {
|
||||
data.get()[size] = 0;
|
||||
}
|
||||
else {
|
||||
data = nullptr;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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 ) );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
size_t get_stream_size() const { return stream_size; }
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void set_stream_size( size_t value ) { stream_size = value; }
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
private:
|
||||
mutable std::istream* pstream = nullptr;
|
||||
T ph = {};
|
||||
Elf_Half index = 0;
|
||||
mutable std::unique_ptr<char[]> data;
|
||||
std::vector<Elf_Half> sections;
|
||||
const endianess_convertor* convertor = nullptr;
|
||||
const address_translator* translator = nullptr;
|
||||
size_t stream_size = 0;
|
||||
bool is_offset_set = false;
|
||||
mutable bool is_lazy = false;
|
||||
};
|
||||
|
||||
} // namespace ELFIO
|
||||
|
||||
#endif // ELFIO_SEGMENT_HPP
|
97
include/elfio/elfio_strings.hpp
Normal file
97
include/elfio/elfio_strings.hpp
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
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>
|
||||
|
||||
namespace ELFIO {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class S> class string_section_accessor_template
|
||||
{
|
||||
public:
|
||||
//------------------------------------------------------------------------------
|
||||
explicit string_section_accessor_template( S* section )
|
||||
: string_section( section )
|
||||
{
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
const char* get_string( Elf_Word index ) const
|
||||
{
|
||||
if ( string_section ) {
|
||||
const char* data = string_section->get_data();
|
||||
if ( index < string_section->get_size() && nullptr != data ) {
|
||||
size_t string_length =
|
||||
strnlen( data + index, string_section->get_size() - index );
|
||||
if ( string_length < ( string_section->get_size() - index ) )
|
||||
return data + index;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Elf_Word add_string( const char* str )
|
||||
{
|
||||
Elf_Word current_position = 0;
|
||||
|
||||
if ( string_section ) {
|
||||
// Strings are addeded 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++;
|
||||
}
|
||||
string_section->append_data(
|
||||
str, static_cast<Elf_Word>( std::strlen( str ) + 1 ) );
|
||||
}
|
||||
|
||||
return current_position;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Elf_Word add_string( const std::string& str )
|
||||
{
|
||||
return add_string( str.c_str() );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
private:
|
||||
S* string_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
|
562
include/elfio/elfio_symbols.hpp
Normal file
562
include/elfio/elfio_symbols.hpp
Normal file
@ -0,0 +1,562 @@
|
||||
/*
|
||||
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 {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class S> class symbol_section_accessor_template
|
||||
{
|
||||
public:
|
||||
//------------------------------------------------------------------------------
|
||||
explicit symbol_section_accessor_template( const elfio& elf_file,
|
||||
S* symbol_section )
|
||||
: elf_file( elf_file ), symbol_section( symbol_section )
|
||||
{
|
||||
find_hash_section();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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<uint32_t>(
|
||||
name, value, size, bind, type, section_index, other );
|
||||
}
|
||||
else {
|
||||
ret = gnu_hash_lookup<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 ) ) {
|
||||
if ( symbol_name == name ) {
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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 endianess_convertor& 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;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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 );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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 );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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 );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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:
|
||||
//------------------------------------------------------------------------------
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Elf_Half get_string_table_index() const
|
||||
{
|
||||
return (Elf_Half)symbol_section->get_link();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Elf_Half get_hash_table_index() const { return hash_section_index; }
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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 endianess_convertor& 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;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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 endianess_convertor& convertor = elf_file.get_convertor();
|
||||
|
||||
uint32_t nbuckets = *( (uint32_t*)hash_section->get_data() + 0 );
|
||||
uint32_t symoffset = *( (uint32_t*)hash_section->get_data() + 1 );
|
||||
uint32_t bloom_size = *( (uint32_t*)hash_section->get_data() + 2 );
|
||||
uint32_t bloom_shift = *( (uint32_t*)hash_section->get_data() + 3 );
|
||||
nbuckets = convertor( nbuckets );
|
||||
symoffset = convertor( symoffset );
|
||||
bloom_size = convertor( bloom_size );
|
||||
bloom_shift = convertor( bloom_shift );
|
||||
|
||||
T* bloom_filter =
|
||||
(T*)( hash_section->get_data() + 4 * sizeof( uint32_t ) );
|
||||
|
||||
uint32_t hash = elf_gnu_hash( (const unsigned char*)name.c_str() );
|
||||
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;
|
||||
|
||||
uint32_t bucket = hash % nbuckets;
|
||||
auto* buckets =
|
||||
(uint32_t*)( hash_section->get_data() + 4 * sizeof( uint32_t ) +
|
||||
bloom_size * sizeof( T ) );
|
||||
auto* chains =
|
||||
(uint32_t*)( hash_section->get_data() + 4 * sizeof( uint32_t ) +
|
||||
bloom_size * sizeof( T ) +
|
||||
nbuckets * sizeof( uint32_t ) );
|
||||
|
||||
if ( convertor( buckets[bucket] ) >= symoffset ) {
|
||||
uint32_t chain_index = convertor( buckets[bucket] ) - symoffset;
|
||||
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;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class T> const T* generic_get_symbol_ptr( Elf_Xword index ) const
|
||||
{
|
||||
if ( 0 != symbol_section->get_data() && index < get_symbols_num() ) {
|
||||
const T* pSym = reinterpret_cast<const T*>(
|
||||
symbol_section->get_data() +
|
||||
index * symbol_section->get_entry_size() );
|
||||
|
||||
return pSym;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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 T* pSym = reinterpret_cast<const T*>(
|
||||
symbol_section->get_data() +
|
||||
index * symbol_section->get_entry_size() );
|
||||
|
||||
const endianess_convertor& 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;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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 endianess_convertor& 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;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class T>
|
||||
Elf_Xword generic_arrange_local_symbols(
|
||||
std::function<void( Elf_Xword first, Elf_Xword second )> func )
|
||||
{
|
||||
const endianess_convertor& 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;
|
||||
S* symbol_section;
|
||||
Elf_Half hash_section_index{ 0 };
|
||||
const section* hash_section{ nullptr };
|
||||
};
|
||||
|
||||
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
|
302
include/elfio/elfio_utils.hpp
Normal file
302
include/elfio/elfio_utils.hpp
Normal file
@ -0,0 +1,302 @@
|
||||
/*
|
||||
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>
|
||||
|
||||
#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 endianess_convertor
|
||||
{
|
||||
public:
|
||||
//------------------------------------------------------------------------------
|
||||
void setup( unsigned char elf_file_encoding )
|
||||
{
|
||||
need_conversion = ( elf_file_encoding != get_host_encoding() );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
uint64_t operator()( 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;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
int64_t operator()( int64_t value ) const
|
||||
{
|
||||
if ( !need_conversion ) {
|
||||
return value;
|
||||
}
|
||||
return (int64_t)( *this )( (uint64_t)value );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
uint32_t operator()( uint32_t value ) const
|
||||
{
|
||||
if ( !need_conversion ) {
|
||||
return value;
|
||||
}
|
||||
value =
|
||||
( ( value & 0x000000FF ) << 24 ) | ( ( value & 0x0000FF00 ) << 8 ) |
|
||||
( ( value & 0x00FF0000 ) >> 8 ) | ( ( value & 0xFF000000 ) >> 24 );
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
int32_t operator()( int32_t value ) const
|
||||
{
|
||||
if ( !need_conversion ) {
|
||||
return value;
|
||||
}
|
||||
return (int32_t)( *this )( (uint32_t)value );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
uint16_t operator()( uint16_t value ) const
|
||||
{
|
||||
if ( !need_conversion ) {
|
||||
return value;
|
||||
}
|
||||
value =
|
||||
(uint16_t)( ( value & 0x00FF ) << 8 ) | ( ( value & 0xFF00 ) >> 8 );
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
int16_t operator()( int16_t value ) const
|
||||
{
|
||||
if ( !need_conversion ) {
|
||||
return value;
|
||||
}
|
||||
return (int16_t)( *this )( (uint16_t)value );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
int8_t operator()( int8_t value ) const { return value; }
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
uint8_t operator()( uint8_t value ) const { return value; }
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
private:
|
||||
//------------------------------------------------------------------------------
|
||||
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;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
struct address_translation
|
||||
{
|
||||
address_translation( uint64_t start, uint64_t size, uint64_t mapped_to )
|
||||
: start( start ), size( size ), mapped_to( mapped_to ){};
|
||||
std::streampos start;
|
||||
std::streampos size;
|
||||
std::streampos mapped_to;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
class address_translator
|
||||
{
|
||||
public:
|
||||
//------------------------------------------------------------------------------
|
||||
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;
|
||||
} );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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;
|
||||
}
|
||||
|
||||
bool empty() const { return addr_translations.empty(); }
|
||||
|
||||
private:
|
||||
std::vector<address_translation> addr_translations;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
inline uint32_t elf_hash( const unsigned char* name )
|
||||
{
|
||||
uint32_t h = 0;
|
||||
uint32_t g = 0;
|
||||
while ( *name != '\0' ) {
|
||||
h = ( h << 4 ) + *name++;
|
||||
g = h & 0xf0000000;
|
||||
if ( g != 0 )
|
||||
h ^= g >> 24;
|
||||
h &= ~g;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
inline uint32_t elf_gnu_hash( const unsigned char* s )
|
||||
{
|
||||
uint32_t h = 0x1505;
|
||||
for ( unsigned char c = *s; c != '\0'; c = *++s )
|
||||
h = ( h << 5 ) + h + c;
|
||||
return h;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
inline std::string to_hex_string( 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;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Consumers should write an implementation of this class and pass an instance of it to the ELFIO::elfio constructor.
|
||||
*/
|
||||
class compression_interface
|
||||
{
|
||||
public:
|
||||
virtual ~compression_interface() = default;
|
||||
/**
|
||||
* decompresses a compressed section
|
||||
*
|
||||
* @param data the buffer of compressed data
|
||||
* @param endianness_convertor pointer to an endianness_convertor instance, used to convert numbers to/from the target endianness.
|
||||
* @param compressed_size the size of the data buffer, in bytes
|
||||
* @param decompressed_size a reference to a variable where the decompressed buffer size will be stored.
|
||||
* @returns a smart pointer to the decompressed data.
|
||||
*/
|
||||
virtual std::unique_ptr<char[]>
|
||||
inflate( const char* data,
|
||||
const endianess_convertor* convertor,
|
||||
Elf_Xword compressed_size,
|
||||
Elf_Xword& uncompressed_size ) const = 0;
|
||||
|
||||
/**
|
||||
* compresses a section
|
||||
*
|
||||
* @param data the buffer of uncompressed data
|
||||
* @param endianness_convertor pointer to an endianness_convertor instance, used to convert numbers to/from the target endianness.
|
||||
* @param decompressed_size the size of the data buffer, in bytes
|
||||
* @param compressed_size a reference to a variable where the compressed buffer size will be stored.
|
||||
* @returns a smart pointer to the compressed data.
|
||||
*/
|
||||
virtual std::unique_ptr<char[]>
|
||||
deflate( const char* data,
|
||||
const endianess_convertor* convertor,
|
||||
Elf_Xword decompressed_size,
|
||||
Elf_Xword& compressed_size ) const = 0;
|
||||
};
|
||||
|
||||
} // namespace ELFIO
|
||||
|
||||
#endif // ELFIO_UTILS_HPP
|
1
include/elfio/elfio_version.hpp
Normal file
1
include/elfio/elfio_version.hpp
Normal file
@ -0,0 +1 @@
|
||||
#define ELFIO_VERSION "3.12"
|
179
include/elfio/elfio_versym.hpp
Normal file
179
include/elfio/elfio_versym.hpp
Normal file
@ -0,0 +1,179 @@
|
||||
/*
|
||||
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 {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class S> class versym_section_accessor_template
|
||||
{
|
||||
public:
|
||||
//------------------------------------------------------------------------------
|
||||
explicit versym_section_accessor_template( S* section )
|
||||
: versym_section( section )
|
||||
{
|
||||
if ( section != nullptr ) {
|
||||
entries_num = decltype( entries_num )( section->get_size() /
|
||||
sizeof( Elf_Half ) );
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Elf_Word get_entries_num() const
|
||||
{
|
||||
if ( versym_section ) {
|
||||
return entries_num;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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;
|
||||
Elf_Word entries_num = 0;
|
||||
};
|
||||
|
||||
using versym_section_accessor = versym_section_accessor_template<section>;
|
||||
using const_versym_section_accessor =
|
||||
versym_section_accessor_template<const section>;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class S> class versym_r_section_accessor_template
|
||||
{
|
||||
public:
|
||||
//------------------------------------------------------------------------------
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Elf_Word get_entries_num() const { return entries_num; }
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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;
|
||||
Elf_Word entries_num = 0;
|
||||
};
|
||||
|
||||
using versym_r_section_accessor = versym_r_section_accessor_template<section>;
|
||||
using const_versym_r_section_accessor =
|
||||
versym_r_section_accessor_template<const section>;
|
||||
|
||||
} // namespace ELFIO
|
||||
|
||||
#endif // ELFIO_VERSYM_HPP
|
7
include/elna/cl.hpp
Normal file
7
include/elna/cl.hpp
Normal file
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
namespace elna
|
||||
{
|
||||
char *readSource(const char *source);
|
||||
int compile(const char *inFile, const char *outputFilename);
|
||||
}
|
@ -1,95 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include "elna/parser.hpp"
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
namespace elna::ir
|
||||
namespace elna
|
||||
{
|
||||
class Node;
|
||||
class Definition;
|
||||
class Operand;
|
||||
class BinaryExpression;
|
||||
class Variable;
|
||||
class VariableDeclaration;
|
||||
class Number;
|
||||
|
||||
struct IRVisitor
|
||||
class TransformVisitor final : public ParserVisitor
|
||||
{
|
||||
virtual void visit(Node *) = 0;
|
||||
virtual void visit(Definition *) = 0;
|
||||
virtual void visit(Operand *) = 0;
|
||||
virtual void visit(BinaryExpression *) = 0;
|
||||
virtual void visit(Variable *) = 0;
|
||||
virtual void visit(Number *) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* AST node.
|
||||
*/
|
||||
class Node
|
||||
{
|
||||
public:
|
||||
virtual void accept(IRVisitor *) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Definition.
|
||||
*/
|
||||
class Definition : public Node
|
||||
{
|
||||
public:
|
||||
BinaryExpression **statements;
|
||||
std::size_t statementsLength;
|
||||
Operand *result;
|
||||
|
||||
virtual void accept(IRVisitor *visitor) override;
|
||||
};
|
||||
|
||||
class Statement : public Node
|
||||
{
|
||||
};
|
||||
|
||||
class Operand : public Node
|
||||
{
|
||||
public:
|
||||
virtual void accept(IRVisitor *visitor) override;
|
||||
};
|
||||
|
||||
class Number : public Operand
|
||||
{
|
||||
public:
|
||||
std::int32_t value;
|
||||
|
||||
virtual void accept(IRVisitor *visitor) override;
|
||||
};
|
||||
|
||||
class Variable : public Operand
|
||||
{
|
||||
public:
|
||||
std::size_t counter;
|
||||
|
||||
virtual void accept(IRVisitor *visitor) override;
|
||||
};
|
||||
|
||||
class BinaryExpression : public Statement
|
||||
{
|
||||
public:
|
||||
Operand *lhs, *rhs;
|
||||
BinaryOperator _operator;
|
||||
|
||||
BinaryExpression(Operand *lhs, Operand *rhs, BinaryOperator _operator);
|
||||
|
||||
virtual void accept(IRVisitor *visitor) override;
|
||||
};
|
||||
|
||||
class BangExpression : public Statement
|
||||
{
|
||||
Operand *operand;
|
||||
|
||||
public:
|
||||
BangExpression(Operand *operand);
|
||||
|
||||
virtual void accept(IRVisitor *visitor) override;
|
||||
void visit(Node *node) override;
|
||||
void visit(Definition *definition) override;
|
||||
void visit(BangStatement *statement) override;
|
||||
void visit(Block *block) override;
|
||||
void visit(Expression *expression) override;
|
||||
void visit(Number *number) override;
|
||||
void visit(Variable *variable) override;
|
||||
void visit(BinaryExpression *binaryExpression) override;
|
||||
};
|
||||
}
|
||||
|
@ -1,5 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <elna/lexer.hpp>
|
||||
|
||||
namespace elna
|
||||
{
|
||||
enum class BinaryOperator
|
||||
@ -7,4 +11,113 @@ namespace elna
|
||||
sum,
|
||||
subtraction
|
||||
};
|
||||
|
||||
class Node;
|
||||
class Definition;
|
||||
class BangStatement;
|
||||
class Block;
|
||||
class Expression;
|
||||
class BinaryExpression;
|
||||
class Variable;
|
||||
class Number;
|
||||
|
||||
struct ParserVisitor
|
||||
{
|
||||
virtual void visit(Node *) = 0;
|
||||
virtual void visit(Definition *) = 0;
|
||||
virtual void visit(BangStatement *) = 0;
|
||||
virtual void visit(Block *) = 0;
|
||||
virtual void visit(Expression *) = 0;
|
||||
virtual void visit(BinaryExpression *) = 0;
|
||||
virtual void visit(Variable *) = 0;
|
||||
virtual void visit(Number *) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* AST node.
|
||||
*/
|
||||
class Node
|
||||
{
|
||||
public:
|
||||
virtual void accept(ParserVisitor *) = 0;
|
||||
};
|
||||
|
||||
class Statement : public Node
|
||||
{
|
||||
};
|
||||
|
||||
/**
|
||||
* Constant definition.
|
||||
*/
|
||||
class Definition : public Node
|
||||
{
|
||||
public:
|
||||
Number *number;
|
||||
const char *identifier;
|
||||
|
||||
virtual void accept(ParserVisitor *visitor) override;
|
||||
};
|
||||
|
||||
class BangStatement : public Statement
|
||||
{
|
||||
public:
|
||||
Expression *expression;
|
||||
|
||||
virtual void accept(ParserVisitor *visitor) override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Block.
|
||||
*/
|
||||
class Block : public Node
|
||||
{
|
||||
public:
|
||||
Definition** definitions{ nullptr };
|
||||
size_t definitionsLength{ 0 };
|
||||
Statement *statement{ nullptr };
|
||||
|
||||
virtual void accept(ParserVisitor *visitor) override;
|
||||
};
|
||||
|
||||
class Expression : public Node
|
||||
{
|
||||
public:
|
||||
virtual void accept(ParserVisitor *visitor) override;
|
||||
};
|
||||
|
||||
class Number : public Expression
|
||||
{
|
||||
public:
|
||||
std::int32_t value;
|
||||
|
||||
virtual void accept(ParserVisitor *visitor) override;
|
||||
};
|
||||
|
||||
class Variable : public Expression
|
||||
{
|
||||
public:
|
||||
const char *identifier;
|
||||
|
||||
virtual void accept(ParserVisitor *visitor) override;
|
||||
};
|
||||
|
||||
class BinaryExpression : public Expression
|
||||
{
|
||||
public:
|
||||
Expression *lhs, *rhs;
|
||||
BinaryOperator _operator;
|
||||
|
||||
BinaryExpression(Expression *lhs, Expression *rhs, unsigned char);
|
||||
|
||||
virtual void accept(ParserVisitor *visitor) override;
|
||||
};
|
||||
|
||||
Expression *parseFactor(Token **tokens, std::size_t *length);
|
||||
Expression *parseTerm(Token **tokens, std::size_t *length);
|
||||
Expression *parseExpression(Token **tokens, std::size_t *length);
|
||||
Definition *parseDefinition(Token **tokens, std::size_t *length);
|
||||
Statement *parseStatement(Token **tokens, std::size_t *length);
|
||||
Definition **parseDefinitions(Token **tokens, std::size_t *length, std::size_t *resultLength);
|
||||
Block *parseBlock(Token **tokens, std::size_t *length);
|
||||
Block *parse(Token *tokenStream, std::size_t length);
|
||||
}
|
||||
|
@ -59,4 +59,13 @@ namespace elna
|
||||
size_t offset;
|
||||
Target target;
|
||||
};
|
||||
|
||||
struct Symbol
|
||||
{
|
||||
Symbol(const char *name);
|
||||
const char *name;
|
||||
unsigned char *text;
|
||||
std::size_t length;
|
||||
Reference symbols[3];
|
||||
};
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include "elna/ir.hpp"
|
||||
#include "elna/parser.hpp"
|
||||
#include "elna/result.hpp"
|
||||
|
||||
namespace elna
|
||||
@ -130,19 +130,27 @@ namespace elna
|
||||
std::uint32_t instruction{ 0 };
|
||||
};
|
||||
|
||||
class RiscVVisitor : public ir::IRVisitor
|
||||
class RiscVVisitor : public ParserVisitor
|
||||
{
|
||||
public:
|
||||
Instruction *instructions;
|
||||
std::size_t instructionsLength;
|
||||
bool registerInUse;
|
||||
bool registerInUse{ true };
|
||||
std::uint32_t variableCounter = 1;
|
||||
Reference references[3];
|
||||
std::int32_t *constValues{ nullptr };
|
||||
const char **constNames{ nullptr };
|
||||
std::size_t constCount{ 0 };
|
||||
|
||||
virtual void visit(ir::Node *) override;
|
||||
virtual void visit(ir::Definition *definition) override;
|
||||
virtual void visit(ir::Operand *operand) override;
|
||||
virtual void visit(ir::Variable *variable) override;
|
||||
virtual void visit(ir::Number *number) override;
|
||||
virtual void visit(ir::BinaryExpression *expression) override;
|
||||
virtual void visit(Node *) override;
|
||||
virtual void visit(Definition *definition) override;
|
||||
virtual void visit(BangStatement *statement) override;
|
||||
virtual void visit(Block *block) override;
|
||||
virtual void visit(Expression *operand) override;
|
||||
virtual void visit(Variable *variable) override;
|
||||
virtual void visit(Number *number) override;
|
||||
virtual void visit(BinaryExpression *expression) override;
|
||||
};
|
||||
|
||||
Symbol writeNext(Block *ast);
|
||||
}
|
||||
|
136
source/cl.cpp
Normal file
136
source/cl.cpp
Normal file
@ -0,0 +1,136 @@
|
||||
#include "elna/cl.hpp"
|
||||
#include "elna/result.hpp"
|
||||
#include "elna/riscv.hpp"
|
||||
#include <cstddef>
|
||||
#include <elfio/elfio.hpp>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
namespace elna
|
||||
{
|
||||
char *readSource(const char *source)
|
||||
{
|
||||
const std::size_t bufferSize = 255;
|
||||
|
||||
std::ifstream input_stream{ source };
|
||||
std::stringstream buffer;
|
||||
buffer << input_stream.rdbuf();
|
||||
input_stream.close();
|
||||
std::string contents = buffer.str();
|
||||
char *result = reinterpret_cast<char *>(malloc(contents.size() + 1));
|
||||
std::copy(std::cbegin(contents), std::cend(contents), result);
|
||||
result[contents.size()] = '\0';
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int compile(const char *inFile, const char *outputFilename)
|
||||
{
|
||||
ELFIO::elfio writer;
|
||||
|
||||
// You can't proceed before this function call!
|
||||
writer.create(ELFIO::ELFCLASS32, ELFIO::ELFDATA2LSB);
|
||||
|
||||
writer.set_os_abi(ELFIO::ELFOSABI_NONE);
|
||||
writer.set_type(ELFIO::ET_REL);
|
||||
writer.set_machine(ELFIO::EM_RISCV);
|
||||
|
||||
auto sourceText = readSource(inFile);
|
||||
if (sourceText == nullptr)
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
CompileError *compileError = nullptr;
|
||||
size_t tokensCount{ 0 };
|
||||
auto tokens = lex(sourceText, compileError, &tokensCount);
|
||||
free(sourceText);
|
||||
if (tokens == nullptr)
|
||||
{
|
||||
printf("%lu:%lu: %s\n", compileError->line(), compileError->column(), compileError->what());
|
||||
return 1;
|
||||
}
|
||||
auto ast = parse(tokens, tokensCount);
|
||||
if (ast == nullptr)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
auto program = writeNext(ast);
|
||||
|
||||
// Create code section
|
||||
ELFIO::section* text_sec = writer.sections.add(".text");
|
||||
text_sec->set_type(ELFIO::SHT_PROGBITS);
|
||||
text_sec->set_flags(ELFIO::SHF_ALLOC | ELFIO::SHF_EXECINSTR);
|
||||
text_sec->set_addr_align(0x1);
|
||||
text_sec->set_data(reinterpret_cast<const char *>(program.text), program.length);
|
||||
|
||||
// Create string table section
|
||||
ELFIO::section* str_sec = writer.sections.add(".strtab");
|
||||
str_sec->set_type(ELFIO::SHT_STRTAB);
|
||||
|
||||
// Create string table writer
|
||||
ELFIO::string_section_accessor stra(str_sec);
|
||||
// Add label name
|
||||
ELFIO::Elf32_Word str_index = stra.add_string("msg");
|
||||
|
||||
// Create read only data section
|
||||
ELFIO::section* ro_sec = writer.sections.add(".rodata");
|
||||
ro_sec->set_type(ELFIO::SHT_PROGBITS);
|
||||
ro_sec->set_flags(ELFIO::SHF_ALLOC);
|
||||
ro_sec->set_addr_align(0x4);
|
||||
ro_sec->set_data("%d\n");
|
||||
|
||||
// Create symbol table section
|
||||
ELFIO::section* sym_sec = writer.sections.add(".symtab");
|
||||
sym_sec->set_type(ELFIO::SHT_SYMTAB);
|
||||
sym_sec->set_info(2);
|
||||
sym_sec->set_addr_align(0x4);
|
||||
sym_sec->set_entry_size(writer.get_default_entry_size(ELFIO::SHT_SYMTAB));
|
||||
sym_sec->set_link(str_sec->get_index());
|
||||
|
||||
// Create symbol table writer
|
||||
ELFIO::symbol_section_accessor syma(writer, sym_sec);
|
||||
auto label_sym = syma.add_symbol(stra, ".CL0", 0x00000000, strlen("%d\n") + 1,
|
||||
ELFIO::STB_LOCAL, ELFIO::STT_NOTYPE, 0, ro_sec->get_index());
|
||||
syma.add_symbol(stra, program.name, 0x00000000, program.length,
|
||||
ELFIO::STB_GLOBAL, ELFIO::STT_FUNC, 0, text_sec->get_index());
|
||||
auto printf_sym = syma.add_symbol(stra, "printf", 0x00000000, 0,
|
||||
ELFIO::STB_GLOBAL, ELFIO::STT_NOTYPE, 0, ELFIO::SHN_UNDEF);
|
||||
|
||||
// Create relocation table section
|
||||
ELFIO::section* rel_sec = writer.sections.add(".rel.text");
|
||||
rel_sec->set_type(ELFIO::SHT_REL);
|
||||
rel_sec->set_info(text_sec->get_index());
|
||||
rel_sec->set_addr_align(0x4);
|
||||
rel_sec->set_entry_size(writer.get_default_entry_size(ELFIO::SHT_REL));
|
||||
rel_sec->set_link(sym_sec->get_index());
|
||||
rel_sec->set_flags(ELFIO::SHF_ALLOC);
|
||||
|
||||
// Create relocation table writer
|
||||
ELFIO::relocation_section_accessor rela(writer, rel_sec);
|
||||
// Add relocation entry (adjust address at offset 11)
|
||||
rela.add_entry(program.symbols[0].offset, label_sym, 26 /* ELFIO::R_RISCV_HI20 */);
|
||||
rela.add_entry(program.symbols[0].offset, label_sym, 51 /* ELFIO::R_RISCV_RELAX */);
|
||||
rela.add_entry(program.symbols[1].offset, label_sym, 27 /* ELFIO::R_RISCV_LO12_I */);
|
||||
rela.add_entry(program.symbols[1].offset, label_sym, 51 /* ELFIO::R_RISCV_RELAX */);
|
||||
rela.add_entry(program.symbols[2].offset, printf_sym, 18 /* ELFIO::R_RISCV_CALL */);
|
||||
rela.add_entry(program.symbols[2].offset, printf_sym, 51 /* ELFIO::R_RISCV_RELAX */);
|
||||
|
||||
// Another method to add the same relocation entry at one step is:
|
||||
// rela.add_entry( stra, "msg",
|
||||
// syma, 29, 0,
|
||||
// ELF_ST_INFO( STB_GLOBAL, STT_OBJECT ), 0,
|
||||
// text_sec->get_index(),
|
||||
// place_to_adjust, (unsigned char)R_386_RELATIVE );
|
||||
|
||||
/* We don't use local symbols here. There is no need to rearrange them.
|
||||
// But, for the completeness, we do this just prior 'save'
|
||||
syma.arrange_local_symbols([&](ELFIO::Elf_Xword first, ELFIO::Elf_Xword second) {
|
||||
rela.swap_symbols( first, second );
|
||||
}); */
|
||||
|
||||
// Create ELF object file
|
||||
writer.save(outputFilename);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
@ -1,154 +0,0 @@
|
||||
/**
|
||||
* Argument parsing.
|
||||
*/
|
||||
module elna.arguments;
|
||||
|
||||
import std.algorithm;
|
||||
import std.range;
|
||||
import std.sumtype;
|
||||
|
||||
struct ArgumentError
|
||||
{
|
||||
enum Type
|
||||
{
|
||||
expectedOutputFile,
|
||||
noInput,
|
||||
superfluousArguments,
|
||||
}
|
||||
|
||||
private Type type_;
|
||||
private string argument_;
|
||||
|
||||
@property Type type() const @nogc nothrow pure @safe
|
||||
{
|
||||
return this.type_;
|
||||
}
|
||||
|
||||
@property string argument() const @nogc nothrow pure @safe
|
||||
{
|
||||
return this.argument_;
|
||||
}
|
||||
|
||||
void toString(OR)(OR range)
|
||||
if (isOutputRage!OR)
|
||||
{
|
||||
final switch (Type)
|
||||
{
|
||||
case Type.expectedOutputFile:
|
||||
put(range, "Expected an output filename after -o");
|
||||
break;
|
||||
case Type.noInput:
|
||||
put(range, "No input files specified");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Supported compiler arguments.
|
||||
*/
|
||||
struct Arguments
|
||||
{
|
||||
private bool assembler_;
|
||||
private string output_;
|
||||
private string inFile_;
|
||||
|
||||
@property string inFile() @nogc nothrow pure @safe
|
||||
{
|
||||
return this.inFile_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns: Whether to generate assembly instead of an object file.
|
||||
*/
|
||||
@property bool assembler() const @nogc nothrow pure @safe
|
||||
{
|
||||
return this.assembler_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns: Output file.
|
||||
*/
|
||||
@property string output() const @nogc nothrow pure @safe
|
||||
{
|
||||
return this.output_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse command line arguments.
|
||||
*
|
||||
* The first argument is expected to be the program name (and it is
|
||||
* ignored).
|
||||
*
|
||||
* Params:
|
||||
* arguments = Command line arguments.
|
||||
*
|
||||
* Returns: Parsed arguments or an error.
|
||||
*/
|
||||
static SumType!(ArgumentError, Arguments) parse(string[] arguments)
|
||||
@nogc nothrow pure @safe
|
||||
{
|
||||
if (!arguments.empty)
|
||||
{
|
||||
arguments.popFront;
|
||||
}
|
||||
alias ReturnType = typeof(return);
|
||||
|
||||
return parseArguments(arguments).match!(
|
||||
(Arguments parsed) {
|
||||
if (parsed.inFile is null)
|
||||
{
|
||||
return ReturnType(ArgumentError(ArgumentError.Type.noInput));
|
||||
}
|
||||
else if (!arguments.empty)
|
||||
{
|
||||
return ReturnType(ArgumentError(
|
||||
ArgumentError.Type.superfluousArguments,
|
||||
arguments.front
|
||||
));
|
||||
}
|
||||
return ReturnType(parsed);
|
||||
},
|
||||
(ArgumentError argumentError) => ReturnType(argumentError)
|
||||
);
|
||||
}
|
||||
|
||||
private static SumType!(ArgumentError, Arguments) parseArguments(ref string[] arguments)
|
||||
@nogc nothrow pure @safe
|
||||
{
|
||||
Arguments parsed;
|
||||
|
||||
while (!arguments.empty)
|
||||
{
|
||||
if (arguments.front == "-s")
|
||||
{
|
||||
parsed.assembler_ = true;
|
||||
}
|
||||
else if (arguments.front == "-o")
|
||||
{
|
||||
if (arguments.empty)
|
||||
{
|
||||
return typeof(return)(ArgumentError(
|
||||
ArgumentError.Type.expectedOutputFile,
|
||||
arguments.front
|
||||
));
|
||||
}
|
||||
arguments.popFront;
|
||||
parsed.output_ = arguments.front;
|
||||
}
|
||||
else if (arguments.front == "--")
|
||||
{
|
||||
arguments.popFront;
|
||||
parsed.inFile_ = arguments.front;
|
||||
arguments.popFront;
|
||||
break;
|
||||
}
|
||||
else if (!arguments.front.startsWith("-"))
|
||||
{
|
||||
parsed.inFile_ = arguments.front;
|
||||
}
|
||||
arguments.popFront;
|
||||
}
|
||||
return typeof(return)(parsed);
|
||||
}
|
||||
}
|
@ -4,9 +4,7 @@ import core.stdc.stdio;
|
||||
import core.stdc.stdlib;
|
||||
import core.stdc.string;
|
||||
import elna.elf;
|
||||
import elna.ir;
|
||||
import elna.extended;
|
||||
import elna.riscv;
|
||||
import elna.lexer;
|
||||
import elna.parser;
|
||||
import elna.result;
|
||||
@ -18,27 +16,16 @@ import tanya.container.array;
|
||||
import tanya.container.string;
|
||||
import tanya.memory.allocator;
|
||||
|
||||
private char* readSource(string source) @nogc
|
||||
{
|
||||
enum size_t bufferSize = 255;
|
||||
auto sourceFilename = String(source);
|
||||
extern(C++, "elna")
|
||||
Symbol writeNext(Block ast) @nogc;
|
||||
|
||||
return readFile(sourceFilename).match!(
|
||||
(ErrorCode errorCode) {
|
||||
perror(sourceFilename.toStringz);
|
||||
return null;
|
||||
},
|
||||
(Array!ubyte contents) {
|
||||
char* cString = cast(char*) malloc(contents.length + 1);
|
||||
memcpy(cString, contents.get.ptr, contents.length);
|
||||
cString[contents.length] = '\0';
|
||||
extern(C++, "elna")
|
||||
char* readSource(const(char)* source) @nogc;
|
||||
|
||||
return cString;
|
||||
}
|
||||
);
|
||||
}
|
||||
extern(C++, "elna")
|
||||
int compile(const(char)* inFile, const(char)* outputFilename) @nogc;
|
||||
|
||||
int generate(string inFile, ref String outputFilename) @nogc
|
||||
int generate(const(char)* inFile, const(char)* outputFilename) @nogc
|
||||
{
|
||||
auto sourceText = readSource(inFile);
|
||||
if (sourceText is null)
|
||||
@ -54,32 +41,24 @@ int generate(string inFile, ref String outputFilename) @nogc
|
||||
printf("%lu:%lu: %s\n", compileError.line, compileError.column, compileError.what);
|
||||
return 1;
|
||||
}
|
||||
auto ast = parse(tokens[0 .. tokensCount]);
|
||||
if (!ast.valid)
|
||||
auto ast = parse(tokens, tokensCount);
|
||||
if (ast is null)
|
||||
{
|
||||
compileError = ast.error.get;
|
||||
printf("%lu:%lu: %s\n", compileError.line, compileError.column, compileError.what);
|
||||
return 2;
|
||||
}
|
||||
auto transformVisitor = cast(TransformVisitor) malloc(__traits(classInstanceSize, TransformVisitor));
|
||||
(cast(void*) transformVisitor)[0 .. __traits(classInstanceSize, TransformVisitor)] = __traits(initSymbol, TransformVisitor)[];
|
||||
auto handle = File.open(outputFilename, BitFlags!(File.Mode)(File.Mode.truncate));
|
||||
|
||||
auto ir = transformVisitor.visit(ast.result);
|
||||
|
||||
transformVisitor.__xdtor();
|
||||
free(cast(void*) transformVisitor);
|
||||
|
||||
auto handle = File.open(outputFilename.toStringz, BitFlags!(File.Mode)(File.Mode.truncate));
|
||||
if (!handle.valid)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
auto program = writeNext(ir);
|
||||
auto program = writeNext(ast);
|
||||
auto elf = Elf!ELFCLASS32(move(handle));
|
||||
auto readOnlyData = Array!ubyte(cast(const(ubyte)[]) "%d\n".ptr[0 .. 4]); // With \0.
|
||||
auto text = Array!ubyte(program.text[0 .. program.length]);
|
||||
|
||||
elf.addReadOnlyData(String(".CL0"), readOnlyData);
|
||||
elf.addCode(program.name, program.text);
|
||||
elf.addCode(String(program.name[0 .. strlen(program.name)]), text);
|
||||
|
||||
elf.addExternSymbol(String("printf"));
|
||||
foreach (ref reference; program.symbols)
|
||||
|
@ -297,10 +297,10 @@ struct File
|
||||
*
|
||||
* See_Also: $(D_PSYMBOL File.read)
|
||||
*/
|
||||
SumType!(ErrorCode, Array!ubyte) readFile(String sourceFilename) @nogc
|
||||
SumType!(ErrorCode, Array!ubyte) readFile(const(char)* sourceFilename) @nogc
|
||||
{
|
||||
enum size_t bufferSize = 255;
|
||||
auto sourceFile = File.open(sourceFilename.toStringz, BitFlags!(File.Mode)(File.Mode.read));
|
||||
auto sourceFile = File.open(sourceFilename, BitFlags!(File.Mode)(File.Mode.read));
|
||||
|
||||
if (!sourceFile.valid)
|
||||
{
|
||||
|
220
source/elna/ir.d
220
source/elna/ir.d
@ -1,220 +0,0 @@
|
||||
module elna.ir;
|
||||
|
||||
import core.stdc.stdlib;
|
||||
import parser = elna.parser;
|
||||
import tanya.container.array;
|
||||
import tanya.container.hashtable;
|
||||
import tanya.container.string;
|
||||
import tanya.memory.allocator;
|
||||
public import elna.parser : BinaryOperator;
|
||||
|
||||
/**
|
||||
* Mapping between the parser and IR AST.
|
||||
*/
|
||||
struct ASTMapping
|
||||
{
|
||||
alias Node = .Node;
|
||||
alias Definition = .Definition;
|
||||
alias Statement = .Operand;
|
||||
alias BangStatement = .Operand;
|
||||
alias Block = .Definition;
|
||||
alias Expression = .Operand;
|
||||
alias Number = .Number;
|
||||
alias Variable = .Number;
|
||||
alias BinaryExpression = .Variable;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* IR visitor.
|
||||
*/
|
||||
extern(C++, "elna", "ir")
|
||||
abstract class IRVisitor
|
||||
{
|
||||
abstract void visit(Node) @nogc;
|
||||
abstract void visit(Definition) @nogc;
|
||||
abstract void visit(Operand) @nogc;
|
||||
abstract void visit(BinaryExpression) @nogc;
|
||||
abstract void visit(Variable) @nogc;
|
||||
abstract void visit(Number) @nogc;
|
||||
}
|
||||
|
||||
/**
|
||||
* AST node.
|
||||
*/
|
||||
extern(C++, "elna", "ir")
|
||||
abstract class Node
|
||||
{
|
||||
abstract void accept(IRVisitor) @nogc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Definition.
|
||||
*/
|
||||
extern(C++, "elna", "ir")
|
||||
class Definition : Node
|
||||
{
|
||||
BinaryExpression* statements;
|
||||
size_t statementsLength;
|
||||
Operand result;
|
||||
|
||||
override void accept(IRVisitor visitor) @nogc;
|
||||
}
|
||||
|
||||
extern(C++, "elna", "ir")
|
||||
abstract class Statement : Node
|
||||
{
|
||||
}
|
||||
|
||||
extern(C++, "elna", "ir")
|
||||
abstract class Operand : Node
|
||||
{
|
||||
override void accept(IRVisitor visitor) @nogc;
|
||||
}
|
||||
|
||||
extern(C++, "elna", "ir")
|
||||
class Number : Operand
|
||||
{
|
||||
int value;
|
||||
|
||||
override void accept(IRVisitor visitor) @nogc;
|
||||
}
|
||||
|
||||
extern(C++, "elna", "ir")
|
||||
class Variable : Operand
|
||||
{
|
||||
size_t counter;
|
||||
|
||||
override void accept(IRVisitor visitor) @nogc;
|
||||
}
|
||||
|
||||
extern(C++, "elna", "ir")
|
||||
class BinaryExpression : Statement
|
||||
{
|
||||
Operand lhs, rhs;
|
||||
BinaryOperator operator;
|
||||
|
||||
this(Operand lhs, Operand rhs, BinaryOperator operator) @nogc;
|
||||
|
||||
override void accept(IRVisitor visitor) @nogc;
|
||||
}
|
||||
|
||||
extern(C++, "elna", "ir")
|
||||
class BangExpression : Statement
|
||||
{
|
||||
Operand operand;
|
||||
|
||||
this(Operand operand);
|
||||
|
||||
override void accept(IRVisitor visitor) @nogc;
|
||||
}
|
||||
|
||||
final class TransformVisitor : parser.ParserVisitor!ASTMapping
|
||||
{
|
||||
private HashTable!(String, int) constants;
|
||||
private BinaryExpression* statements;
|
||||
private size_t statementsLength;
|
||||
|
||||
ASTMapping.Node visit(parser.Node node) @nogc
|
||||
{
|
||||
assert(false, "Not implemented");
|
||||
}
|
||||
|
||||
ASTMapping.Definition visit(parser.Definition definition) @nogc
|
||||
{
|
||||
assert(false, "Not implemented");
|
||||
}
|
||||
|
||||
ASTMapping.BangStatement visit(parser.BangStatement statement) @nogc
|
||||
{
|
||||
return statement.expression.accept(this);
|
||||
}
|
||||
|
||||
ASTMapping.Block visit(parser.Block block) @nogc
|
||||
{
|
||||
auto target = defaultAllocator.make!Definition;
|
||||
this.constants = transformConstants(block.definitions);
|
||||
|
||||
target.result = block.statement.accept(this);
|
||||
target.statements = this.statements;
|
||||
target.statementsLength = this.statementsLength;
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
ASTMapping.Expression visit(parser.Expression expression) @nogc
|
||||
{
|
||||
if ((cast(parser.Number) expression) !is null)
|
||||
{
|
||||
return (cast(parser.Number) expression).accept(this);
|
||||
}
|
||||
if ((cast(parser.Variable) expression) !is null)
|
||||
{
|
||||
return (cast(parser.Variable) expression).accept(this);
|
||||
}
|
||||
else if ((cast(parser.BinaryExpression) expression) !is null)
|
||||
{
|
||||
return (cast(parser.BinaryExpression) expression).accept(this);
|
||||
}
|
||||
assert(false, "Invalid expression type");
|
||||
}
|
||||
|
||||
ASTMapping.Number visit(parser.Number number) @nogc
|
||||
{
|
||||
auto numberExpression = defaultAllocator.make!Number;
|
||||
numberExpression.value = number.value;
|
||||
|
||||
return numberExpression;
|
||||
}
|
||||
|
||||
ASTMapping.Variable visit(parser.Variable variable) @nogc
|
||||
{
|
||||
auto numberExpression = defaultAllocator.make!Number;
|
||||
numberExpression.value = this.constants[variable.identifier];
|
||||
|
||||
return numberExpression;
|
||||
}
|
||||
|
||||
ASTMapping.BinaryExpression visit(parser.BinaryExpression binaryExpression) @nogc
|
||||
{
|
||||
auto target = defaultAllocator.make!BinaryExpression(
|
||||
binaryExpression.lhs.accept(this),
|
||||
binaryExpression.rhs.accept(this),
|
||||
binaryExpression.operator
|
||||
);
|
||||
this.statements = cast(BinaryExpression*)
|
||||
realloc(this.statements, (this.statementsLength + 1) * BinaryExpression.sizeof);
|
||||
this.statements[this.statementsLength++] = target;
|
||||
|
||||
auto newVariable = defaultAllocator.make!Variable;
|
||||
newVariable.counter = this.statementsLength;
|
||||
|
||||
return newVariable;
|
||||
}
|
||||
|
||||
private Number transformNumber(parser.Number number) @nogc
|
||||
{
|
||||
return defaultAllocator.make!Number(number.value);
|
||||
}
|
||||
|
||||
override Operand visit(parser.Statement statement) @nogc
|
||||
{
|
||||
if ((cast(parser.BangStatement) statement) !is null)
|
||||
{
|
||||
return (cast(parser.BangStatement) statement).accept(this);
|
||||
}
|
||||
assert(false, "Invalid statement type");
|
||||
}
|
||||
|
||||
private HashTable!(String, int) transformConstants(ref Array!(parser.Definition) definitions) @nogc
|
||||
{
|
||||
typeof(return) constants;
|
||||
|
||||
foreach (definition; definitions[])
|
||||
{
|
||||
constants[definition.identifier] = definition.number.value;
|
||||
}
|
||||
|
||||
return constants;
|
||||
}
|
||||
}
|
@ -1,12 +1,7 @@
|
||||
module elna.lexer;
|
||||
|
||||
import core.stdc.stdlib;
|
||||
import core.stdc.ctype;
|
||||
import core.stdc.string;
|
||||
import elna.result;
|
||||
import std.range;
|
||||
import tanya.container.array;
|
||||
import tanya.container.string;
|
||||
|
||||
extern(C++, "elna")
|
||||
struct Token
|
||||
@ -56,62 +51,5 @@ struct Token
|
||||
@property const(Position) position() const @nogc nothrow pure @safe;
|
||||
}
|
||||
|
||||
/**
|
||||
* Range over the source text that keeps track of the current position.
|
||||
*/
|
||||
struct Source
|
||||
{
|
||||
const(char)* buffer;
|
||||
Position position;
|
||||
|
||||
this(const(char)* buffer) @nogc nothrow pure @safe
|
||||
{
|
||||
this.buffer = buffer;
|
||||
}
|
||||
|
||||
@disable this();
|
||||
|
||||
bool empty() @nogc nothrow pure @safe
|
||||
{
|
||||
return this.buffer is null || this.buffer[0] == '\0';
|
||||
}
|
||||
|
||||
char front() @nogc nothrow pure @safe
|
||||
in (!empty)
|
||||
{
|
||||
return this.buffer[0];
|
||||
}
|
||||
|
||||
void popFront() @nogc nothrow pure
|
||||
in (!empty)
|
||||
{
|
||||
++this.buffer;
|
||||
++this.position.column;
|
||||
}
|
||||
|
||||
void breakLine() @nogc nothrow pure
|
||||
in (!empty)
|
||||
{
|
||||
++this.buffer;
|
||||
++this.position.line;
|
||||
this.position.column = 1;
|
||||
}
|
||||
|
||||
@property size_t length() const @nogc nothrow pure
|
||||
{
|
||||
return strlen(this.buffer);
|
||||
}
|
||||
|
||||
char opIndex(size_t index) @nogc nothrow pure
|
||||
{
|
||||
return this.buffer[index];
|
||||
}
|
||||
|
||||
const(char)[] opSlice(size_t i, size_t j) @nogc nothrow pure
|
||||
{
|
||||
return this.buffer[i .. j];
|
||||
}
|
||||
}
|
||||
|
||||
extern(C++, "elna")
|
||||
Token* lex(const(char)* buffer, CompileError* compileError, size_t* length) @nogc;
|
||||
|
@ -1,109 +1,92 @@
|
||||
module elna.parser;
|
||||
|
||||
import core.stdc.string;
|
||||
import core.stdc.stdlib;
|
||||
import elna.lexer;
|
||||
import elna.result;
|
||||
import tanya.container.array;
|
||||
import tanya.container.string;
|
||||
import tanya.memory.allocator;
|
||||
import std.array;
|
||||
|
||||
/**
|
||||
* Parser visitor.
|
||||
*/
|
||||
interface ParserVisitor(Mapping)
|
||||
extern(C++, "elna")
|
||||
abstract class ParserVisitor
|
||||
{
|
||||
Mapping.Node visit(Node) @nogc;
|
||||
Mapping.Definition visit(Definition) @nogc;
|
||||
Mapping.Statement visit(Statement) @nogc;
|
||||
Mapping.BangStatement visit(BangStatement) @nogc;
|
||||
Mapping.Block visit(Block) @nogc;
|
||||
Mapping.Expression visit(Expression) @nogc;
|
||||
Mapping.Number visit(Number) @nogc;
|
||||
Mapping.Variable visit(Variable) @nogc;
|
||||
Mapping.BinaryExpression visit(BinaryExpression) @nogc;
|
||||
abstract void visit(Node) @nogc;
|
||||
abstract void visit(Definition) @nogc;
|
||||
abstract void visit(BangStatement) @nogc;
|
||||
abstract void visit(Block) @nogc;
|
||||
abstract void visit(Expression) @nogc;
|
||||
abstract void visit(BinaryExpression) @nogc;
|
||||
abstract void visit(Variable) @nogc;
|
||||
abstract void visit(Number) @nogc;
|
||||
}
|
||||
|
||||
/**
|
||||
* AST node.
|
||||
*/
|
||||
extern(C++, "elna")
|
||||
abstract class Node
|
||||
{
|
||||
Mapping.Node accept(Mapping)(ParserVisitor!Mapping visitor) @nogc
|
||||
{
|
||||
return visitor.visit(this);
|
||||
}
|
||||
abstract void accept(ParserVisitor visitor) @nogc;
|
||||
}
|
||||
|
||||
extern(C++, "elna")
|
||||
abstract class Statement : Node
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Constant definition.
|
||||
*/
|
||||
extern(C++, "elna")
|
||||
class Definition : Node
|
||||
{
|
||||
Number number;
|
||||
String identifier;
|
||||
const(char)* identifier;
|
||||
|
||||
Mapping.Definition accept(Mapping)(ParserVisitor!Mapping visitor) @nogc
|
||||
{
|
||||
return visitor.visit(this);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class Statement : Node
|
||||
{
|
||||
Mapping.Statement accept(Mapping)(ParserVisitor!Mapping visitor) @nogc
|
||||
{
|
||||
return visitor.visit(this);
|
||||
}
|
||||
override void accept(ParserVisitor visitor) @nogc;
|
||||
}
|
||||
|
||||
extern(C++, "elna")
|
||||
class BangStatement : Statement
|
||||
{
|
||||
Expression expression;
|
||||
|
||||
Mapping.BangStatement accept(Mapping)(ParserVisitor!Mapping visitor) @nogc
|
||||
{
|
||||
return visitor.visit(this);
|
||||
}
|
||||
override void accept(ParserVisitor visitor) @nogc;
|
||||
}
|
||||
|
||||
extern(C++, "elna")
|
||||
class Block : Node
|
||||
{
|
||||
Array!Definition definitions;
|
||||
Definition* definitions;
|
||||
size_t definitionsLength;
|
||||
Statement statement;
|
||||
|
||||
Mapping.Block accept(Mapping)(ParserVisitor!Mapping visitor) @nogc
|
||||
{
|
||||
return visitor.visit(this);
|
||||
}
|
||||
override void accept(ParserVisitor visitor) @nogc;
|
||||
}
|
||||
|
||||
extern(C++, "elna")
|
||||
abstract class Expression : Node
|
||||
{
|
||||
Mapping.Expression accept(Mapping)(ParserVisitor!Mapping visitor) @nogc
|
||||
{
|
||||
return visitor.visit(this);
|
||||
}
|
||||
override void accept(ParserVisitor visitor) @nogc;
|
||||
}
|
||||
|
||||
extern(C++, "elna")
|
||||
class Number : Expression
|
||||
{
|
||||
int value;
|
||||
|
||||
Mapping.Number accept(Mapping)(ParserVisitor!Mapping visitor) @nogc
|
||||
{
|
||||
return visitor.visit(this);
|
||||
}
|
||||
override void accept(ParserVisitor visitor) @nogc;
|
||||
}
|
||||
|
||||
extern(C++, "elna")
|
||||
class Variable : Expression
|
||||
{
|
||||
String identifier;
|
||||
const(char)* identifier;
|
||||
|
||||
Mapping.Variable accept(Mapping)(ParserVisitor!Mapping visitor) @nogc
|
||||
{
|
||||
return visitor.visit(this);
|
||||
}
|
||||
override void accept(ParserVisitor visitor) @nogc;
|
||||
}
|
||||
|
||||
extern(C++, "elna")
|
||||
@ -113,196 +96,15 @@ enum BinaryOperator
|
||||
subtraction
|
||||
}
|
||||
|
||||
extern(C++, "elna")
|
||||
class BinaryExpression : Expression
|
||||
{
|
||||
Expression lhs, rhs;
|
||||
BinaryOperator operator;
|
||||
|
||||
this(Expression lhs, Expression rhs, String operator) @nogc
|
||||
{
|
||||
this.lhs = lhs;
|
||||
this.rhs = rhs;
|
||||
if (operator == "+")
|
||||
{
|
||||
this.operator = BinaryOperator.sum;
|
||||
}
|
||||
else if (operator == "-")
|
||||
{
|
||||
this.operator = BinaryOperator.subtraction;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false, "Invalid binary operator");
|
||||
}
|
||||
}
|
||||
|
||||
Mapping.BinaryExpression accept(Mapping)(ParserVisitor!Mapping visitor) @nogc
|
||||
{
|
||||
return visitor.visit(this);
|
||||
}
|
||||
this(Expression lhs, Expression rhs, ubyte operator) @nogc;
|
||||
override void accept(ParserVisitor visitor) @nogc;
|
||||
}
|
||||
|
||||
private Result!Expression parseFactor(ref Token[] tokens) @nogc
|
||||
in (!tokens.empty, "Expected factor, got end of stream")
|
||||
{
|
||||
if (tokens.front.of() == Token.Type.identifier)
|
||||
{
|
||||
auto variable = defaultAllocator.make!Variable;
|
||||
variable.identifier = tokens.front.identifier()[0 .. strlen(tokens.front.identifier())];
|
||||
tokens.popFront;
|
||||
return Result!Expression(variable);
|
||||
}
|
||||
else if (tokens.front.of() == Token.Type.number)
|
||||
{
|
||||
auto number = defaultAllocator.make!Number;
|
||||
number.value = tokens.front.number();
|
||||
tokens.popFront;
|
||||
return Result!Expression(number);
|
||||
}
|
||||
else if (tokens.front.of() == Token.Type.leftParen)
|
||||
{
|
||||
tokens.popFront;
|
||||
|
||||
auto expression = parseExpression(tokens);
|
||||
|
||||
tokens.popFront;
|
||||
return expression;
|
||||
}
|
||||
return Result!Expression("Expected a factor", tokens.front.position);
|
||||
}
|
||||
|
||||
private Result!Expression parseTerm(ref Token[] tokens) @nogc
|
||||
{
|
||||
return parseFactor(tokens);
|
||||
}
|
||||
|
||||
private Result!Expression parseExpression(ref Token[] tokens) @nogc
|
||||
in (!tokens.empty, "Expected expression, got end of stream")
|
||||
{
|
||||
auto term = parseTerm(tokens);
|
||||
if (!term.valid || tokens.empty || tokens.front.of() != Token.Type.operator)
|
||||
{
|
||||
return term;
|
||||
}
|
||||
auto operator = String(tokens.front.identifier()[0 .. strlen(tokens.front.identifier())]);
|
||||
tokens.popFront;
|
||||
|
||||
auto expression = parseExpression(tokens);
|
||||
|
||||
if (expression.valid)
|
||||
{
|
||||
auto binaryExpression = defaultAllocator
|
||||
.make!BinaryExpression(term.result, expression.result, operator);
|
||||
|
||||
return Result!Expression(binaryExpression);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Result!Expression("Expected right-hand side to be an expression", tokens.front.position);
|
||||
}
|
||||
}
|
||||
|
||||
private Result!Definition parseDefinition(ref Token[] tokens) @nogc
|
||||
in (!tokens.empty, "Expected definition, got end of stream")
|
||||
{
|
||||
auto definition = defaultAllocator.make!Definition;
|
||||
definition.identifier = tokens.front.identifier()[0 .. strlen(tokens.front.identifier())]; // Copy.
|
||||
|
||||
tokens.popFront();
|
||||
tokens.popFront(); // Skip the equals sign.
|
||||
|
||||
if (tokens.front.of() == Token.Type.number)
|
||||
{
|
||||
auto number = defaultAllocator.make!Number;
|
||||
number.value = tokens.front.number();
|
||||
definition.number = number;
|
||||
tokens.popFront;
|
||||
return Result!Definition(definition);
|
||||
}
|
||||
return Result!Definition("Expected a number", tokens.front.position);
|
||||
}
|
||||
|
||||
private Result!Statement parseStatement(ref Token[] tokens) @nogc
|
||||
in (!tokens.empty, "Expected block, got end of stream")
|
||||
{
|
||||
if (tokens.front.of() == Token.Type.bang)
|
||||
{
|
||||
tokens.popFront;
|
||||
auto statement = defaultAllocator.make!BangStatement;
|
||||
auto expression = parseExpression(tokens);
|
||||
if (expression.valid)
|
||||
{
|
||||
statement.expression = expression.result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Result!Statement(expression.error.get);
|
||||
}
|
||||
return Result!Statement(statement);
|
||||
}
|
||||
return Result!Statement("Expected ! statement", tokens.front.position);
|
||||
}
|
||||
|
||||
private Result!(Array!Definition) parseDefinitions(ref Token[] tokens) @nogc
|
||||
in (!tokens.empty, "Expected definition, got end of stream")
|
||||
{
|
||||
tokens.popFront; // Skip const.
|
||||
|
||||
Array!Definition definitions;
|
||||
|
||||
while (!tokens.empty)
|
||||
{
|
||||
auto definition = parseDefinition(tokens);
|
||||
if (!definition.valid)
|
||||
{
|
||||
return typeof(return)(definition.error.get);
|
||||
}
|
||||
definitions.insertBack(definition.result);
|
||||
if (tokens.front.of() == Token.Type.semicolon)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (tokens.front.of() == Token.Type.comma)
|
||||
{
|
||||
tokens.popFront;
|
||||
}
|
||||
}
|
||||
|
||||
return typeof(return)(definitions);
|
||||
}
|
||||
|
||||
private Result!Block parseBlock(ref Token[] tokens) @nogc
|
||||
in (!tokens.empty, "Expected block, got end of stream")
|
||||
{
|
||||
auto block = defaultAllocator.make!Block;
|
||||
if (tokens.front.of() == Token.Type.let)
|
||||
{
|
||||
auto constDefinitions = parseDefinitions(tokens);
|
||||
if (constDefinitions.valid)
|
||||
{
|
||||
block.definitions = constDefinitions.result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Result!Block(constDefinitions.error.get);
|
||||
}
|
||||
tokens.popFront;
|
||||
}
|
||||
auto statement = parseStatement(tokens);
|
||||
if (statement.valid)
|
||||
{
|
||||
block.statement = statement.result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Result!Block(statement.error.get);
|
||||
}
|
||||
|
||||
return Result!Block(block);
|
||||
}
|
||||
|
||||
Result!Block parse(Token[] tokenStream) @nogc
|
||||
{
|
||||
auto tokens = tokenStream[];
|
||||
return parseBlock(tokens);
|
||||
}
|
||||
extern(C++, "elna")
|
||||
Block parse(Token* tokenStream, size_t length) @nogc;
|
||||
|
@ -90,9 +90,12 @@ struct Reference
|
||||
Target target;
|
||||
}
|
||||
|
||||
extern(C++, "elna")
|
||||
struct Symbol
|
||||
{
|
||||
String name;
|
||||
Array!ubyte text;
|
||||
Array!Reference symbols;
|
||||
this(const(char)* name) @nogc;
|
||||
const(char)* name;
|
||||
ubyte* text;
|
||||
size_t length;
|
||||
Reference[3] symbols;
|
||||
}
|
||||
|
@ -1,183 +0,0 @@
|
||||
module elna.riscv;
|
||||
|
||||
import core.stdc.stdlib;
|
||||
import elna.ir;
|
||||
import elna.result;
|
||||
import tanya.container.array;
|
||||
import tanya.container.string;
|
||||
|
||||
extern(C++, "elna")
|
||||
enum XRegister : ubyte
|
||||
{
|
||||
zero = 0,
|
||||
ra = 1,
|
||||
sp = 2,
|
||||
gp = 3,
|
||||
tp = 4,
|
||||
t0 = 5,
|
||||
t1 = 6,
|
||||
t2 = 7,
|
||||
s0 = 8,
|
||||
s1 = 9,
|
||||
a0 = 10,
|
||||
a1 = 11,
|
||||
a2 = 12,
|
||||
a3 = 13,
|
||||
a4 = 14,
|
||||
a5 = 15,
|
||||
a6 = 16,
|
||||
a7 = 17,
|
||||
s2 = 18,
|
||||
s3 = 19,
|
||||
s4 = 20,
|
||||
s5 = 21,
|
||||
s6 = 22,
|
||||
s7 = 23,
|
||||
s8 = 24,
|
||||
s9 = 25,
|
||||
s10 = 26,
|
||||
s11 = 27,
|
||||
t3 = 28,
|
||||
t4 = 29,
|
||||
t5 = 30,
|
||||
t6 = 31,
|
||||
}
|
||||
|
||||
extern(C++, "elna")
|
||||
enum Funct3 : ubyte
|
||||
{
|
||||
addi = 0b000,
|
||||
slti = 0b001,
|
||||
sltiu = 0b011,
|
||||
andi = 0b111,
|
||||
ori = 0b110,
|
||||
xori = 0b100,
|
||||
slli = 0b000,
|
||||
srli = 0b101,
|
||||
srai = 0b101,
|
||||
add = 0b000,
|
||||
slt = 0b010,
|
||||
sltu = 0b011,
|
||||
and = 0b111,
|
||||
or = 0b110,
|
||||
xor = 0b100,
|
||||
sll = 0b001,
|
||||
srl = 0b101,
|
||||
sub = 0b000,
|
||||
sra = 0b101,
|
||||
beq = 0b000,
|
||||
bne = 0b001,
|
||||
blt = 0b100,
|
||||
bltu = 0b110,
|
||||
bge = 0b101,
|
||||
bgeu = 0b111,
|
||||
fence = 0b000,
|
||||
fenceI = 0b001,
|
||||
csrrw = 0b001,
|
||||
csrrs = 0b010,
|
||||
csrrc = 0b011,
|
||||
csrrwi = 0b101,
|
||||
csrrsi = 0b110,
|
||||
csrrci = 0b111,
|
||||
priv = 0b000,
|
||||
sb = 0b000,
|
||||
sh = 0b001,
|
||||
sw = 0b010,
|
||||
lb = 0b000,
|
||||
lh = 0b001,
|
||||
lw = 0b010,
|
||||
lbu = 0b100,
|
||||
lhu = 0b101,
|
||||
jalr = 0b000,
|
||||
}
|
||||
|
||||
extern(C++, "elna")
|
||||
enum Funct12 : ubyte
|
||||
{
|
||||
ecall = 0b000000000000,
|
||||
ebreak = 0b000000000001,
|
||||
}
|
||||
|
||||
extern(C++, "elna")
|
||||
enum Funct7 : ubyte
|
||||
{
|
||||
none = 0,
|
||||
sub = 0b0100000
|
||||
}
|
||||
|
||||
extern(C++, "elna")
|
||||
enum BaseOpcode : ubyte
|
||||
{
|
||||
opImm = 0b0010011,
|
||||
lui = 0b0110111,
|
||||
auipc = 0b0010111,
|
||||
op = 0b0110011,
|
||||
jal = 0b1101111,
|
||||
jalr = 0b1100111,
|
||||
branch = 0b1100011,
|
||||
load = 0b0000011,
|
||||
store = 0b0100011,
|
||||
miscMem = 0b0001111,
|
||||
system = 0b1110011,
|
||||
}
|
||||
|
||||
extern(C++, "elna")
|
||||
struct Instruction
|
||||
{
|
||||
private uint instruction;
|
||||
|
||||
this(BaseOpcode opcode) @nogc;
|
||||
@disable this();
|
||||
|
||||
ref Instruction i(XRegister rd, Funct3 funct3, XRegister rs1, uint immediate)
|
||||
return scope @nogc;
|
||||
|
||||
ref Instruction s(uint imm1, Funct3 funct3, XRegister rs1, XRegister rs2)
|
||||
return scope @nogc;
|
||||
|
||||
ref Instruction r(XRegister rd, Funct3 funct3, XRegister rs1, XRegister rs2, Funct7 funct7 = Funct7.none)
|
||||
return scope @nogc;
|
||||
|
||||
ref Instruction u(XRegister rd, uint imm)
|
||||
return scope @nogc;
|
||||
|
||||
ubyte* encode() return scope @nogc;
|
||||
}
|
||||
|
||||
extern(C++, "elna")
|
||||
class RiscVVisitor : IRVisitor
|
||||
{
|
||||
Instruction *instructions;
|
||||
size_t instructionsLength;
|
||||
bool registerInUse;
|
||||
uint variableCounter = 1;
|
||||
Reference[3] references;
|
||||
|
||||
override void visit(Node) @nogc;
|
||||
override void visit(Definition definition) @nogc;
|
||||
override void visit(Operand operand) @nogc;
|
||||
override void visit(Variable variable) @nogc;
|
||||
override void visit(Number number) @nogc;
|
||||
override void visit(BinaryExpression expression) @nogc;
|
||||
}
|
||||
|
||||
Symbol writeNext(Definition ast) @nogc
|
||||
{
|
||||
Array!Instruction instructions;
|
||||
auto visitor = cast(RiscVVisitor) malloc(__traits(classInstanceSize, RiscVVisitor));
|
||||
(cast(void*) visitor)[0 .. __traits(classInstanceSize, RiscVVisitor)] = __traits(initSymbol, RiscVVisitor)[];
|
||||
scope (exit)
|
||||
{
|
||||
free(cast(void*) visitor);
|
||||
}
|
||||
visitor.visit(ast);
|
||||
|
||||
auto program = Symbol(String("main"));
|
||||
|
||||
program.symbols = Array!Reference(visitor.references[]);
|
||||
foreach (ref instruction; visitor.instructions[0 .. visitor.instructionsLength])
|
||||
{
|
||||
program.text.insertBack(instruction.encode[0 .. uint.sizeof]);
|
||||
}
|
||||
return program;
|
||||
}
|
@ -1,53 +1,46 @@
|
||||
#include "elna/ir.hpp"
|
||||
|
||||
namespace elna::ir
|
||||
#include <cassert>
|
||||
|
||||
namespace elna
|
||||
{
|
||||
/**
|
||||
* AST node.
|
||||
*/
|
||||
void Node::accept(IRVisitor *)
|
||||
void TransformVisitor::visit(Node *node)
|
||||
{
|
||||
assert(false);
|
||||
}
|
||||
|
||||
void Definition::accept(IRVisitor *visitor)
|
||||
void TransformVisitor::visit(Definition *definition)
|
||||
{
|
||||
visitor->visit(this);
|
||||
assert(false);
|
||||
}
|
||||
|
||||
void Operand::accept(IRVisitor *visitor)
|
||||
void TransformVisitor::visit(BangStatement *statement)
|
||||
{
|
||||
visitor->visit(this);
|
||||
assert(false);
|
||||
}
|
||||
|
||||
void Number::accept(IRVisitor *visitor)
|
||||
void TransformVisitor::visit(Block *block)
|
||||
{
|
||||
visitor->visit(this);
|
||||
assert(false);
|
||||
}
|
||||
|
||||
void Variable::accept(IRVisitor *visitor)
|
||||
void TransformVisitor::visit(Expression *expression)
|
||||
{
|
||||
visitor->visit(this);
|
||||
assert(false);
|
||||
}
|
||||
|
||||
BinaryExpression::BinaryExpression(Operand *lhs, Operand *rhs, BinaryOperator _operator)
|
||||
void TransformVisitor::visit(Number *number)
|
||||
{
|
||||
this->lhs = lhs;
|
||||
this->rhs = rhs;
|
||||
this->_operator = _operator;
|
||||
assert(false);
|
||||
}
|
||||
|
||||
void BinaryExpression::accept(IRVisitor *visitor)
|
||||
void TransformVisitor::visit(Variable *variable)
|
||||
{
|
||||
visitor->visit(this);
|
||||
assert(false);
|
||||
}
|
||||
|
||||
BangExpression::BangExpression(Operand *operand)
|
||||
void TransformVisitor::visit(BinaryExpression *binaryExpression)
|
||||
{
|
||||
this->operand = operand;
|
||||
}
|
||||
|
||||
void BangExpression::accept(IRVisitor *visitor)
|
||||
{
|
||||
visitor->visit(this);
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
@ -1,33 +1,15 @@
|
||||
import elna.backend;
|
||||
import elna.ir;
|
||||
import elna.arguments;
|
||||
import std.path;
|
||||
import std.sumtype;
|
||||
import tanya.container.string;
|
||||
import tanya.memory.allocator;
|
||||
import tanya.memory.mmappool;
|
||||
|
||||
int main(string[] args)
|
||||
extern(C)
|
||||
int main(int argc, char** args)
|
||||
{
|
||||
defaultAllocator = MmapPool.instance;
|
||||
|
||||
return Arguments.parse(args).match!(
|
||||
(ArgumentError argumentError) => 4,
|
||||
(Arguments arguments) {
|
||||
String outputFilename;
|
||||
if (arguments.output is null)
|
||||
{
|
||||
outputFilename = arguments
|
||||
.inFile
|
||||
.baseName
|
||||
.withExtension("o");
|
||||
}
|
||||
else
|
||||
{
|
||||
outputFilename = String(arguments.output);
|
||||
}
|
||||
|
||||
return generate(arguments.inFile, outputFilename);
|
||||
}
|
||||
);
|
||||
// return generate(args[3], args[2]);
|
||||
return compile(args[3], args[2]);
|
||||
}
|
||||
|
240
source/parser.cpp
Normal file
240
source/parser.cpp
Normal file
@ -0,0 +1,240 @@
|
||||
#include "elna/parser.hpp"
|
||||
#include <stdexcept>
|
||||
|
||||
namespace elna
|
||||
{
|
||||
/**
|
||||
* AST node.
|
||||
*/
|
||||
void Node::accept(ParserVisitor *)
|
||||
{
|
||||
}
|
||||
|
||||
void Definition::accept(ParserVisitor *visitor)
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
|
||||
void Block::accept(ParserVisitor *visitor)
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
|
||||
void Expression::accept(ParserVisitor *visitor)
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
|
||||
void Number::accept(ParserVisitor *visitor)
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
|
||||
void Variable::accept(ParserVisitor *visitor)
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
|
||||
BinaryExpression::BinaryExpression(Expression *lhs, Expression *rhs, unsigned char _operator)
|
||||
{
|
||||
this->lhs = lhs;
|
||||
this->rhs = rhs;
|
||||
|
||||
if (_operator == '+')
|
||||
{
|
||||
this->_operator = BinaryOperator::sum;
|
||||
}
|
||||
else if (_operator == '-')
|
||||
{
|
||||
this->_operator = BinaryOperator::subtraction;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::logic_error("Invalid binary operator");
|
||||
}
|
||||
}
|
||||
|
||||
void BinaryExpression::accept(ParserVisitor *visitor)
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
|
||||
void BangStatement::accept(ParserVisitor *visitor)
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
|
||||
Block *parse(Token *tokenStream, std::size_t length)
|
||||
{
|
||||
return parseBlock(&tokenStream, &length);
|
||||
}
|
||||
|
||||
Expression *parseFactor(Token **tokens, size_t *length)
|
||||
{
|
||||
if ((*tokens)[0].of() == Token::TOKEN_IDENTIFIER)
|
||||
{
|
||||
auto variable = new Variable();
|
||||
variable->identifier = (*tokens)[0].identifier();
|
||||
++(*tokens);
|
||||
--(*length);
|
||||
return variable;
|
||||
}
|
||||
else if ((*tokens)[0].of() == Token::TOKEN_NUMBER)
|
||||
{
|
||||
auto number = new Number();
|
||||
number->value = (*tokens)[0].number();
|
||||
++(*tokens);
|
||||
--(*length);
|
||||
return number;
|
||||
}
|
||||
else if ((*tokens)[0].of() == Token::TOKEN_LEFT_PAREN)
|
||||
{
|
||||
++(*tokens);
|
||||
--(*length);
|
||||
|
||||
auto expression = parseExpression(tokens, length);
|
||||
|
||||
++(*tokens);
|
||||
--(*length);
|
||||
|
||||
return expression;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Expression *parseTerm(Token **tokens, size_t *length)
|
||||
{
|
||||
return parseFactor(tokens, length);
|
||||
}
|
||||
|
||||
Expression *parseExpression(Token **tokens, size_t *length)
|
||||
{
|
||||
auto term = parseTerm(tokens, length);
|
||||
if (term == nullptr || *length == 0 || (*tokens)[0].of() != Token::TOKEN_OPERATOR)
|
||||
{
|
||||
return term;
|
||||
}
|
||||
auto _operator = (*tokens)[0].identifier()[0];
|
||||
++(*tokens);
|
||||
--(*length);
|
||||
|
||||
auto expression = parseExpression(tokens, length);
|
||||
|
||||
if (expression != nullptr)
|
||||
{
|
||||
auto binaryExpression = new BinaryExpression(term, expression, _operator);
|
||||
|
||||
return binaryExpression;
|
||||
}
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Definition *parseDefinition(Token **tokens, size_t *length)
|
||||
{
|
||||
auto definition = new Definition();
|
||||
definition->identifier = (*tokens)[0].identifier(); // Copy.
|
||||
|
||||
++(*tokens);
|
||||
++(*tokens); // Skip the equals sign.
|
||||
*length -= 2;
|
||||
|
||||
if ((*tokens)[0].of() == Token::TOKEN_NUMBER)
|
||||
{
|
||||
auto number = new Number();
|
||||
number->value = (*tokens)[0].number();
|
||||
definition->number = number;
|
||||
++(*tokens);
|
||||
--(*length);
|
||||
return definition;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Statement *parseStatement(Token **tokens, std::size_t *length)
|
||||
{
|
||||
if ((*tokens)[0].of() == Token::TOKEN_BANG)
|
||||
{
|
||||
++(*tokens);
|
||||
--(*length);
|
||||
auto statement = new BangStatement();
|
||||
auto expression = parseExpression(tokens, length);
|
||||
if (expression != nullptr)
|
||||
{
|
||||
statement->expression = expression;
|
||||
}
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return statement;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Definition **parseDefinitions(Token **tokens, size_t *length, size_t *resultLength)
|
||||
{
|
||||
++(*tokens); // Skip const.
|
||||
--(*length);
|
||||
|
||||
Definition **definitions;
|
||||
*resultLength = 0;
|
||||
|
||||
while (*length != 0)
|
||||
{
|
||||
auto definition = parseDefinition(tokens, length);
|
||||
if (definition == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
definitions = reinterpret_cast<Definition **>(
|
||||
realloc(definitions, (*resultLength + 1) * sizeof(Definition*)));
|
||||
definitions[(*resultLength)++] = definition;
|
||||
|
||||
if ((*tokens)[0].of() == Token::TOKEN_SEMICOLON)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if ((*tokens)[0].of() == Token::TOKEN_COMMA)
|
||||
{
|
||||
++(*tokens);
|
||||
--(*length);
|
||||
}
|
||||
}
|
||||
|
||||
return definitions;
|
||||
}
|
||||
|
||||
Block *parseBlock(Token **tokens, std::size_t *length)
|
||||
{
|
||||
auto block = new Block();
|
||||
if ((*tokens)[0].of() == Token::TOKEN_LET)
|
||||
{
|
||||
size_t length_ = 0;
|
||||
auto constDefinitions = parseDefinitions(tokens, length, &length_);
|
||||
if (constDefinitions != nullptr)
|
||||
{
|
||||
block->definitionsLength = length_;
|
||||
block->definitions = constDefinitions;
|
||||
}
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
++(*tokens);
|
||||
--(*length);
|
||||
}
|
||||
auto statement = parseStatement(tokens, length);
|
||||
if (statement != nullptr)
|
||||
{
|
||||
block->statement = statement;
|
||||
}
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return block;
|
||||
}
|
||||
}
|
@ -22,4 +22,9 @@ namespace elna
|
||||
{
|
||||
return this->position.column;
|
||||
}
|
||||
|
||||
Symbol::Symbol(const char *name)
|
||||
{
|
||||
this->name = name;
|
||||
}
|
||||
}
|
||||
|
130
source/riscv.cpp
130
source/riscv.cpp
@ -1,5 +1,6 @@
|
||||
#include "elna/parser.hpp"
|
||||
#include "elna/riscv.hpp"
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
namespace elna
|
||||
@ -53,35 +54,43 @@ namespace elna
|
||||
return reinterpret_cast<std::uint8_t *>(&this->instruction);
|
||||
}
|
||||
|
||||
void RiscVVisitor::visit(ir::Node *)
|
||||
void RiscVVisitor::visit(Node *)
|
||||
{
|
||||
}
|
||||
|
||||
void RiscVVisitor::visit(ir::Definition *definition)
|
||||
void RiscVVisitor::visit(Definition *definition)
|
||||
{
|
||||
const uint stackSize = static_cast<std::uint32_t>(definition->statementsLength * 4 + 12);
|
||||
++constCount;
|
||||
constNames = reinterpret_cast<const char **>(realloc(constNames, sizeof(const char *) * constCount));
|
||||
constValues = reinterpret_cast<std::int32_t *>(realloc(constValues, sizeof(std::int32_t) * constCount));
|
||||
|
||||
constNames[constCount - 1] = definition->identifier;
|
||||
constValues[constCount - 1] = definition->number->value;
|
||||
}
|
||||
|
||||
void RiscVVisitor::visit(Block *block)
|
||||
{
|
||||
for (std::size_t i = 0; i < block->definitionsLength; ++i)
|
||||
{
|
||||
block->definitions[i]->accept(this);
|
||||
}
|
||||
this->instructionsLength += 4;
|
||||
this->instructions = reinterpret_cast<Instruction *>(
|
||||
realloc(this->instructions, this->instructionsLength * sizeof(Instruction)));
|
||||
|
||||
// Prologue.
|
||||
this->instructions[instructionsLength - 4] = Instruction(BaseOpcode::opImm)
|
||||
.i(XRegister::sp, Funct3::addi, XRegister::sp, -stackSize);
|
||||
this->instructions[instructionsLength - 3] = Instruction(BaseOpcode::store)
|
||||
.s(stackSize - 4, Funct3::sw, XRegister::sp, XRegister::s0);
|
||||
this->instructions[instructionsLength - 2] = Instruction(BaseOpcode::store)
|
||||
.s(stackSize - 8, Funct3::sw, XRegister::sp, XRegister::ra);
|
||||
this->instructions[instructionsLength - 1] = Instruction(BaseOpcode::opImm)
|
||||
.i(XRegister::s0, Funct3::addi, XRegister::sp, stackSize);
|
||||
block->statement->accept(this);
|
||||
|
||||
for (std::size_t i = 0; i < definition->statementsLength; ++i)
|
||||
{
|
||||
definition->statements[i]->accept(this);
|
||||
}
|
||||
this->registerInUse = true;
|
||||
definition->result->accept(this);
|
||||
this->registerInUse = false;
|
||||
// Prologue.
|
||||
const uint stackSize = static_cast<std::uint32_t>(variableCounter * 4 + 12);
|
||||
|
||||
this->instructions[0] = Instruction(BaseOpcode::opImm)
|
||||
.i(XRegister::sp, Funct3::addi, XRegister::sp, -stackSize);
|
||||
this->instructions[1] = Instruction(BaseOpcode::store)
|
||||
.s(stackSize - 4, Funct3::sw, XRegister::sp, XRegister::s0);
|
||||
this->instructions[2] = Instruction(BaseOpcode::store)
|
||||
.s(stackSize - 8, Funct3::sw, XRegister::sp, XRegister::ra);
|
||||
this->instructions[3] = Instruction(BaseOpcode::opImm)
|
||||
.i(XRegister::s0, Funct3::addi, XRegister::sp, stackSize);
|
||||
|
||||
this->instructions = reinterpret_cast<Instruction*>(
|
||||
realloc(this->instructions, (this->instructionsLength + 10) * sizeof(Instruction)));
|
||||
@ -123,32 +132,44 @@ namespace elna
|
||||
.i(XRegister::zero, Funct3::jalr, XRegister::ra, 0);
|
||||
}
|
||||
|
||||
void RiscVVisitor::visit(ir::Operand *operand)
|
||||
void RiscVVisitor::visit(BangStatement *statement)
|
||||
{
|
||||
if (dynamic_cast<ir::Variable *>(operand) != nullptr)
|
||||
statement->expression->accept(this);
|
||||
}
|
||||
|
||||
void RiscVVisitor::visit(Expression *operand)
|
||||
{
|
||||
if (dynamic_cast<Variable *>(operand) != nullptr)
|
||||
{
|
||||
return dynamic_cast<ir::Variable *>(operand)->accept(this);
|
||||
return dynamic_cast<Variable *>(operand)->accept(this);
|
||||
}
|
||||
if (dynamic_cast<ir::Number *>(operand) != nullptr)
|
||||
if (dynamic_cast<Number *>(operand) != nullptr)
|
||||
{
|
||||
return dynamic_cast<ir::Number *>(operand)->accept(this);
|
||||
return dynamic_cast<Number *>(operand)->accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
void RiscVVisitor::visit(ir::Variable *variable)
|
||||
void RiscVVisitor::visit(Variable *variable)
|
||||
{
|
||||
std::size_t i = 0;
|
||||
for (; i < constCount; ++i)
|
||||
{
|
||||
if (strcmp(variable->identifier, constNames[i]) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
const auto freeRegister = this->registerInUse ? XRegister::a0 : XRegister::t0;
|
||||
|
||||
++this->instructionsLength;
|
||||
this->instructions = reinterpret_cast<Instruction *>(
|
||||
realloc(this->instructions, this->instructionsLength * sizeof(Instruction)));
|
||||
// movl -x(%rbp), %eax; where x is a number.
|
||||
this->instructions[instructionsLength - 1] = Instruction(BaseOpcode::load)
|
||||
.i(freeRegister, Funct3::lw, XRegister::sp,
|
||||
static_cast<std::int8_t>(variable->counter * 4));
|
||||
this->instructions[this->instructionsLength - 1] =
|
||||
Instruction(BaseOpcode::opImm) // movl $x, %eax; where $x is a number.
|
||||
.i(freeRegister, Funct3::addi, XRegister::zero, constValues[i]);
|
||||
}
|
||||
|
||||
void RiscVVisitor::visit(ir::Number *number)
|
||||
void RiscVVisitor::visit(Number *number)
|
||||
{
|
||||
const auto freeRegister = this->registerInUse ? XRegister::a0 : XRegister::t0;
|
||||
|
||||
@ -160,32 +181,63 @@ namespace elna
|
||||
.i(freeRegister, Funct3::addi, XRegister::zero, number->value);
|
||||
}
|
||||
|
||||
void RiscVVisitor::visit(ir::BinaryExpression *expression)
|
||||
void RiscVVisitor::visit(BinaryExpression *expression)
|
||||
{
|
||||
const auto lhs_register = this->registerInUse ? XRegister::a0 : XRegister::t0;
|
||||
|
||||
this->registerInUse = true;
|
||||
expression->lhs->accept(this);
|
||||
|
||||
++this->instructionsLength;
|
||||
this->instructions = reinterpret_cast<Instruction *>(
|
||||
realloc(this->instructions, this->instructionsLength * sizeof(Instruction)));
|
||||
this->instructions[instructionsLength - 1] = // movl %eax, -x(%rbp); where x is a number.
|
||||
Instruction(BaseOpcode::store)
|
||||
.s(static_cast<std::uint32_t>(this->variableCounter * 4), Funct3::sw, XRegister::sp, XRegister::a0);
|
||||
auto lhs_stack_position = ++this->variableCounter;
|
||||
|
||||
this->registerInUse = false;
|
||||
expression->rhs->accept(this);
|
||||
|
||||
this->instructionsLength += 2;
|
||||
this->instructions = reinterpret_cast<Instruction *>(
|
||||
realloc(this->instructions, this->instructionsLength * sizeof(Instruction)));
|
||||
|
||||
this->instructions[instructionsLength - 2] = Instruction(BaseOpcode::load)
|
||||
.i(XRegister::a0, Funct3::lw, XRegister::sp,
|
||||
static_cast<std::int8_t>((lhs_stack_position - 1) * 4));
|
||||
|
||||
// Calculate the result and assign it to a variable on the stack.
|
||||
switch (expression->_operator)
|
||||
{
|
||||
case BinaryOperator::sum:
|
||||
this->instructions[instructionsLength - 2] = Instruction(BaseOpcode::op)
|
||||
.r(XRegister::a0, Funct3::add, XRegister::a0, XRegister::t0);
|
||||
this->instructions[instructionsLength - 1] = Instruction(BaseOpcode::op)
|
||||
.r(lhs_register, Funct3::add, XRegister::a0, XRegister::t0);
|
||||
break;
|
||||
case BinaryOperator::subtraction:
|
||||
this->instructions[instructionsLength - 2] = Instruction(BaseOpcode::op)
|
||||
.r(XRegister::a0, Funct3::sub, XRegister::a0, XRegister::t0, Funct7::sub);
|
||||
this->instructions[instructionsLength - 1] = Instruction(BaseOpcode::op)
|
||||
.r(lhs_register, Funct3::sub, XRegister::a0, XRegister::t0, Funct7::sub);
|
||||
break;
|
||||
}
|
||||
this->instructions[instructionsLength - 1] = // movl %eax, -x(%rbp); where x is a number.
|
||||
Instruction(BaseOpcode::store)
|
||||
.s(static_cast<std::uint32_t>(this->variableCounter * 4), Funct3::sw, XRegister::sp, XRegister::a0);
|
||||
}
|
||||
|
||||
++this->variableCounter;
|
||||
Symbol writeNext(Block *ast)
|
||||
{
|
||||
auto visitor = std::make_unique<RiscVVisitor>();
|
||||
visitor->visit(ast);
|
||||
|
||||
Symbol program{ "main" };
|
||||
|
||||
for (std::size_t i = 0; i < 3; ++i)
|
||||
{
|
||||
program.symbols[i] = visitor->references[i];
|
||||
}
|
||||
program.text = reinterpret_cast<unsigned char *>(malloc(sizeof(std::uint32_t) * visitor->instructionsLength));
|
||||
for (std::size_t i = 0; i < visitor->instructionsLength; ++i)
|
||||
{
|
||||
memcpy(program.text + program.length, visitor->instructions[i].encode(), sizeof(std::uint32_t));
|
||||
program.length += sizeof(std::uint32_t);
|
||||
}
|
||||
return program;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user