ELFIO/tests/ELFIOTest1.cpp
Serge Lamikhov-Center 8e0b5754e4 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
2020-08-18 12:57:45 -07:00

687 lines
26 KiB
C++

#ifdef _MSC_VER
#define _SCL_SECURE_NO_WARNINGS
#define ELFIO_NO_INTTYPES
#endif
#include <boost/test/unit_test.hpp>
#include <boost/test/tools/output_test_stream.hpp>
using boost::test_tools::output_test_stream;
#include <elfio/elfio.hpp>
using namespace ELFIO;
enum Tests
{
SEG_ALIGN = 1
};
////////////////////////////////////////////////////////////////////////////////
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);
// 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);
// 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));
// 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);
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);
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));
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());
// Another way to add symbol
symbol_writer.add_symbol(str_writer, "_start", 0x00000000, 0,
STB_WEAK, STT_FUNC, 0,
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));
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",
// pSymWriter, 29, 0,
// ELF32_ST_INFO( STB_GLOBAL, STT_OBJECT ), 0,
// data_sec->GetIndex(),
// 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);
// Create notes writer
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");
return true;
}
////////////////////////////////////////////////////////////////////////////////
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);
// 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);
}
// 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));
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);
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());
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));
// Create ELF file
writer.set_entry(0x08048000);
writer.save(filename);
return true;
}
////////////////////////////////////////////////////////////////////////////////
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);
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)
{
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_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)
{
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);
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())
continue;
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());
// 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);
}
BOOST_CHECK_EQUAL_COLLECTIONS(pdata1.begin(), pdata1.end(),
pdata2.begin(), pdata2.end());
}
}
////////////////////////////////////////////////////////////////////////////////
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());
}
////////////////////////////////////////////////////////////////////////////////
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_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_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);
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());
}
////////////////////////////////////////////////////////////////////////////////
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");
// 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" );
}
////////////////////////////////////////////////////////////////////////////////
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");
}
////////////////////////////////////////////////////////////////////////////////
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);
checkObjestsAreEqual(in, out);
checkExeAreEqual(in, out, SEG_ALIGN);
}
////////////////////////////////////////////////////////////////////////////////
BOOST_AUTO_TEST_CASE(get_symbol_32)
{
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";
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_AUTO_TEST_CASE(get_symbol_64)
{
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";
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_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
//
// Note: The test case checking the load/save of a segment containing no section
// is covered by elf_object_copy_32: elf_examples/hello_32 has empty segments
// 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);
// 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));
// 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));
// 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);
// 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);
// 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());
// Setup entry point
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);
// 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_AUTO_TEST_CASE(invalid_file)
{
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";
BOOST_REQUIRE_EQUAL(elf.load(in), true);
section *psymsec = elf.sections[".symtab"];
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("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_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);
}
}