From 8e0b5754e41bd295b17aea9f993d1a13e3fa2503 Mon Sep 17 00:00:00 2001 From: Serge Lamikhov-Center Date: Tue, 18 Aug 2020 12:57:45 -0700 Subject: [PATCH] arrange_local_symbols() added ELF standard requires that all STB_LOCAL symbols will go prior others and sh_info entry will contain the number of the local symbols --- .gitignore | 1 + .vscode/launch.json | 9 +- .vscode/tasks.json | 9 +- elfio/elfio_symbols.hpp | 73 +++- tests/ELFIOTest1.cpp | 871 ++++++++++++++++++++++------------------ 5 files changed, 570 insertions(+), 393 deletions(-) diff --git a/.gitignore b/.gitignore index 6e2e3f6..f2522ff 100644 --- a/.gitignore +++ b/.gitignore @@ -44,6 +44,7 @@ tests/elf_examples/write_exe_i386_32_section_added tests/elf_examples/ppc-32bit-testcopy*.elf tests/elf_examples/null_section_inside_segment* tests/elf_examples/segment_containing_no_section* +tests/elf_examples/test_symbols_order.elf examples/writer/hello_x86_64 examples/write_obj/hello diff --git a/.vscode/launch.json b/.vscode/launch.json index 89c5dc4..942fb13 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -8,10 +8,13 @@ "name": "Run ELFIO Tests", "type": "cppdbg", "request": "launch", - "program": "${workspaceFolder}/ELFIOTest/ELFIOTest", - "args": [], + "program": "${workspaceFolder}/tests/ELFIOTest", + "args": [ + "-r", + "short" + ], "stopAtEntry": false, - "cwd": "${workspaceFolder}/ELFIOTest", + "cwd": "${workspaceFolder}/tests", "environment": [], "externalConsole": false, "MIMode": "gdb", diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 5ff6952..f5bb3cc 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -9,12 +9,15 @@ "CXXFLAGS='-g -O0'" ], "options": { - "cwd": "${workspaceRoot}/ELFIOTest", + "cwd": "${workspaceRoot}/tests" }, "group": { "kind": "build", "isDefault": true - } + }, + "problemMatcher": [ + "$gcc" + ] }, { "type": "shell", @@ -25,7 +28,7 @@ "CXXFLAGS='-g -O0'" ], "options": { - "cwd": "${workspaceRoot}", + "cwd": "${workspaceRoot}" }, "group": { "kind": "build", diff --git a/elfio/elfio_symbols.hpp b/elfio/elfio_symbols.hpp index da61f55..3f79e55 100644 --- a/elfio/elfio_symbols.hpp +++ b/elfio/elfio_symbols.hpp @@ -215,7 +215,23 @@ class symbol_section_accessor_template } //------------------------------------------------------------------------------ - private: + Elf_Xword + arrange_local_symbols() + { + int nRet = 0; + + if (elf_file.get_class() == ELFCLASS32) { + nRet = generic_arrange_local_symbols(); + } + else { + nRet = generic_arrange_local_symbols(); + } + + return nRet; + } + +//------------------------------------------------------------------------------ + private : //------------------------------------------------------------------------------ void find_hash_section() @@ -345,6 +361,61 @@ class symbol_section_accessor_template return nRet; } + //------------------------------------------------------------------------------ + template + Elf_Xword + generic_arrange_local_symbols() + { + const endianess_convertor &convertor = elf_file.get_convertor(); + const Elf_Xword size = symbol_section->get_entry_size(); + + Elf_Xword first_not_local = 1; // Skip the first entry + 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(generic_get_symbol_ptr(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(generic_get_symbol_ptr(current)); + if (ELF_ST_BIND(convertor(p2->st_info)) == STB_LOCAL) + break; + ++current; + } + + if (first_not_local < count && current < count) + { + // Swap the symbols + T tmp; + memcpy(&tmp, p1, size); + memcpy(p1, p2, size); + memcpy(p2, &tmp, size); + } + else + { + // Update 'info' field of the section + symbol_section->set_info(first_not_local); + break; + } + } + + // Elf_Word nRet = symbol_section->get_size() / sizeof(entry) - 1; + + return first_not_local; + } + //------------------------------------------------------------------------------ private: const elfio& elf_file; diff --git a/tests/ELFIOTest1.cpp b/tests/ELFIOTest1.cpp index 16d2972..f81673d 100644 --- a/tests/ELFIOTest1.cpp +++ b/tests/ELFIOTest1.cpp @@ -11,79 +11,84 @@ using boost::test_tools::output_test_stream; using namespace ELFIO; +enum Tests +{ + SEG_ALIGN = 1 +}; -bool write_obj_i386( bool is64bit ) +//////////////////////////////////////////////////////////////////////////////// +bool write_obj_i386(bool is64bit) { elfio writer; - writer.create( is64bit ? ELFCLASS64 : ELFCLASS32, ELFDATA2LSB ); - writer.set_type( ET_REL ); - writer.set_os_abi( ELFOSABI_LINUX ); - writer.set_machine( is64bit ? EM_X86_64 : EM_386 ); + writer.create(is64bit ? ELFCLASS64 : ELFCLASS32, ELFDATA2LSB); + writer.set_type(ET_REL); + writer.set_os_abi(ELFOSABI_LINUX); + writer.set_machine(is64bit ? EM_X86_64 : EM_386); // Create code section* - section* text_sec = writer.sections.add( ".text" ); - text_sec->set_type( SHT_PROGBITS ); - text_sec->set_flags( SHF_ALLOC | SHF_EXECINSTR ); - text_sec->set_addr_align( 0x10 ); + section *text_sec = writer.sections.add(".text"); + text_sec->set_type(SHT_PROGBITS); + text_sec->set_flags(SHF_ALLOC | SHF_EXECINSTR); + text_sec->set_addr_align(0x10); // Add data into it - char text[] = { '\xB8', '\x04', '\x00', '\x00', '\x00', // mov eax, 4 - '\xBB', '\x01', '\x00', '\x00', '\x00', // mov ebx, 1 - '\xB9', '\x00', '\x00', '\x00', '\x00', // mov ecx, msg - '\xBA', '\x0E', '\x00', '\x00', '\x00', // mov edx, 14 - '\xCD', '\x80', // int 0x80 - '\xB8', '\x01', '\x00', '\x00', '\x00', // mov eax, 1 - '\xCD', '\x80' // int 0x80 - }; - text_sec->set_data( text, sizeof( text ) ); + char text[] = { + '\xB8', '\x04', '\x00', '\x00', '\x00', // mov eax, 4 + '\xBB', '\x01', '\x00', '\x00', '\x00', // mov ebx, 1 + '\xB9', '\x00', '\x00', '\x00', '\x00', // mov ecx, msg + '\xBA', '\x0E', '\x00', '\x00', '\x00', // mov edx, 14 + '\xCD', '\x80', // int 0x80 + '\xB8', '\x01', '\x00', '\x00', '\x00', // mov eax, 1 + '\xCD', '\x80' // int 0x80 + }; + text_sec->set_data(text, sizeof(text)); // Create data section* - section* data_sec = writer.sections.add( ".data" ); - data_sec->set_type( SHT_PROGBITS ); - data_sec->set_flags( SHF_ALLOC | SHF_WRITE ); - data_sec->set_addr_align( 4 ); + section *data_sec = writer.sections.add(".data"); + data_sec->set_type(SHT_PROGBITS); + data_sec->set_flags(SHF_ALLOC | SHF_WRITE); + data_sec->set_addr_align(4); - char data[] = { '\x48', '\x65', '\x6C', '\x6C', '\x6F', // msg: db 'Hello, World!', 10 - '\x2C', '\x20', '\x57', '\x6F', '\x72', - '\x6C', '\x64', '\x21', '\x0A' - }; - data_sec->set_data( data, sizeof( data ) ); + char data[] = {'\x48', '\x65', '\x6C', '\x6C', '\x6F', // msg: db 'Hello, World!', 10 + '\x2C', '\x20', '\x57', '\x6F', '\x72', + '\x6C', '\x64', '\x21', '\x0A'}; + data_sec->set_data(data, sizeof(data)); - section* str_sec = writer.sections.add( ".strtab" ); - str_sec->set_type( SHT_STRTAB ); - str_sec->set_addr_align( 0x1 ); + section *str_sec = writer.sections.add(".strtab"); + str_sec->set_type(SHT_STRTAB); + str_sec->set_addr_align(0x1); - string_section_accessor str_writer( str_sec ); - Elf_Word nStrIndex = str_writer.add_string( "msg" ); + string_section_accessor str_writer(str_sec); + Elf_Word nStrIndex = str_writer.add_string("msg"); - section* sym_sec = writer.sections.add( ".symtab" ); - sym_sec->set_type( SHT_SYMTAB ); - sym_sec->set_info( 2 ); - sym_sec->set_link( str_sec->get_index() ); - sym_sec->set_addr_align( 4 ); - sym_sec->set_entry_size( writer.get_default_entry_size( SHT_SYMTAB ) ); + section *sym_sec = writer.sections.add(".symtab"); + sym_sec->set_type(SHT_SYMTAB); + sym_sec->set_info(2); + sym_sec->set_link(str_sec->get_index()); + sym_sec->set_addr_align(4); + sym_sec->set_entry_size(writer.get_default_entry_size(SHT_SYMTAB)); - symbol_section_accessor symbol_writer( writer, sym_sec ); - Elf_Word nSymIndex = symbol_writer.add_symbol( nStrIndex, 0, 0, + symbol_section_accessor symbol_writer(writer, sym_sec); + Elf_Word nSymIndex = symbol_writer.add_symbol(nStrIndex, 0, 0, STB_LOCAL, STT_NOTYPE, 0, - data_sec->get_index() ); + data_sec->get_index()); // Another way to add symbol - symbol_writer.add_symbol( str_writer, "_start", 0x00000000, 0, + symbol_writer.add_symbol(str_writer, "_start", 0x00000000, 0, STB_WEAK, STT_FUNC, 0, - text_sec->get_index() ); + text_sec->get_index()); // Create relocation table section* - section* rel_sec = writer.sections.add( ".rel.text" ); - rel_sec->set_type( SHT_REL ); - rel_sec->set_info( text_sec->get_index() ); - rel_sec->set_link( sym_sec->get_index() ); - rel_sec->set_addr_align( 4 ); - rel_sec->set_entry_size( writer.get_default_entry_size( SHT_REL ) ); + section *rel_sec = writer.sections.add(".rel.text"); + rel_sec->set_type(SHT_REL); + rel_sec->set_info(text_sec->get_index()); + rel_sec->set_link(sym_sec->get_index()); + rel_sec->set_addr_align(4); + rel_sec->set_entry_size(writer.get_default_entry_size(SHT_REL)); - relocation_section_accessor rel_writer( writer, rel_sec ); - rel_writer.add_entry( 11, nSymIndex, (unsigned char)R_386_RELATIVE ); + relocation_section_accessor rel_writer(writer, rel_sec); + rel_writer.add_entry(11, nSymIndex, (unsigned char)R_386_RELATIVE); // Another method to add the same relocation entry // pRelWriter->AddEntry( pStrWriter, "msg", @@ -93,399 +98,394 @@ bool write_obj_i386( bool is64bit ) // 0, (unsigned char)R_386_RELATIVE ); // Create note section* - section* note_sec = writer.sections.add( ".note" ); - note_sec->set_type( SHT_NOTE ); - note_sec->set_addr_align( 1 ); + section *note_sec = writer.sections.add(".note"); + note_sec->set_type(SHT_NOTE); + note_sec->set_addr_align(1); // Create notes writer - note_section_accessor note_writer( writer, note_sec ); - note_writer.add_note( 0x77, "Created by ELFIO", 0, 0 ); + note_section_accessor note_writer(writer, note_sec); + note_writer.add_note(0x77, "Created by ELFIO", 0, 0); // Create ELF file writer.save( - is64bit ? - "elf_examples/write_obj_i386_64.o" : - "elf_examples/write_obj_i386_32.o" - ); + is64bit ? "elf_examples/write_obj_i386_64.o" : "elf_examples/write_obj_i386_32.o"); return true; } - //////////////////////////////////////////////////////////////////////////////// -BOOST_AUTO_TEST_CASE( write_obj_i386_32 ) -{ - BOOST_CHECK_EQUAL( true, write_obj_i386( false ) ); - output_test_stream output( "elf_examples/write_obj_i386_32_match.o", true, false ); - std::ifstream input( "elf_examples/write_obj_i386_32.o", std::ios::binary ); - output << input.rdbuf(); - BOOST_CHECK( output.match_pattern() ); -} - - -//////////////////////////////////////////////////////////////////////////////// -BOOST_AUTO_TEST_CASE( write_obj_i386_64 ) -{ - BOOST_CHECK_EQUAL( true, write_obj_i386( true ) ); - output_test_stream output( "elf_examples/write_obj_i386_64_match.o", true, false ); - std::ifstream input( "elf_examples/write_obj_i386_64.o", std::ios::binary ); - output << input.rdbuf(); - BOOST_CHECK( output.match_pattern() ); -} - -bool write_exe_i386( const std::string& filename, bool is64bit, bool set_addr = false, Elf64_Addr addr = 0 ) +bool write_exe_i386(const std::string &filename, bool is64bit, bool set_addr = false, Elf64_Addr addr = 0) { elfio writer; - writer.create( is64bit ? ELFCLASS64 : ELFCLASS32, ELFDATA2LSB ); - writer.set_os_abi( ELFOSABI_LINUX ); - writer.set_type( ET_EXEC ); - writer.set_machine( is64bit ? EM_X86_64 : EM_386 ); + writer.create(is64bit ? ELFCLASS64 : ELFCLASS32, ELFDATA2LSB); + writer.set_os_abi(ELFOSABI_LINUX); + writer.set_type(ET_EXEC); + writer.set_machine(is64bit ? EM_X86_64 : EM_386); // Create code section* - section* text_sec = writer.sections.add( ".text" ); - text_sec->set_type( SHT_PROGBITS ); - text_sec->set_flags( SHF_ALLOC | SHF_EXECINSTR ); - text_sec->set_addr_align( 0x10 ); - if ( set_addr ) { - text_sec->set_address( addr ); + section *text_sec = writer.sections.add(".text"); + text_sec->set_type(SHT_PROGBITS); + text_sec->set_flags(SHF_ALLOC | SHF_EXECINSTR); + text_sec->set_addr_align(0x10); + if (set_addr) + { + text_sec->set_address(addr); } // Add data into it - char text[] = { '\xB8', '\x04', '\x00', '\x00', '\x00', // mov eax, 4 - '\xBB', '\x01', '\x00', '\x00', '\x00', // mov ebx, 1 - '\xB9', '\x20', '\x80', '\x04', '\x08', // mov ecx, msg - '\xBA', '\x0E', '\x00', '\x00', '\x00', // mov edx, 14 - '\xCD', '\x80', // int 0x80 - '\xB8', '\x01', '\x00', '\x00', '\x00', // mov eax, 1 - '\xCD', '\x80' // int 0x80 - }; - text_sec->set_data( text, sizeof( text ) ); + char text[] = { + '\xB8', '\x04', '\x00', '\x00', '\x00', // mov eax, 4 + '\xBB', '\x01', '\x00', '\x00', '\x00', // mov ebx, 1 + '\xB9', '\x20', '\x80', '\x04', '\x08', // mov ecx, msg + '\xBA', '\x0E', '\x00', '\x00', '\x00', // mov edx, 14 + '\xCD', '\x80', // int 0x80 + '\xB8', '\x01', '\x00', '\x00', '\x00', // mov eax, 1 + '\xCD', '\x80' // int 0x80 + }; + text_sec->set_data(text, sizeof(text)); - segment* text_seg = writer.segments.add(); - text_seg->set_type( PT_LOAD ); - text_seg->set_virtual_address( 0x08048000 ); - text_seg->set_physical_address( 0x08048000 ); - text_seg->set_flags( PF_X | PF_R ); - text_seg->set_align( 0x1000 ); - text_seg->add_section_index( text_sec->get_index(), text_sec->get_addr_align() ); + segment *text_seg = writer.segments.add(); + text_seg->set_type(PT_LOAD); + text_seg->set_virtual_address(0x08048000); + text_seg->set_physical_address(0x08048000); + text_seg->set_flags(PF_X | PF_R); + text_seg->set_align(0x1000); + text_seg->add_section_index(text_sec->get_index(), text_sec->get_addr_align()); // Create data section* - section* data_sec = writer.sections.add( ".data" ); - data_sec->set_type( SHT_PROGBITS ); - data_sec->set_flags( SHF_ALLOC | SHF_WRITE ); - data_sec->set_addr_align( 0x4 ); + section *data_sec = writer.sections.add(".data"); + data_sec->set_type(SHT_PROGBITS); + data_sec->set_flags(SHF_ALLOC | SHF_WRITE); + data_sec->set_addr_align(0x4); - char data[] = { '\x48', '\x65', '\x6C', '\x6C', '\x6F', // msg: db 'Hello, World!', 10 - '\x2C', '\x20', '\x57', '\x6F', '\x72', - '\x6C', '\x64', '\x21', '\x0A' - }; - data_sec->set_data( data, sizeof( data ) ); + char data[] = {'\x48', '\x65', '\x6C', '\x6C', '\x6F', // msg: db 'Hello, World!', 10 + '\x2C', '\x20', '\x57', '\x6F', '\x72', + '\x6C', '\x64', '\x21', '\x0A'}; + data_sec->set_data(data, sizeof(data)); - segment* data_seg = writer.segments.add(); - data_seg->set_type( PT_LOAD ); - data_seg->set_virtual_address( 0x08048020 ); - data_seg->set_physical_address( 0x08048020 ); - data_seg->set_flags( PF_W | PF_R ); - data_seg->set_align( 0x10 ); - data_seg->add_section_index( data_sec->get_index(), data_sec->get_addr_align() ); + segment *data_seg = writer.segments.add(); + data_seg->set_type(PT_LOAD); + data_seg->set_virtual_address(0x08048020); + data_seg->set_physical_address(0x08048020); + data_seg->set_flags(PF_W | PF_R); + data_seg->set_align(0x10); + data_seg->add_section_index(data_sec->get_index(), data_sec->get_addr_align()); - section* note_sec = writer.sections.add( ".note" ); - note_sec->set_type( SHT_NOTE ); - note_sec->set_addr_align( 1 ); - note_section_accessor note_writer( writer, note_sec ); - note_writer.add_note( 0x01, "Created by ELFIO", 0, 0 ); + section *note_sec = writer.sections.add(".note"); + note_sec->set_type(SHT_NOTE); + note_sec->set_addr_align(1); + note_section_accessor note_writer(writer, note_sec); + note_writer.add_note(0x01, "Created by ELFIO", 0, 0); char descr[6] = {0x31, 0x32, 0x33, 0x34, 0x35, 0x36}; - note_writer.add_note( 0x01, "Never easier!", descr, sizeof( descr ) ); + note_writer.add_note(0x01, "Never easier!", descr, sizeof(descr)); // Create ELF file - writer.set_entry( 0x08048000 ); + writer.set_entry(0x08048000); - writer.save( filename ); + writer.save(filename); return true; } - //////////////////////////////////////////////////////////////////////////////// -BOOST_AUTO_TEST_CASE( write_exe_i386_32 ) -{ - const std::string generated_file ( "elf_examples/write_exe_i386_32" ); - const std::string reference_file ( "elf_examples/write_exe_i386_32_match" ); - BOOST_CHECK_EQUAL( true, write_exe_i386( generated_file, false ) ); - output_test_stream output( reference_file, true, false ); - std::ifstream input( generated_file, std::ios::binary ); - output << input.rdbuf(); - BOOST_CHECK_MESSAGE( output.match_pattern(), "Comparing " + generated_file + " and " + reference_file ); -} - -enum Tests { SEG_ALIGN = 1 }; - -void checkObjestsAreEqual( std::string file_name1, std::string file_name2 ) +void checkObjestsAreEqual(std::string file_name1, std::string file_name2) { elfio file1; elfio file2; - BOOST_REQUIRE_EQUAL( file1.load( file_name1 ), true ); - BOOST_CHECK_EQUAL( file1.save( file_name2 ), true ); - BOOST_REQUIRE_EQUAL( file1.load( file_name1 ), true ); - BOOST_REQUIRE_EQUAL( file2.load( file_name2 ), true ); + BOOST_REQUIRE_EQUAL(file1.load(file_name1), true); + BOOST_CHECK_EQUAL(file1.save(file_name2), true); + BOOST_REQUIRE_EQUAL(file1.load(file_name1), true); + BOOST_REQUIRE_EQUAL(file2.load(file_name2), true); - for (int i = 0; i < file1.sections.size(); ++i ) { - BOOST_CHECK_EQUAL( file1.sections[i]->get_address(), - file2.sections[i]->get_address() ); - BOOST_CHECK_EQUAL( file1.sections[i]->get_addr_align(), - file2.sections[i]->get_addr_align() ); - BOOST_CHECK_EQUAL( file1.sections[i]->get_entry_size(), - file2.sections[i]->get_entry_size() ); - BOOST_CHECK_EQUAL( file1.sections[i]->get_flags(), - file2.sections[i]->get_flags() ); - BOOST_CHECK_EQUAL( file1.sections[i]->get_index(), - file2.sections[i]->get_index() ); - BOOST_CHECK_EQUAL( file1.sections[i]->get_info(), - file2.sections[i]->get_info() ); - BOOST_CHECK_EQUAL( file1.sections[i]->get_link(), - file2.sections[i]->get_link() ); - BOOST_CHECK_EQUAL( file1.sections[i]->get_name(), - file2.sections[i]->get_name() ); - BOOST_CHECK_EQUAL( file1.sections[i]->get_name_string_offset(), - file2.sections[i]->get_name_string_offset() ); - BOOST_CHECK_EQUAL( file1.sections[i]->get_size(), - file2.sections[i]->get_size() ); - BOOST_CHECK_EQUAL( file1.sections[i]->get_type(), - file2.sections[i]->get_type() ); + for (int i = 0; i < file1.sections.size(); ++i) + { + BOOST_CHECK_EQUAL(file1.sections[i]->get_address(), + file2.sections[i]->get_address()); + BOOST_CHECK_EQUAL(file1.sections[i]->get_addr_align(), + file2.sections[i]->get_addr_align()); + BOOST_CHECK_EQUAL(file1.sections[i]->get_entry_size(), + file2.sections[i]->get_entry_size()); + BOOST_CHECK_EQUAL(file1.sections[i]->get_flags(), + file2.sections[i]->get_flags()); + BOOST_CHECK_EQUAL(file1.sections[i]->get_index(), + file2.sections[i]->get_index()); + BOOST_CHECK_EQUAL(file1.sections[i]->get_info(), + file2.sections[i]->get_info()); + BOOST_CHECK_EQUAL(file1.sections[i]->get_link(), + file2.sections[i]->get_link()); + BOOST_CHECK_EQUAL(file1.sections[i]->get_name(), + file2.sections[i]->get_name()); + BOOST_CHECK_EQUAL(file1.sections[i]->get_name_string_offset(), + file2.sections[i]->get_name_string_offset()); + BOOST_CHECK_EQUAL(file1.sections[i]->get_size(), + file2.sections[i]->get_size()); + BOOST_CHECK_EQUAL(file1.sections[i]->get_type(), + file2.sections[i]->get_type()); - - if ( file1.sections[i]->get_type() == SHT_NULL || - file1.sections[i]->get_type() == SHT_NOBITS ) { + if (file1.sections[i]->get_type() == SHT_NULL || + file1.sections[i]->get_type() == SHT_NOBITS) + { continue; } - BOOST_REQUIRE_NE( file1.sections[i]->get_data(), (const char*)0 ); - BOOST_REQUIRE_NE( file2.sections[i]->get_data(), (const char*)0 ); - std::string pdata1( file1.sections[i]->get_data(), - file1.sections[i]->get_data() + - file1.sections[i]->get_size() ); - std::string pdata2( file2.sections[i]->get_data(), - file2.sections[i]->get_data() + - file2.sections[i]->get_size() ); + BOOST_REQUIRE_NE(file1.sections[i]->get_data(), (const char *)0); + BOOST_REQUIRE_NE(file2.sections[i]->get_data(), (const char *)0); + std::string pdata1(file1.sections[i]->get_data(), + file1.sections[i]->get_data() + + file1.sections[i]->get_size()); + std::string pdata2(file2.sections[i]->get_data(), + file2.sections[i]->get_data() + + file2.sections[i]->get_size()); - BOOST_CHECK_EQUAL( file1.sections[i]->get_size(), - file2.sections[i]->get_size() ); - if ( ( file2.sections[i]->get_type() != SHT_NULL ) && - ( file2.sections[i]->get_type() != SHT_NOBITS ) ) { - BOOST_CHECK_EQUAL_COLLECTIONS( pdata1.begin(), pdata1.end(), - pdata2.begin(), pdata2.end() ); + BOOST_CHECK_EQUAL(file1.sections[i]->get_size(), + file2.sections[i]->get_size()); + if ((file2.sections[i]->get_type() != SHT_NULL) && + (file2.sections[i]->get_type() != SHT_NOBITS)) + { + BOOST_CHECK_EQUAL_COLLECTIONS(pdata1.begin(), pdata1.end(), + pdata2.begin(), pdata2.end()); } } } - -void checkExeAreEqual( std::string file_name1, std::string file_name2, int skipTests = 0 ) +//////////////////////////////////////////////////////////////////////////////// +void checkExeAreEqual(std::string file_name1, std::string file_name2, int skipTests = 0) { - checkObjestsAreEqual( file_name1, file_name2 ); + checkObjestsAreEqual(file_name1, file_name2); elfio file1; elfio file2; - BOOST_REQUIRE_EQUAL( file1.load( file_name1 ), true ); - BOOST_REQUIRE_EQUAL( file2.load( file_name2 ), true ); + BOOST_REQUIRE_EQUAL(file1.load(file_name1), true); + BOOST_REQUIRE_EQUAL(file2.load(file_name2), true); - for (int i = 0; i < file1.segments.size(); ++i ) { - if ( !(skipTests & SEG_ALIGN) ) - BOOST_CHECK_EQUAL( file1.segments[i]->get_align(), - file2.segments[i]->get_align() ); - BOOST_CHECK_EQUAL( file1.segments[i]->get_file_size(), - file2.segments[i]->get_file_size() ); - BOOST_CHECK_EQUAL( file1.segments[i]->get_memory_size(), - file2.segments[i]->get_memory_size() ); - BOOST_CHECK_EQUAL( file1.segments[i]->get_type(), - file2.segments[i]->get_type() ); + for (int i = 0; i < file1.segments.size(); ++i) + { + if (!(skipTests & SEG_ALIGN)) + BOOST_CHECK_EQUAL(file1.segments[i]->get_align(), + file2.segments[i]->get_align()); + BOOST_CHECK_EQUAL(file1.segments[i]->get_file_size(), + file2.segments[i]->get_file_size()); + BOOST_CHECK_EQUAL(file1.segments[i]->get_memory_size(), + file2.segments[i]->get_memory_size()); + BOOST_CHECK_EQUAL(file1.segments[i]->get_type(), + file2.segments[i]->get_type()); // skip data comparisons of the program header and of empty segments - if( file1.segments[i]->get_type() == PT_PHDR || !file1.segments[i]->get_file_size() ) + if (file1.segments[i]->get_type() == PT_PHDR || !file1.segments[i]->get_file_size()) continue; - BOOST_REQUIRE_NE( file1.segments[i]->get_data(), (const char*)0 ); - BOOST_REQUIRE_NE( file2.segments[i]->get_data(), (const char*)0 ); + BOOST_REQUIRE_NE(file1.segments[i]->get_data(), (const char *)0); + BOOST_REQUIRE_NE(file2.segments[i]->get_data(), (const char *)0); - std::string pdata1( file1.segments[i]->get_data(), - file1.segments[i]->get_data() + - file1.segments[i]->get_file_size() ); - std::string pdata2( file2.segments[i]->get_data(), - file2.segments[i]->get_data() + - file2.segments[i]->get_file_size() ); + std::string pdata1(file1.segments[i]->get_data(), + file1.segments[i]->get_data() + + file1.segments[i]->get_file_size()); + std::string pdata2(file2.segments[i]->get_data(), + file2.segments[i]->get_data() + + file2.segments[i]->get_file_size()); // truncate the data if the header and the segment table is // part of the segment Elf64_Off afterPHDR = file1.get_segments_offset() + - file1.get_segment_entry_size() * (Elf64_Off)file1.segments.size(); - if( file1.segments[i]->get_offset() < afterPHDR ) { - pdata1 = pdata1.substr( (unsigned int)afterPHDR ); - pdata2 = pdata2.substr( (unsigned int)afterPHDR ); + file1.get_segment_entry_size() * (Elf64_Off)file1.segments.size(); + if (file1.segments[i]->get_offset() < afterPHDR) + { + pdata1 = pdata1.substr((unsigned int)afterPHDR); + pdata2 = pdata2.substr((unsigned int)afterPHDR); } - BOOST_CHECK_EQUAL_COLLECTIONS( pdata1.begin(), pdata1.end(), - pdata2.begin(), pdata2.end() ); + BOOST_CHECK_EQUAL_COLLECTIONS(pdata1.begin(), pdata1.end(), + pdata2.begin(), pdata2.end()); } } - //////////////////////////////////////////////////////////////////////////////// -BOOST_AUTO_TEST_CASE( elf_object_copy_32 ) +BOOST_AUTO_TEST_CASE(write_obj_i386_32) { - checkObjestsAreEqual( "elf_examples/hello_32.o", - "elf_examples/hello_32_copy.o" ); - checkObjestsAreEqual( "elf_examples/hello_64.o", - "elf_examples/hello_64_copy.o" ); - checkObjestsAreEqual( "elf_examples/test_ppc.o", - "elf_examples/test_ppc_copy.o" ); - checkObjestsAreEqual( "elf_examples/write_obj_i386_32.o", - "elf_examples/write_obj_i386_32_copy.o" ); - checkObjestsAreEqual( "elf_examples/write_obj_i386_64.o", - "elf_examples/write_obj_i386_64_copy.o" ); + BOOST_CHECK_EQUAL(true, write_obj_i386(false)); + output_test_stream output("elf_examples/write_obj_i386_32_match.o", true, false); + std::ifstream input("elf_examples/write_obj_i386_32.o", std::ios::binary); + output << input.rdbuf(); + BOOST_CHECK(output.match_pattern()); } +//////////////////////////////////////////////////////////////////////////////// +BOOST_AUTO_TEST_CASE(write_obj_i386_64) +{ + BOOST_CHECK_EQUAL(true, write_obj_i386(true)); + output_test_stream output("elf_examples/write_obj_i386_64_match.o", true, false); + std::ifstream input("elf_examples/write_obj_i386_64.o", std::ios::binary); + output << input.rdbuf(); + BOOST_CHECK(output.match_pattern()); +} //////////////////////////////////////////////////////////////////////////////// -BOOST_AUTO_TEST_CASE( section_header_address_update ) +BOOST_AUTO_TEST_CASE(write_exe_i386_32) +{ + const std::string generated_file("elf_examples/write_exe_i386_32"); + const std::string reference_file("elf_examples/write_exe_i386_32_match"); + BOOST_CHECK_EQUAL(true, write_exe_i386(generated_file, false)); + output_test_stream output(reference_file, true, false); + std::ifstream input(generated_file, std::ios::binary); + output << input.rdbuf(); + BOOST_CHECK_MESSAGE(output.match_pattern(), "Comparing " + generated_file + " and " + reference_file); +} + +//////////////////////////////////////////////////////////////////////////////// +BOOST_AUTO_TEST_CASE(elf_object_copy_32) +{ + checkObjestsAreEqual("elf_examples/hello_32.o", + "elf_examples/hello_32_copy.o"); + checkObjestsAreEqual("elf_examples/hello_64.o", + "elf_examples/hello_64_copy.o"); + checkObjestsAreEqual("elf_examples/test_ppc.o", + "elf_examples/test_ppc_copy.o"); + checkObjestsAreEqual("elf_examples/write_obj_i386_32.o", + "elf_examples/write_obj_i386_32_copy.o"); + checkObjestsAreEqual("elf_examples/write_obj_i386_64.o", + "elf_examples/write_obj_i386_64_copy.o"); +} + +//////////////////////////////////////////////////////////////////////////////// +BOOST_AUTO_TEST_CASE(section_header_address_update) { elfio reader; - const std::string file_w_addr ( "elf_examples/write_exe_i386_32_w_addr" ); - write_exe_i386( file_w_addr, false, true, 0x08048100 ); - reader.load( file_w_addr ); - section* sec = reader.sections[".text"]; - BOOST_REQUIRE_NE( sec, (section*)0 ); - BOOST_CHECK_EQUAL( sec->get_address(), 0x08048100 ); + const std::string file_w_addr("elf_examples/write_exe_i386_32_w_addr"); + write_exe_i386(file_w_addr, false, true, 0x08048100); + reader.load(file_w_addr); + section *sec = reader.sections[".text"]; + BOOST_REQUIRE_NE(sec, (section *)0); + BOOST_CHECK_EQUAL(sec->get_address(), 0x08048100); - - const std::string file_wo_addr ( "elf_examples/write_exe_i386_32_wo_addr" ); - write_exe_i386( file_wo_addr, false, false, 0 ); - reader.load( file_wo_addr ); + const std::string file_wo_addr("elf_examples/write_exe_i386_32_wo_addr"); + write_exe_i386(file_wo_addr, false, false, 0); + reader.load(file_wo_addr); sec = reader.sections[".text"]; - BOOST_REQUIRE_NE( sec, (section*)0 ); - BOOST_CHECK_EQUAL( sec->get_address(), 0x08048000 ); + BOOST_REQUIRE_NE(sec, (section *)0); + BOOST_CHECK_EQUAL(sec->get_address(), 0x08048000); } - //////////////////////////////////////////////////////////////////////////////// -BOOST_AUTO_TEST_CASE( elfio_copy ) +BOOST_AUTO_TEST_CASE(elfio_copy) { elfio e; - const std::string filename ( "elf_examples/write_exe_i386_32_section_added" ); - write_exe_i386( filename, false, true, 0x08048100 ); + const std::string filename("elf_examples/write_exe_i386_32_section_added"); + write_exe_i386(filename, false, true, 0x08048100); - e.load( filename ); - Elf_Half num = e.sections.size(); + e.load(filename); + Elf_Half num = e.sections.size(); //section* new_sec = - e.sections.add( "new" ); - e.save( filename ); - BOOST_CHECK_EQUAL( num + 1, e.sections.size() ); + e.sections.add("new"); + e.save(filename); + BOOST_CHECK_EQUAL(num + 1, e.sections.size()); } //////////////////////////////////////////////////////////////////////////////// -BOOST_AUTO_TEST_CASE( elf_exe_copy_64 ) +BOOST_AUTO_TEST_CASE(elf_exe_copy_64) { - checkExeAreEqual( "elf_examples/64bitLOAD.elf", - "elf_examples/64bitLOAD_copy.elf" ); - checkExeAreEqual( "elf_examples/asm64", - "elf_examples/asm64_copy" ); - checkExeAreEqual( "elf_examples/hello_64", - "elf_examples/hello_64_copy" ); + checkExeAreEqual("elf_examples/64bitLOAD.elf", + "elf_examples/64bitLOAD_copy.elf"); + checkExeAreEqual("elf_examples/asm64", + "elf_examples/asm64_copy"); + checkExeAreEqual("elf_examples/hello_64", + "elf_examples/hello_64_copy"); // The last segment (GNU_RELRO) is bigger than necessary. // I don't see why but it contains a few bits of the .got.plt section. // -> load, store, compare cycle fails -// checkExeAreEqual( "elf_examples/main", -// "elf_examples/main_copy" ); -// checkExeAreEqual( "elf_examples/ls", -// "elf_examples/ls_copy" ); + // checkExeAreEqual( "elf_examples/main", + // "elf_examples/main_copy" ); + // checkExeAreEqual( "elf_examples/ls", + // "elf_examples/ls_copy" ); } //////////////////////////////////////////////////////////////////////////////// -BOOST_AUTO_TEST_CASE( elf_exe_copy_32 ) +BOOST_AUTO_TEST_CASE(elf_exe_copy_32) { - checkExeAreEqual( "elf_examples/asm", - "elf_examples/asm_copy" ); - checkExeAreEqual( "elf_examples/arm_v7m_test_debug.elf", - "elf_examples/arm_v7m_test_debug_copy.elf" ); - checkExeAreEqual( "elf_examples/arm_v7m_test_release.elf", - "elf_examples/arm_v7m_test_release_copy.elf" ); - checkExeAreEqual( "elf_examples/hello_32", - "elf_examples/hello_32_copy" ); - checkExeAreEqual( "elf_examples/hello_arm", - "elf_examples/hello_arm_copy" ); - checkExeAreEqual( "elf_examples/hello_arm_stripped", - "elf_examples/hello_arm_stripped_copy" ); - checkExeAreEqual( "elf_examples/read_write_arm_elf32_input", - "elf_examples/read_write_arm_elf32_input_copy" ); - checkExeAreEqual( "elf_examples/test_ppc", - "elf_examples/test_ppc_copy" ); + checkExeAreEqual("elf_examples/asm", + "elf_examples/asm_copy"); + checkExeAreEqual("elf_examples/arm_v7m_test_debug.elf", + "elf_examples/arm_v7m_test_debug_copy.elf"); + checkExeAreEqual("elf_examples/arm_v7m_test_release.elf", + "elf_examples/arm_v7m_test_release_copy.elf"); + checkExeAreEqual("elf_examples/hello_32", + "elf_examples/hello_32_copy"); + checkExeAreEqual("elf_examples/hello_arm", + "elf_examples/hello_arm_copy"); + checkExeAreEqual("elf_examples/hello_arm_stripped", + "elf_examples/hello_arm_stripped_copy"); + checkExeAreEqual("elf_examples/read_write_arm_elf32_input", + "elf_examples/read_write_arm_elf32_input_copy"); + checkExeAreEqual("elf_examples/test_ppc", + "elf_examples/test_ppc_copy"); } //////////////////////////////////////////////////////////////////////////////// -BOOST_AUTO_TEST_CASE( elf_exe_loadsave_ppc32big3 ) +BOOST_AUTO_TEST_CASE(elf_exe_loadsave_ppc32big3) { std::string in = "elf_examples/ppc-32bit-specimen3.elf"; std::string out = "elf_examples/ppc-32bit-testcopy3.elf"; elfio elf; - BOOST_REQUIRE_EQUAL( elf.load( in ), true ); - BOOST_REQUIRE_EQUAL( elf.save( out ), true ); + BOOST_REQUIRE_EQUAL(elf.load(in), true); + BOOST_REQUIRE_EQUAL(elf.save(out), true); - checkObjestsAreEqual( in, out); - checkExeAreEqual( in, out, SEG_ALIGN ); + checkObjestsAreEqual(in, out); + checkExeAreEqual(in, out, SEG_ALIGN); } //////////////////////////////////////////////////////////////////////////////// -BOOST_AUTO_TEST_CASE( get_symbol_32 ) +BOOST_AUTO_TEST_CASE(get_symbol_32) { - elfio elf; - std::string name; + elfio elf; + std::string name; ELFIO::Elf_Xword size; - unsigned char bind; - unsigned char type; - ELFIO::Elf_Half section_index; - unsigned char other; - std::string in = "elf_examples/hello_32"; + unsigned char bind; + unsigned char type; + ELFIO::Elf_Half section_index; + unsigned char other; + std::string in = "elf_examples/hello_32"; - BOOST_REQUIRE_EQUAL( elf.load(in), true ); - section* psymsec = elf.sections[ ".symtab" ]; - const symbol_section_accessor symbols( elf, psymsec ); + BOOST_REQUIRE_EQUAL(elf.load(in), true); + section *psymsec = elf.sections[".symtab"]; + const symbol_section_accessor symbols(elf, psymsec); - BOOST_CHECK_EQUAL( true, - symbols.get_symbol( 0x08048478, name, size, bind, - type, section_index, other) ); - BOOST_CHECK_EQUAL( "_IO_stdin_used", name ); - BOOST_CHECK_EQUAL( 14, section_index ); - BOOST_CHECK_EQUAL( 4, size ); + BOOST_CHECK_EQUAL(true, + symbols.get_symbol(0x08048478, name, size, bind, + type, section_index, other)); + BOOST_CHECK_EQUAL("_IO_stdin_used", name); + BOOST_CHECK_EQUAL(14, section_index); + BOOST_CHECK_EQUAL(4, size); } //////////////////////////////////////////////////////////////////////////////// -BOOST_AUTO_TEST_CASE( get_symbol_64 ) +BOOST_AUTO_TEST_CASE(get_symbol_64) { - elfio elf; - std::string name; + elfio elf; + std::string name; ELFIO::Elf_Xword size; - unsigned char bind; - unsigned char type; - ELFIO::Elf_Half section_index; - unsigned char other; - std::string in = "elf_examples/hello_64"; + unsigned char bind; + unsigned char type; + ELFIO::Elf_Half section_index; + unsigned char other; + std::string in = "elf_examples/hello_64"; - BOOST_REQUIRE_EQUAL( elf.load(in), true ); - section* psymsec = elf.sections[ ".symtab" ]; - const symbol_section_accessor symbols( elf, psymsec ); + BOOST_REQUIRE_EQUAL(elf.load(in), true); + section *psymsec = elf.sections[".symtab"]; + const symbol_section_accessor symbols(elf, psymsec); - BOOST_CHECK_EQUAL( true, - symbols.get_symbol(0x00400498, name, size, bind, - type, section_index, other) ); - BOOST_CHECK_EQUAL( "main", name ); - BOOST_CHECK_EQUAL( 12, section_index ); - BOOST_CHECK_EQUAL( 21, size ); + BOOST_CHECK_EQUAL(true, + symbols.get_symbol(0x00400498, name, size, bind, + type, section_index, other)); + BOOST_CHECK_EQUAL("main", name); + BOOST_CHECK_EQUAL(12, section_index); + BOOST_CHECK_EQUAL(21, size); } //////////////////////////////////////////////////////////////////////////////// -BOOST_AUTO_TEST_CASE( null_section_inside_segment ) +BOOST_AUTO_TEST_CASE(null_section_inside_segment) { // This test case checks the load/save of SHT_NULL sections in a segment // See https://github.com/serge1/ELFIO/issues/19 @@ -495,93 +495,192 @@ BOOST_AUTO_TEST_CASE( null_section_inside_segment ) // Create an ELF file with SHT_NULL sections at the beginning/middle/end of a segment elfio writer; - writer.create( ELFCLASS32, ELFDATA2LSB ); - writer.set_os_abi( ELFOSABI_LINUX ); - writer.set_type( ET_EXEC ); - writer.set_machine( EM_386 ); + writer.create(ELFCLASS32, ELFDATA2LSB); + writer.set_os_abi(ELFOSABI_LINUX); + writer.set_type(ET_EXEC); + writer.set_machine(EM_386); // Create code section 1 - section* text_sec1 = writer.sections.add( ".text1" ); - text_sec1->set_type( SHT_PROGBITS ); - text_sec1->set_flags( SHF_ALLOC | SHF_EXECINSTR ); - text_sec1->set_addr_align( 0x10 ); - text_sec1->set_address( 0x08048000 ); - char text[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - text_sec1->set_data( text, sizeof( text ) ); + section *text_sec1 = writer.sections.add(".text1"); + text_sec1->set_type(SHT_PROGBITS); + text_sec1->set_flags(SHF_ALLOC | SHF_EXECINSTR); + text_sec1->set_addr_align(0x10); + text_sec1->set_address(0x08048000); + char text[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + text_sec1->set_data(text, sizeof(text)); // Create code section 2 - section* text_sec2 = writer.sections.add( ".text2" ); - text_sec2->set_type( SHT_PROGBITS ); - text_sec2->set_flags( SHF_ALLOC | SHF_EXECINSTR ); - text_sec2->set_addr_align( 0x10 ); - text_sec2->set_address( 0x08048010 ); - text_sec2->set_data( text, sizeof( text ) ); + section *text_sec2 = writer.sections.add(".text2"); + text_sec2->set_type(SHT_PROGBITS); + text_sec2->set_flags(SHF_ALLOC | SHF_EXECINSTR); + text_sec2->set_addr_align(0x10); + text_sec2->set_address(0x08048010); + text_sec2->set_data(text, sizeof(text)); // Create null sections - section* null_sec1 = writer.sections.add( "null" ); - null_sec1->set_type( SHT_NULL ); - null_sec1->set_flags( SHF_ALLOC | SHF_EXECINSTR ); - null_sec1->set_address( 0x08048000 ); - section* null_sec2 = writer.sections.add( "null" ); - null_sec2->set_type( SHT_NULL ); - null_sec2->set_flags( SHF_ALLOC | SHF_EXECINSTR ); - null_sec2->set_address( 0x08048010 ); - section* null_sec3 = writer.sections.add( "null" ); - null_sec3->set_type( SHT_NULL ); - null_sec3->set_flags( SHF_ALLOC | SHF_EXECINSTR ); - null_sec3->set_address( 0x08048020 ); + section *null_sec1 = writer.sections.add("null"); + null_sec1->set_type(SHT_NULL); + null_sec1->set_flags(SHF_ALLOC | SHF_EXECINSTR); + null_sec1->set_address(0x08048000); + section *null_sec2 = writer.sections.add("null"); + null_sec2->set_type(SHT_NULL); + null_sec2->set_flags(SHF_ALLOC | SHF_EXECINSTR); + null_sec2->set_address(0x08048010); + section *null_sec3 = writer.sections.add("null"); + null_sec3->set_type(SHT_NULL); + null_sec3->set_flags(SHF_ALLOC | SHF_EXECINSTR); + null_sec3->set_address(0x08048020); // Create a loadable segment - segment* text_seg = writer.segments.add(); - text_seg->set_type( PT_LOAD ); - text_seg->set_virtual_address( 0x08048000 ); - text_seg->set_physical_address( 0x08048000 ); - text_seg->set_flags( PF_X | PF_R ); - text_seg->set_align( 0x1000 ); + segment *text_seg = writer.segments.add(); + text_seg->set_type(PT_LOAD); + text_seg->set_virtual_address(0x08048000); + text_seg->set_physical_address(0x08048000); + text_seg->set_flags(PF_X | PF_R); + text_seg->set_align(0x1000); // Add sections into the loadable segment - text_seg->add_section_index( null_sec1->get_index(), null_sec1->get_addr_align() ); - text_seg->add_section_index( text_sec1->get_index(), text_sec1->get_addr_align() ); - text_seg->add_section_index( null_sec2->get_index(), null_sec2->get_addr_align() ); - text_seg->add_section_index( text_sec2->get_index(), text_sec2->get_addr_align() ); - text_seg->add_section_index( null_sec3->get_index(), null_sec3->get_addr_align() ); + text_seg->add_section_index(null_sec1->get_index(), null_sec1->get_addr_align()); + text_seg->add_section_index(text_sec1->get_index(), text_sec1->get_addr_align()); + text_seg->add_section_index(null_sec2->get_index(), null_sec2->get_addr_align()); + text_seg->add_section_index(text_sec2->get_index(), text_sec2->get_addr_align()); + text_seg->add_section_index(null_sec3->get_index(), null_sec3->get_addr_align()); // Setup entry point - writer.set_entry( 0x08048000 ); + writer.set_entry(0x08048000); // Create ELF file std::string f1 = "elf_examples/null_section_inside_segment1"; std::string f2 = "elf_examples/null_section_inside_segment2"; - BOOST_CHECK_EQUAL( writer.save(f1), true ); + BOOST_CHECK_EQUAL(writer.save(f1), true); // Load and check the ELF file created above elfio elf; - BOOST_CHECK_EQUAL( elf.load(f1), true ); - BOOST_CHECK_EQUAL( elf.save(f2), true ); + BOOST_CHECK_EQUAL(elf.load(f1), true); + BOOST_CHECK_EQUAL(elf.save(f2), true); } //////////////////////////////////////////////////////////////////////////////// BOOST_AUTO_TEST_CASE(invalid_file) { - elfio elf; - std::string name; + elfio elf; + std::string name; ELFIO::Elf64_Addr value; - ELFIO::Elf_Xword size; - unsigned char bind; - unsigned char type; - ELFIO::Elf_Half section_index; - unsigned char other; - std::string in = "elf_examples/crash.elf"; + ELFIO::Elf_Xword size; + unsigned char bind; + unsigned char type; + ELFIO::Elf_Half section_index; + unsigned char other; + std::string in = "elf_examples/crash.elf"; BOOST_REQUIRE_EQUAL(elf.load(in), true); section *psymsec = elf.sections[".symtab"]; - BOOST_REQUIRE_NE(psymsec, (void*)0); + BOOST_REQUIRE_NE(psymsec, (void *)0); const symbol_section_accessor symbols(elf, psymsec); - BOOST_CHECK_EQUAL( true, - symbols.get_symbol( "main", value, size, bind, - type, section_index, other ) ); - BOOST_CHECK_EQUAL( 0x402560, value ); + BOOST_CHECK_EQUAL(true, + symbols.get_symbol("main", value, size, bind, + type, section_index, other)); + BOOST_CHECK_EQUAL(0x402560, value); BOOST_CHECK_EQUAL( - true, symbols.get_symbol( "frame_dummy", value, size, bind, - type, section_index, other ) ); - BOOST_CHECK_EQUAL( 0x402550, value ); + true, symbols.get_symbol("frame_dummy", value, size, bind, + type, section_index, other)); + BOOST_CHECK_EQUAL(0x402550, value); - BOOST_CHECK_EQUAL( false, - symbols.get_symbol( 0x00400498, name, size, bind, - type, section_index, other ) ); + BOOST_CHECK_EQUAL(false, + symbols.get_symbol(0x00400498, name, size, bind, + type, section_index, other)); +} + +//////////////////////////////////////////////////////////////////////////////// +BOOST_AUTO_TEST_CASE(rearrange_local_symbols) +{ + std::string name = ""; + ELFIO::Elf64_Addr value = 0; + ELFIO::Elf_Xword size = 0; + unsigned char bind = STB_LOCAL; + unsigned char type = STT_FUNC; + ELFIO::Elf_Half section_index = 0; + unsigned char other = 0; + const std::string file_name = "elf_examples/test_symbols_order.elf"; + + elfio writer; + writer.create(ELFCLASS64, ELFDATA2LSB); + writer.set_os_abi(ELFOSABI_LINUX); + writer.set_type(ET_EXEC); + writer.set_machine(EM_X86_64); + + section *str_sec = writer.sections.add(".strtab"); + str_sec->set_type(SHT_STRTAB); + str_sec->set_addr_align(0x1); + string_section_accessor str_writer(str_sec); + + section *sym_sec = writer.sections.add(".symtab"); + sym_sec->set_type(SHT_SYMTAB); + sym_sec->set_info(0); + sym_sec->set_link(str_sec->get_index()); + sym_sec->set_addr_align(4); + sym_sec->set_entry_size(writer.get_default_entry_size(SHT_SYMTAB)); + symbol_section_accessor symbols(writer, sym_sec); + + name = "Str1"; + bind = STB_GLOBAL; + value = 1; + symbols.add_symbol(str_writer, name.c_str(), value, size, bind, type, other, section_index); + name = "Str2"; + bind = STB_LOCAL; + value = 2; + symbols.add_symbol(str_writer, name.c_str(), value, size, bind, type, other, section_index); + name = "Str3"; + bind = STB_WEAK; + value = 3; + symbols.add_symbol(str_writer, name.c_str(), value, size, bind, type, other, section_index); + name = "Str4"; + bind = STB_LOCAL; + value = 4; + symbols.add_symbol(str_writer, name.c_str(), value, size, bind, type, other, section_index); + name = "Str5"; + bind = STB_LOCAL; + value = 5; + symbols.add_symbol(str_writer, name.c_str(), value, size, bind, type, other, section_index); + name = "Str6"; + bind = STB_GLOBAL; + value = 6; + symbols.add_symbol(str_writer, name.c_str(), value, size, bind, type, other, section_index); + name = "Str7"; + bind = STB_LOCAL; + value = 7; + symbols.add_symbol(str_writer, name.c_str(), value, size, bind, type, other, section_index); + name = "Str8"; + bind = STB_WEAK; + value = 8; + symbols.add_symbol(str_writer, name.c_str(), value, size, bind, type, other, section_index); + + symbols.arrange_local_symbols(); + + BOOST_REQUIRE_EQUAL(writer.save(file_name), true); + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + elfio reader; + BOOST_REQUIRE_EQUAL(reader.load(file_name), true); + + auto psymsec = reader.sections[".symtab"]; + BOOST_REQUIRE_NE(psymsec, nullptr); + + const_symbol_section_accessor rsymbols(reader, psymsec); + + auto bound = psymsec->get_info(); + auto num = rsymbols.get_symbols_num(); + + BOOST_CHECK_LE(bound, num); + + // Check that all symbols are LOCAL until the bound value + for (auto i = 0; i < bound; i++) + { + rsymbols.get_symbol(i, name, value, size, bind, type, section_index, other); + BOOST_CHECK_EQUAL(bind, STB_LOCAL); + } + + // Check that all symbols are not LOCAL after the bound value + for (auto i = bound; i < num; i++) + { + rsymbols.get_symbol(i, name, value, size, bind, type, section_index, other); + + BOOST_CHECK_NE(bind, STB_LOCAL); + } }