#ifdef _MSC_VER #define _SCL_SECURE_NO_WARNINGS #define ELFIO_NO_INTTYPES #endif #include #include using boost::test_tools::output_test_stream; #include 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); } }