mirror of
https://github.com/serge1/ELFIO.git
synced 2024-11-02 11:27:03 +00:00
687 lines
26 KiB
C++
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((Elf_Xword)bound, num);
|
|
|
|
// Check that all symbols are LOCAL until the bound value
|
|
for (Elf_Word i = 0; i < bound; i++)
|
|
{
|
|
rsymbols.get_symbol(i, name, value, size, bind, type, section_index, other);
|
|
BOOST_CHECK_EQUAL(bind, (unsigned char)STB_LOCAL);
|
|
}
|
|
|
|
// Check that all symbols are not LOCAL after the bound value
|
|
for (Elf_Word i = bound; i < num; i++)
|
|
{
|
|
rsymbols.get_symbol(i, name, value, size, bind, type, section_index, other);
|
|
|
|
BOOST_CHECK_NE(bind, (unsigned char)STB_LOCAL);
|
|
}
|
|
}
|