Remove the IR for know for simplicity

This commit is contained in:
Eugen Wissner 2024-03-01 10:13:55 +01:00
parent 4d46fc6b4d
commit 223f54d38d
Signed by: belka
GPG Key ID: A27FDC1E8EE902C0
36 changed files with 7547 additions and 1079 deletions

View File

@ -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

File diff suppressed because it is too large Load Diff

1096
include/elfio/elfio.hpp Normal file

File diff suppressed because it is too large Load Diff

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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

View 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

View 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, &section::get_size>;
using const_note_section_accessor =
note_section_accessor_template<const section, &section::get_size>;
using note_segment_accessor =
note_section_accessor_template<segment, &segment::get_file_size>;
using const_note_segment_accessor =
note_section_accessor_template<const segment, &segment::get_file_size>;
} // namespace ELFIO
#endif // ELFIO_NOTE_HPP

View File

@ -0,0 +1,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

View 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

View 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

View 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

View 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

View 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

View File

@ -0,0 +1 @@
#define ELFIO_VERSION "3.12"

View 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
View File

@ -0,0 +1,7 @@
#pragma once
namespace elna
{
char *readSource(const char *source);
int compile(const char *inFile, const char *outputFilename);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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)
{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -22,4 +22,9 @@ namespace elna
{
return this->position.column;
}
Symbol::Symbol(const char *name)
{
this->name = name;
}
}

View File

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