1 /*
2 Copyright (C) 2001-present by Serge Lamikhov-Center
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 THE SOFTWARE.
21 */
22
23 #ifdef _MSC_VER
24 #define _SCL_SECURE_NO_WARNINGS
25 #define ELFIO_NO_INTTYPES
26 #endif
27
28 #include <boost/test/unit_test.hpp>
29 #include <boost/test/tools/output_test_stream.hpp>
30 using boost::test_tools::output_test_stream;
31
32 #include <elfio/elfio.hpp>
33
34 using namespace ELFIO;
35
36 enum Tests
37 {
38 SEG_ALIGN = 1
39 };
40
41 ////////////////////////////////////////////////////////////////////////////////
write_obj_i386(bool is64bit)42 bool write_obj_i386( bool is64bit )
43 {
44 elfio writer;
45
46 writer.create( is64bit ? ELFCLASS64 : ELFCLASS32, ELFDATA2LSB );
47 writer.set_type( ET_REL );
48 writer.set_os_abi( ELFOSABI_LINUX );
49 writer.set_machine( is64bit ? EM_X86_64 : EM_386 );
50
51 // Create code section*
52 section* text_sec = writer.sections.add( ".text" );
53 text_sec->set_type( SHT_PROGBITS );
54 text_sec->set_flags( SHF_ALLOC | SHF_EXECINSTR );
55 text_sec->set_addr_align( 0x10 );
56
57 // Add data into it
58 char text[] = {
59 '\xB8', '\x04', '\x00', '\x00', '\x00', // mov eax, 4
60 '\xBB', '\x01', '\x00', '\x00', '\x00', // mov ebx, 1
61 '\xB9', '\x00', '\x00', '\x00', '\x00', // mov ecx, msg
62 '\xBA', '\x0E', '\x00', '\x00', '\x00', // mov edx, 14
63 '\xCD', '\x80', // int 0x80
64 '\xB8', '\x01', '\x00', '\x00', '\x00', // mov eax, 1
65 '\xCD', '\x80' // int 0x80
66 };
67 text_sec->set_data( text, sizeof( text ) );
68
69 // Create data section*
70 section* data_sec = writer.sections.add( ".data" );
71 data_sec->set_type( SHT_PROGBITS );
72 data_sec->set_flags( SHF_ALLOC | SHF_WRITE );
73 data_sec->set_addr_align( 4 );
74
75 char data[] = {
76 '\x48', '\x65', '\x6C', '\x6C', '\x6F', // msg: db 'Hello, World!', 10
77 '\x2C', '\x20', '\x57', '\x6F', '\x72',
78 '\x6C', '\x64', '\x21', '\x0A' };
79 data_sec->set_data( data, sizeof( data ) );
80
81 section* str_sec = writer.sections.add( ".strtab" );
82 str_sec->set_type( SHT_STRTAB );
83 str_sec->set_addr_align( 0x1 );
84
85 string_section_accessor str_writer( str_sec );
86 Elf_Word nStrIndex = str_writer.add_string( "msg" );
87
88 section* sym_sec = writer.sections.add( ".symtab" );
89 sym_sec->set_type( SHT_SYMTAB );
90 sym_sec->set_info( 2 );
91 sym_sec->set_link( str_sec->get_index() );
92 sym_sec->set_addr_align( 4 );
93 sym_sec->set_entry_size( writer.get_default_entry_size( SHT_SYMTAB ) );
94
95 symbol_section_accessor symbol_writer( writer, sym_sec );
96 Elf_Word nSymIndex = symbol_writer.add_symbol(
97 nStrIndex, 0, 0, STB_LOCAL, STT_NOTYPE, 0, data_sec->get_index() );
98
99 // Another way to add symbol
100 symbol_writer.add_symbol( str_writer, "_start", 0x00000000, 0, STB_WEAK,
101 STT_FUNC, 0, text_sec->get_index() );
102
103 // Create relocation table section*
104 section* rel_sec = writer.sections.add( ".rel.text" );
105 rel_sec->set_type( SHT_REL );
106 rel_sec->set_info( text_sec->get_index() );
107 rel_sec->set_link( sym_sec->get_index() );
108 rel_sec->set_addr_align( 4 );
109 rel_sec->set_entry_size( writer.get_default_entry_size( SHT_REL ) );
110
111 relocation_section_accessor rel_writer( writer, rel_sec );
112 rel_writer.add_entry( 11, nSymIndex, (unsigned char)R_386_RELATIVE );
113
114 // Another method to add the same relocation entry
115 // pRelWriter->AddEntry( pStrWriter, "msg",
116 // pSymWriter, 29, 0,
117 // ELF32_ST_INFO( STB_GLOBAL, STT_OBJECT ), 0,
118 // data_sec->GetIndex(),
119 // 0, (unsigned char)R_386_RELATIVE );
120
121 // Create note section*
122 section* note_sec = writer.sections.add( ".note" );
123 note_sec->set_type( SHT_NOTE );
124 note_sec->set_addr_align( 1 );
125
126 // Create notes writer
127 note_section_accessor note_writer( writer, note_sec );
128 note_writer.add_note( 0x77, "Created by ELFIO", 0, 0 );
129
130 // Create ELF file
131 writer.save( is64bit ? "elf_examples/write_obj_i386_64.o"
132 : "elf_examples/write_obj_i386_32.o" );
133
134 return true;
135 }
136
137 ////////////////////////////////////////////////////////////////////////////////
write_exe_i386(const std::string & filename,bool is64bit,bool set_addr=false,Elf64_Addr addr=0)138 bool write_exe_i386( const std::string& filename,
139 bool is64bit,
140 bool set_addr = false,
141 Elf64_Addr addr = 0 )
142 {
143 elfio writer;
144
145 writer.create( is64bit ? ELFCLASS64 : ELFCLASS32, ELFDATA2LSB );
146 writer.set_os_abi( ELFOSABI_LINUX );
147 writer.set_type( ET_EXEC );
148 writer.set_machine( is64bit ? EM_X86_64 : EM_386 );
149
150 // Create code section*
151 section* text_sec = writer.sections.add( ".text" );
152 text_sec->set_type( SHT_PROGBITS );
153 text_sec->set_flags( SHF_ALLOC | SHF_EXECINSTR );
154 text_sec->set_addr_align( 0x10 );
155 if ( set_addr ) {
156 text_sec->set_address( addr );
157 }
158
159 // Add data into it
160 char text[] = {
161 '\xB8', '\x04', '\x00', '\x00', '\x00', // mov eax, 4
162 '\xBB', '\x01', '\x00', '\x00', '\x00', // mov ebx, 1
163 '\xB9', '\x20', '\x80', '\x04', '\x08', // mov ecx, msg
164 '\xBA', '\x0E', '\x00', '\x00', '\x00', // mov edx, 14
165 '\xCD', '\x80', // int 0x80
166 '\xB8', '\x01', '\x00', '\x00', '\x00', // mov eax, 1
167 '\xCD', '\x80' // int 0x80
168 };
169 text_sec->set_data( text, sizeof( text ) );
170
171 segment* text_seg = writer.segments.add();
172 text_seg->set_type( PT_LOAD );
173 text_seg->set_virtual_address( 0x08048000 );
174 text_seg->set_physical_address( 0x08048000 );
175 text_seg->set_flags( PF_X | PF_R );
176 text_seg->set_align( 0x1000 );
177 text_seg->add_section_index( text_sec->get_index(),
178 text_sec->get_addr_align() );
179
180 // Create data section*
181 section* data_sec = writer.sections.add( ".data" );
182 data_sec->set_type( SHT_PROGBITS );
183 data_sec->set_flags( SHF_ALLOC | SHF_WRITE );
184 data_sec->set_addr_align( 0x4 );
185
186 char data[] = {
187 '\x48', '\x65', '\x6C', '\x6C', '\x6F', // msg: db 'Hello, World!', 10
188 '\x2C', '\x20', '\x57', '\x6F', '\x72',
189 '\x6C', '\x64', '\x21', '\x0A' };
190 data_sec->set_data( data, sizeof( data ) );
191
192 segment* data_seg = writer.segments.add();
193 data_seg->set_type( PT_LOAD );
194 data_seg->set_virtual_address( 0x08048020 );
195 data_seg->set_physical_address( 0x08048020 );
196 data_seg->set_flags( PF_W | PF_R );
197 data_seg->set_align( 0x10 );
198 data_seg->add_section_index( data_sec->get_index(),
199 data_sec->get_addr_align() );
200
201 section* note_sec = writer.sections.add( ".note" );
202 note_sec->set_type( SHT_NOTE );
203 note_sec->set_addr_align( 1 );
204 note_section_accessor note_writer( writer, note_sec );
205 note_writer.add_note( 0x01, "Created by ELFIO", 0, 0 );
206 char descr[6] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36 };
207 note_writer.add_note( 0x01, "Never easier!", descr, sizeof( descr ) );
208
209 // Create ELF file
210 writer.set_entry( 0x08048000 );
211
212 writer.save( filename );
213
214 return true;
215 }
216
217 ////////////////////////////////////////////////////////////////////////////////
checkObjestsAreEqual(std::string file_name1,std::string file_name2)218 void checkObjestsAreEqual( std::string file_name1, std::string file_name2 )
219 {
220 elfio file1;
221 elfio file2;
222 BOOST_REQUIRE_EQUAL( file1.load( file_name1 ), true );
223 BOOST_CHECK_EQUAL( file1.save( file_name2 ), true );
224 BOOST_REQUIRE_EQUAL( file1.load( file_name1 ), true );
225 BOOST_REQUIRE_EQUAL( file2.load( file_name2 ), true );
226
227 for ( int i = 0; i < file1.sections.size(); ++i ) {
228 BOOST_CHECK_EQUAL( file1.sections[i]->get_address(),
229 file2.sections[i]->get_address() );
230 BOOST_CHECK_EQUAL( file1.sections[i]->get_addr_align(),
231 file2.sections[i]->get_addr_align() );
232 BOOST_CHECK_EQUAL( file1.sections[i]->get_entry_size(),
233 file2.sections[i]->get_entry_size() );
234 BOOST_CHECK_EQUAL( file1.sections[i]->get_flags(),
235 file2.sections[i]->get_flags() );
236 BOOST_CHECK_EQUAL( file1.sections[i]->get_index(),
237 file2.sections[i]->get_index() );
238 BOOST_CHECK_EQUAL( file1.sections[i]->get_info(),
239 file2.sections[i]->get_info() );
240 BOOST_CHECK_EQUAL( file1.sections[i]->get_link(),
241 file2.sections[i]->get_link() );
242 BOOST_CHECK_EQUAL( file1.sections[i]->get_name(),
243 file2.sections[i]->get_name() );
244 BOOST_CHECK_EQUAL( file1.sections[i]->get_name_string_offset(),
245 file2.sections[i]->get_name_string_offset() );
246 BOOST_CHECK_EQUAL( file1.sections[i]->get_size(),
247 file2.sections[i]->get_size() );
248 BOOST_CHECK_EQUAL( file1.sections[i]->get_type(),
249 file2.sections[i]->get_type() );
250
251 if ( file1.sections[i]->get_type() == SHT_NULL ||
252 file1.sections[i]->get_type() == SHT_NOBITS ) {
253 continue;
254 }
255 BOOST_REQUIRE_NE( file1.sections[i]->get_data(), (const char*)0 );
256 BOOST_REQUIRE_NE( file2.sections[i]->get_data(), (const char*)0 );
257 std::string pdata1( file1.sections[i]->get_data(),
258 file1.sections[i]->get_data() +
259 file1.sections[i]->get_size() );
260 std::string pdata2( file2.sections[i]->get_data(),
261 file2.sections[i]->get_data() +
262 file2.sections[i]->get_size() );
263
264 BOOST_CHECK_EQUAL( file1.sections[i]->get_size(),
265 file2.sections[i]->get_size() );
266 if ( ( file2.sections[i]->get_type() != SHT_NULL ) &&
267 ( file2.sections[i]->get_type() != SHT_NOBITS ) ) {
268 BOOST_CHECK_EQUAL_COLLECTIONS( pdata1.begin(), pdata1.end(),
269 pdata2.begin(), pdata2.end() );
270 }
271 }
272 }
273
274 ////////////////////////////////////////////////////////////////////////////////
checkExeAreEqual(std::string file_name1,std::string file_name2,int skipTests=0)275 void checkExeAreEqual( std::string file_name1,
276 std::string file_name2,
277 int skipTests = 0 )
278 {
279 checkObjestsAreEqual( file_name1, file_name2 );
280
281 elfio file1;
282 elfio file2;
283
284 BOOST_REQUIRE_EQUAL( file1.load( file_name1 ), true );
285 BOOST_REQUIRE_EQUAL( file2.load( file_name2 ), true );
286
287 for ( int i = 0; i < file1.segments.size(); ++i ) {
288 if ( !( skipTests & SEG_ALIGN ) )
289 BOOST_CHECK_EQUAL( file1.segments[i]->get_align(),
290 file2.segments[i]->get_align() );
291 BOOST_CHECK_EQUAL( file1.segments[i]->get_file_size(),
292 file2.segments[i]->get_file_size() );
293 BOOST_CHECK_EQUAL( file1.segments[i]->get_memory_size(),
294 file2.segments[i]->get_memory_size() );
295 BOOST_CHECK_EQUAL( file1.segments[i]->get_type(),
296 file2.segments[i]->get_type() );
297
298 // skip data comparisons of the program header and of empty segments
299 if ( file1.segments[i]->get_type() == PT_PHDR ||
300 !file1.segments[i]->get_file_size() )
301 continue;
302
303 BOOST_REQUIRE_NE( file1.segments[i]->get_data(), (const char*)0 );
304 BOOST_REQUIRE_NE( file2.segments[i]->get_data(), (const char*)0 );
305
306 std::string pdata1( file1.segments[i]->get_data(),
307 file1.segments[i]->get_data() +
308 file1.segments[i]->get_file_size() );
309 std::string pdata2( file2.segments[i]->get_data(),
310 file2.segments[i]->get_data() +
311 file2.segments[i]->get_file_size() );
312
313 // truncate the data if the header and the segment table is
314 // part of the segment
315 Elf64_Off afterPHDR =
316 file1.get_segments_offset() +
317 file1.get_segment_entry_size() * (Elf64_Off)file1.segments.size();
318 if ( file1.segments[i]->get_offset() < afterPHDR ) {
319 pdata1 = pdata1.substr( (unsigned int)afterPHDR );
320 pdata2 = pdata2.substr( (unsigned int)afterPHDR );
321 }
322
323 BOOST_CHECK_EQUAL_COLLECTIONS( pdata1.begin(), pdata1.end(),
324 pdata2.begin(), pdata2.end() );
325 }
326 }
327
328 ////////////////////////////////////////////////////////////////////////////////
BOOST_AUTO_TEST_CASE(write_obj_i386_32)329 BOOST_AUTO_TEST_CASE( write_obj_i386_32 )
330 {
331 BOOST_CHECK_EQUAL( true, write_obj_i386( false ) );
332 output_test_stream output( "elf_examples/write_obj_i386_32_match.o", true,
333 false );
334 std::ifstream input( "elf_examples/write_obj_i386_32.o", std::ios::binary );
335 output << input.rdbuf();
336 BOOST_CHECK( output.match_pattern() );
337 }
338
339 ////////////////////////////////////////////////////////////////////////////////
BOOST_AUTO_TEST_CASE(write_obj_i386_64)340 BOOST_AUTO_TEST_CASE( write_obj_i386_64 )
341 {
342 BOOST_CHECK_EQUAL( true, write_obj_i386( true ) );
343 output_test_stream output( "elf_examples/write_obj_i386_64_match.o", true,
344 false );
345 std::ifstream input( "elf_examples/write_obj_i386_64.o", std::ios::binary );
346 output << input.rdbuf();
347 BOOST_CHECK( output.match_pattern() );
348 }
349
350 ////////////////////////////////////////////////////////////////////////////////
BOOST_AUTO_TEST_CASE(write_exe_i386_32)351 BOOST_AUTO_TEST_CASE( write_exe_i386_32 )
352 {
353 const std::string generated_file( "elf_examples/write_exe_i386_32" );
354 const std::string reference_file( "elf_examples/write_exe_i386_32_match" );
355 BOOST_CHECK_EQUAL( true, write_exe_i386( generated_file, false ) );
356 output_test_stream output( reference_file, true, false );
357 std::ifstream input( generated_file, std::ios::binary );
358 output << input.rdbuf();
359 BOOST_CHECK_MESSAGE( output.match_pattern(), "Comparing " + generated_file +
360 " and " + reference_file );
361 }
362
363 ////////////////////////////////////////////////////////////////////////////////
BOOST_AUTO_TEST_CASE(elf_object_copy_32)364 BOOST_AUTO_TEST_CASE( elf_object_copy_32 )
365 {
366 checkObjestsAreEqual( "elf_examples/hello_32.o",
367 "elf_examples/hello_32_copy.o" );
368 checkObjestsAreEqual( "elf_examples/hello_64.o",
369 "elf_examples/hello_64_copy.o" );
370 checkObjestsAreEqual( "elf_examples/test_ppc.o",
371 "elf_examples/test_ppc_copy.o" );
372 checkObjestsAreEqual( "elf_examples/write_obj_i386_32.o",
373 "elf_examples/write_obj_i386_32_copy.o" );
374 checkObjestsAreEqual( "elf_examples/write_obj_i386_64.o",
375 "elf_examples/write_obj_i386_64_copy.o" );
376 }
377
378 ////////////////////////////////////////////////////////////////////////////////
BOOST_AUTO_TEST_CASE(section_header_address_update)379 BOOST_AUTO_TEST_CASE( section_header_address_update )
380 {
381 elfio reader;
382
383 const std::string file_w_addr( "elf_examples/write_exe_i386_32_w_addr" );
384 write_exe_i386( file_w_addr, false, true, 0x08048100 );
385 reader.load( file_w_addr );
386 section* sec = reader.sections[".text"];
387 BOOST_REQUIRE_NE( sec, (section*)0 );
388 BOOST_CHECK_EQUAL( sec->get_address(), 0x08048100 );
389
390 const std::string file_wo_addr( "elf_examples/write_exe_i386_32_wo_addr" );
391 write_exe_i386( file_wo_addr, false, false, 0 );
392 reader.load( file_wo_addr );
393 sec = reader.sections[".text"];
394 BOOST_REQUIRE_NE( sec, (section*)0 );
395 BOOST_CHECK_EQUAL( sec->get_address(), 0x08048000 );
396 }
397
398 ////////////////////////////////////////////////////////////////////////////////
BOOST_AUTO_TEST_CASE(elfio_copy)399 BOOST_AUTO_TEST_CASE( elfio_copy )
400 {
401 elfio e;
402
403 const std::string filename(
404 "elf_examples/write_exe_i386_32_section_added" );
405 write_exe_i386( filename, false, true, 0x08048100 );
406
407 e.load( filename );
408 Elf_Half num = e.sections.size();
409 //section* new_sec =
410 e.sections.add( "new" );
411 e.save( filename );
412 BOOST_CHECK_EQUAL( num + 1, e.sections.size() );
413 }
414
415 ////////////////////////////////////////////////////////////////////////////////
BOOST_AUTO_TEST_CASE(elf_exe_copy_64)416 BOOST_AUTO_TEST_CASE( elf_exe_copy_64 )
417 {
418 checkExeAreEqual( "elf_examples/64bitLOAD.elf",
419 "elf_examples/64bitLOAD_copy.elf" );
420 checkExeAreEqual( "elf_examples/asm64", "elf_examples/asm64_copy" );
421 checkExeAreEqual( "elf_examples/hello_64", "elf_examples/hello_64_copy" );
422
423 // The last segment (GNU_RELRO) is bigger than necessary.
424 // I don't see why but it contains a few bits of the .got.plt section.
425 // -> load, store, compare cycle fails
426 // checkExeAreEqual( "elf_examples/main",
427 // "elf_examples/main_copy" );
428 // checkExeAreEqual( "elf_examples/ls",
429 // "elf_examples/ls_copy" );
430 }
431
432 ////////////////////////////////////////////////////////////////////////////////
BOOST_AUTO_TEST_CASE(elf_exe_copy_32)433 BOOST_AUTO_TEST_CASE( elf_exe_copy_32 )
434 {
435 checkExeAreEqual( "elf_examples/asm", "elf_examples/asm_copy" );
436 checkExeAreEqual( "elf_examples/arm_v7m_test_debug.elf",
437 "elf_examples/arm_v7m_test_debug_copy.elf" );
438 checkExeAreEqual( "elf_examples/arm_v7m_test_release.elf",
439 "elf_examples/arm_v7m_test_release_copy.elf" );
440 checkExeAreEqual( "elf_examples/hello_32", "elf_examples/hello_32_copy" );
441 checkExeAreEqual( "elf_examples/hello_arm", "elf_examples/hello_arm_copy" );
442 checkExeAreEqual( "elf_examples/hello_arm_stripped",
443 "elf_examples/hello_arm_stripped_copy" );
444 checkExeAreEqual( "elf_examples/read_write_arm_elf32_input",
445 "elf_examples/read_write_arm_elf32_input_copy" );
446 checkExeAreEqual( "elf_examples/test_ppc", "elf_examples/test_ppc_copy" );
447 }
448
449 ////////////////////////////////////////////////////////////////////////////////
BOOST_AUTO_TEST_CASE(elf_exe_loadsave_ppc32big3)450 BOOST_AUTO_TEST_CASE( elf_exe_loadsave_ppc32big3 )
451 {
452 std::string in = "elf_examples/ppc-32bit-specimen3.elf";
453 std::string out = "elf_examples/ppc-32bit-testcopy3.elf";
454 elfio elf;
455 BOOST_REQUIRE_EQUAL( elf.load( in ), true );
456 BOOST_REQUIRE_EQUAL( elf.save( out ), true );
457
458 checkObjestsAreEqual( in, out );
459 checkExeAreEqual( in, out, SEG_ALIGN );
460 }
461
462 ////////////////////////////////////////////////////////////////////////////////
BOOST_AUTO_TEST_CASE(get_symbol_32)463 BOOST_AUTO_TEST_CASE( get_symbol_32 )
464 {
465 elfio elf;
466 std::string name;
467 ELFIO::Elf_Xword size;
468 unsigned char bind;
469 unsigned char type;
470 ELFIO::Elf_Half section_index;
471 unsigned char other;
472 std::string in = "elf_examples/hello_32";
473
474 BOOST_REQUIRE_EQUAL( elf.load( in ), true );
475 section* psymsec = elf.sections[".symtab"];
476 const symbol_section_accessor symbols( elf, psymsec );
477
478 BOOST_CHECK_EQUAL( true, symbols.get_symbol( 0x08048478, name, size, bind,
479 type, section_index, other ) );
480 BOOST_CHECK_EQUAL( "_IO_stdin_used", name );
481 BOOST_CHECK_EQUAL( 14, section_index );
482 BOOST_CHECK_EQUAL( 4, size );
483 }
484
485 ////////////////////////////////////////////////////////////////////////////////
BOOST_AUTO_TEST_CASE(get_symbol_64)486 BOOST_AUTO_TEST_CASE( get_symbol_64 )
487 {
488 elfio elf;
489 std::string name;
490 ELFIO::Elf_Xword size;
491 unsigned char bind;
492 unsigned char type;
493 ELFIO::Elf_Half section_index;
494 unsigned char other;
495 std::string in = "elf_examples/hello_64";
496
497 BOOST_REQUIRE_EQUAL( elf.load( in ), true );
498 section* psymsec = elf.sections[".symtab"];
499 const symbol_section_accessor symbols( elf, psymsec );
500
501 BOOST_CHECK_EQUAL( true, symbols.get_symbol( 0x00400498, name, size, bind,
502 type, section_index, other ) );
503 BOOST_CHECK_EQUAL( "main", name );
504 BOOST_CHECK_EQUAL( 12, section_index );
505 BOOST_CHECK_EQUAL( 21, size );
506 }
507
508 ////////////////////////////////////////////////////////////////////////////////
BOOST_AUTO_TEST_CASE(null_section_inside_segment)509 BOOST_AUTO_TEST_CASE( null_section_inside_segment )
510 {
511 // This test case checks the load/save of SHT_NULL sections in a segment
512 // See https://github.com/serge1/ELFIO/issues/19
513 //
514 // Note: The test case checking the load/save of a segment containing no section
515 // is covered by elf_object_copy_32: elf_examples/hello_32 has empty segments
516
517 // Create an ELF file with SHT_NULL sections at the beginning/middle/end of a segment
518 elfio writer;
519 writer.create( ELFCLASS32, ELFDATA2LSB );
520 writer.set_os_abi( ELFOSABI_LINUX );
521 writer.set_type( ET_EXEC );
522 writer.set_machine( EM_386 );
523 // Create code section 1
524 section* text_sec1 = writer.sections.add( ".text1" );
525 text_sec1->set_type( SHT_PROGBITS );
526 text_sec1->set_flags( SHF_ALLOC | SHF_EXECINSTR );
527 text_sec1->set_addr_align( 0x10 );
528 text_sec1->set_address( 0x08048000 );
529 char text[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
530 text_sec1->set_data( text, sizeof( text ) );
531 // Create code section 2
532 section* text_sec2 = writer.sections.add( ".text2" );
533 text_sec2->set_type( SHT_PROGBITS );
534 text_sec2->set_flags( SHF_ALLOC | SHF_EXECINSTR );
535 text_sec2->set_addr_align( 0x10 );
536 text_sec2->set_address( 0x08048010 );
537 text_sec2->set_data( text, sizeof( text ) );
538 // Create null sections
539 section* null_sec1 = writer.sections.add( "null" );
540 null_sec1->set_type( SHT_NULL );
541 null_sec1->set_flags( SHF_ALLOC | SHF_EXECINSTR );
542 null_sec1->set_address( 0x08048000 );
543 section* null_sec2 = writer.sections.add( "null" );
544 null_sec2->set_type( SHT_NULL );
545 null_sec2->set_flags( SHF_ALLOC | SHF_EXECINSTR );
546 null_sec2->set_address( 0x08048010 );
547 section* null_sec3 = writer.sections.add( "null" );
548 null_sec3->set_type( SHT_NULL );
549 null_sec3->set_flags( SHF_ALLOC | SHF_EXECINSTR );
550 null_sec3->set_address( 0x08048020 );
551 // Create a loadable segment
552 segment* text_seg = writer.segments.add();
553 text_seg->set_type( PT_LOAD );
554 text_seg->set_virtual_address( 0x08048000 );
555 text_seg->set_physical_address( 0x08048000 );
556 text_seg->set_flags( PF_X | PF_R );
557 text_seg->set_align( 0x1000 );
558 // Add sections into the loadable segment
559 text_seg->add_section_index( null_sec1->get_index(),
560 null_sec1->get_addr_align() );
561 text_seg->add_section_index( text_sec1->get_index(),
562 text_sec1->get_addr_align() );
563 text_seg->add_section_index( null_sec2->get_index(),
564 null_sec2->get_addr_align() );
565 text_seg->add_section_index( text_sec2->get_index(),
566 text_sec2->get_addr_align() );
567 text_seg->add_section_index( null_sec3->get_index(),
568 null_sec3->get_addr_align() );
569 // Setup entry point
570 writer.set_entry( 0x08048000 );
571 // Create ELF file
572 std::string f1 = "elf_examples/null_section_inside_segment1";
573 std::string f2 = "elf_examples/null_section_inside_segment2";
574 BOOST_CHECK_EQUAL( writer.save( f1 ), true );
575
576 // Load and check the ELF file created above
577 elfio elf;
578 BOOST_CHECK_EQUAL( elf.load( f1 ), true );
579 BOOST_CHECK_EQUAL( elf.save( f2 ), true );
580 }
581
582 ////////////////////////////////////////////////////////////////////////////////
BOOST_AUTO_TEST_CASE(invalid_file)583 BOOST_AUTO_TEST_CASE( invalid_file )
584 {
585 elfio elf;
586 std::string name;
587 ELFIO::Elf64_Addr value;
588 ELFIO::Elf_Xword size;
589 unsigned char bind;
590 unsigned char type;
591 ELFIO::Elf_Half section_index;
592 unsigned char other;
593 std::string in = "elf_examples/crash.elf";
594
595 BOOST_REQUIRE_EQUAL( elf.load( in ), true );
596 section* psymsec = elf.sections[".symtab"];
597 BOOST_REQUIRE_NE( psymsec, (void*)0 );
598 const symbol_section_accessor symbols( elf, psymsec );
599
600 BOOST_CHECK_EQUAL( true, symbols.get_symbol( "main", value, size, bind,
601 type, section_index, other ) );
602 BOOST_CHECK_EQUAL( 0x402560, value );
603
604 BOOST_CHECK_EQUAL( true,
605 symbols.get_symbol( "frame_dummy", value, size, bind,
606 type, section_index, other ) );
607 BOOST_CHECK_EQUAL( 0x402550, value );
608
609 BOOST_CHECK_EQUAL( false,
610 symbols.get_symbol( 0x00400498, name, size, bind, type,
611 section_index, other ) );
612 }
613
614 ////////////////////////////////////////////////////////////////////////////////
BOOST_AUTO_TEST_CASE(rearrange_local_symbols)615 BOOST_AUTO_TEST_CASE( rearrange_local_symbols )
616 {
617 std::string name = "";
618 ELFIO::Elf64_Addr value = 0;
619 ELFIO::Elf_Xword size = 0;
620 unsigned char bind = STB_LOCAL;
621 unsigned char type = STT_FUNC;
622 ELFIO::Elf_Half section_index = 0;
623 unsigned char other = 0;
624 const std::string file_name = "elf_examples/test_symbols_order.elf";
625
626 elfio writer;
627 writer.create( ELFCLASS64, ELFDATA2LSB );
628 writer.set_os_abi( ELFOSABI_LINUX );
629 writer.set_type( ET_EXEC );
630 writer.set_machine( EM_X86_64 );
631
632 section* str_sec = writer.sections.add( ".strtab" );
633 str_sec->set_type( SHT_STRTAB );
634 str_sec->set_addr_align( 0x1 );
635 string_section_accessor str_writer( str_sec );
636
637 section* sym_sec = writer.sections.add( ".symtab" );
638 sym_sec->set_type( SHT_SYMTAB );
639 sym_sec->set_info( 0 );
640 sym_sec->set_link( str_sec->get_index() );
641 sym_sec->set_addr_align( 4 );
642 sym_sec->set_entry_size( writer.get_default_entry_size( SHT_SYMTAB ) );
643 symbol_section_accessor symbols( writer, sym_sec );
644
645 name = "Str1";
646 bind = STB_GLOBAL;
647 value = 1;
648 symbols.add_symbol( str_writer, name.c_str(), value, size, bind, type,
649 other, section_index );
650 name = "Str2";
651 bind = STB_LOCAL;
652 value = 2;
653 symbols.add_symbol( str_writer, name.c_str(), value, size, bind, type,
654 other, section_index );
655 name = "Str3";
656 bind = STB_WEAK;
657 value = 3;
658 symbols.add_symbol( str_writer, name.c_str(), value, size, bind, type,
659 other, section_index );
660 name = "Str4";
661 bind = STB_LOCAL;
662 value = 4;
663 symbols.add_symbol( str_writer, name.c_str(), value, size, bind, type,
664 other, section_index );
665 name = "Str5";
666 bind = STB_LOCAL;
667 value = 5;
668 symbols.add_symbol( str_writer, name.c_str(), value, size, bind, type,
669 other, section_index );
670 name = "Str6";
671 bind = STB_GLOBAL;
672 value = 6;
673 symbols.add_symbol( str_writer, name.c_str(), value, size, bind, type,
674 other, section_index );
675 name = "Str7";
676 bind = STB_LOCAL;
677 value = 7;
678 symbols.add_symbol( str_writer, name.c_str(), value, size, bind, type,
679 other, section_index );
680 name = "Str8";
681 bind = STB_WEAK;
682 value = 8;
683 symbols.add_symbol( str_writer, name.c_str(), value, size, bind, type,
684 other, section_index );
685
686 symbols.arrange_local_symbols( [&]( Elf_Xword first, Elf_Xword ) -> void {
687 static int counter = 0;
688 BOOST_CHECK_EQUAL( first, ++counter );
689 // std::string name = "";
690 // ELFIO::Elf64_Addr value = 0;
691 // ELFIO::Elf_Xword size = 0;
692 // unsigned char bind = STB_LOCAL;
693 // unsigned char type = STT_FUNC;
694 // ELFIO::Elf_Half section_index = 0;
695 // unsigned char other = 0;
696
697 // std::cout << first << " " << second << std::endl;
698 // symbols.get_symbol(first, name, value, size, bind, type, section_index, other);
699 // std::cout << " " << name;
700 // symbols.get_symbol(second, name, value, size, bind, type, section_index, other);
701 // std::cout << " " << name << std::endl;
702 } );
703
704 BOOST_REQUIRE_EQUAL( writer.save( file_name ), true );
705
706 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
707
708 elfio reader;
709 BOOST_REQUIRE_EQUAL( reader.load( file_name ), true );
710
711 auto psymsec = reader.sections[".symtab"];
712 BOOST_REQUIRE_NE( psymsec, nullptr );
713
714 const_symbol_section_accessor rsymbols( reader, psymsec );
715
716 auto bound = psymsec->get_info();
717 auto num = rsymbols.get_symbols_num();
718
719 BOOST_CHECK_LE( (Elf_Xword)bound, num );
720
721 // Check that all symbols are LOCAL until the bound value
722 for ( Elf_Word i = 0; i < bound; i++ ) {
723 rsymbols.get_symbol( i, name, value, size, bind, type, section_index,
724 other );
725 BOOST_CHECK_EQUAL( bind, (unsigned char)STB_LOCAL );
726 }
727 BOOST_CHECK_EQUAL( name, "Str7" );
728
729 // Check that all symbols are not LOCAL after the bound value
730 for ( Elf_Word i = bound; i < num; i++ ) {
731 rsymbols.get_symbol( i, name, value, size, bind, type, section_index,
732 other );
733
734 BOOST_CHECK_NE( bind, (unsigned char)STB_LOCAL );
735 }
736 BOOST_CHECK_EQUAL( name, "Str8" );
737 }
738
739 ////////////////////////////////////////////////////////////////////////////////
BOOST_AUTO_TEST_CASE(rearrange_local_symbols_with_reallocation)740 BOOST_AUTO_TEST_CASE( rearrange_local_symbols_with_reallocation )
741 {
742 std::string name = "";
743 ELFIO::Elf64_Addr value = 0;
744 ELFIO::Elf_Xword size = 0;
745 unsigned char bind = STB_LOCAL;
746 unsigned char type = STT_FUNC;
747 ELFIO::Elf_Half section_index = 0;
748 unsigned char other = 0;
749 const std::string file_name = "elf_examples/test_symbols_order.elf";
750
751 elfio writer;
752 writer.create( ELFCLASS64, ELFDATA2LSB );
753 writer.set_os_abi( ELFOSABI_LINUX );
754 writer.set_type( ET_EXEC );
755 writer.set_machine( EM_X86_64 );
756
757 section* text_sec = writer.sections.add( ".text" );
758 text_sec->set_type( SHT_PROGBITS );
759 text_sec->set_flags( SHF_ALLOC | SHF_EXECINSTR );
760 text_sec->set_addr_align( 0x10 );
761
762 section* str_sec = writer.sections.add( ".strtab" );
763 str_sec->set_type( SHT_STRTAB );
764 str_sec->set_addr_align( 0x1 );
765 string_section_accessor str_writer( str_sec );
766
767 section* sym_sec = writer.sections.add( ".symtab" );
768 sym_sec->set_type( SHT_SYMTAB );
769 sym_sec->set_info( 0 );
770 sym_sec->set_link( str_sec->get_index() );
771 sym_sec->set_addr_align( 4 );
772 sym_sec->set_entry_size( writer.get_default_entry_size( SHT_SYMTAB ) );
773 symbol_section_accessor symbols( writer, sym_sec );
774
775 name = "Str1";
776 bind = STB_GLOBAL;
777 value = 1;
778 Elf_Word sym1 = symbols.add_symbol( str_writer, name.c_str(), value, size,
779 bind, type, other, section_index );
780 name = "Str2";
781 bind = STB_LOCAL;
782 value = 2;
783 Elf_Word sym2 = symbols.add_symbol( str_writer, name.c_str(), value, size,
784 bind, type, other, section_index );
785 name = "Str3";
786 bind = STB_WEAK;
787 value = 3;
788 Elf_Word sym3 = symbols.add_symbol( str_writer, name.c_str(), value, size,
789 bind, type, other, section_index );
790 name = "Str4";
791 bind = STB_LOCAL;
792 value = 4;
793 Elf_Word sym4 = symbols.add_symbol( str_writer, name.c_str(), value, size,
794 bind, type, other, section_index );
795 name = "Str5";
796 bind = STB_LOCAL;
797 value = 5;
798 Elf_Word sym5 = symbols.add_symbol( str_writer, name.c_str(), value, size,
799 bind, type, other, section_index );
800 name = "Str6";
801 bind = STB_GLOBAL;
802 value = 6;
803 Elf_Word sym6 = symbols.add_symbol( str_writer, name.c_str(), value, size,
804 bind, type, other, section_index );
805 name = "Str7";
806 bind = STB_LOCAL;
807 value = 7;
808 Elf_Word sym7 = symbols.add_symbol( str_writer, name.c_str(), value, size,
809 bind, type, other, section_index );
810 name = "Str8";
811 bind = STB_WEAK;
812 value = 8;
813 Elf_Word sym8 = symbols.add_symbol( str_writer, name.c_str(), value, size,
814 bind, type, other, section_index );
815
816 section* rel_sec = writer.sections.add( ".rel.text" );
817 rel_sec->set_type( SHT_REL );
818 rel_sec->set_info( text_sec->get_index() );
819 rel_sec->set_addr_align( 0x4 );
820 rel_sec->set_entry_size( writer.get_default_entry_size( SHT_REL ) );
821 rel_sec->set_link( sym_sec->get_index() );
822
823 relocation_section_accessor rela( writer, rel_sec );
824 // Add relocation entry (adjust address at offset 11)
825 rela.add_entry( 1, sym1, (unsigned char)R_386_RELATIVE );
826 rela.add_entry( 8, sym8, (unsigned char)R_386_RELATIVE );
827 rela.add_entry( 6, sym6, (unsigned char)R_386_RELATIVE );
828 rela.add_entry( 2, sym2, (unsigned char)R_386_RELATIVE );
829 rela.add_entry( 3, sym3, (unsigned char)R_386_RELATIVE );
830 rela.add_entry( 8, sym8, (unsigned char)R_386_RELATIVE );
831 rela.add_entry( 7, sym7, (unsigned char)R_386_RELATIVE );
832 rela.add_entry( 2, sym2, (unsigned char)R_386_RELATIVE );
833 rela.add_entry( 11, sym1, (unsigned char)R_386_RELATIVE );
834 rela.add_entry( 18, sym8, (unsigned char)R_386_RELATIVE );
835 rela.add_entry( 16, sym6, (unsigned char)R_386_RELATIVE );
836 rela.add_entry( 12, sym2, (unsigned char)R_386_RELATIVE );
837 rela.add_entry( 13, sym3, (unsigned char)R_386_RELATIVE );
838 rela.add_entry( 17, sym7, (unsigned char)R_386_RELATIVE );
839 rela.add_entry( 14, sym4, (unsigned char)R_386_RELATIVE );
840 rela.add_entry( 15, sym5, (unsigned char)R_386_RELATIVE );
841
842 std::vector<std::string> before;
843
844 for ( Elf_Word i = 0; i < rela.get_entries_num(); i++ ) {
845 Elf64_Addr offset;
846 Elf_Word symbol;
847 Elf_Word rtype;
848 Elf_Sxword addend;
849
850 rela.get_entry( i, offset, symbol, rtype, addend );
851 symbols.get_symbol( symbol, name, value, size, bind, type,
852 section_index, other );
853 before.push_back( name );
854 }
855
856 symbols.arrange_local_symbols( [&]( Elf_Xword first, Elf_Xword second ) {
857 rela.swap_symbols( first, second );
858 } );
859
860 BOOST_REQUIRE_EQUAL( writer.save( file_name ), true );
861
862 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
863
864 elfio reader;
865 BOOST_REQUIRE_EQUAL( reader.load( file_name ), true );
866
867 auto prelsec = reader.sections[".rel.text"];
868 auto psyms = reader.sections[".symtab"];
869
870 BOOST_REQUIRE_NE( prelsec, nullptr );
871 BOOST_REQUIRE_NE( psyms, nullptr );
872
873 const_relocation_section_accessor rel( reader, prelsec );
874 const_symbol_section_accessor syms( reader, psyms );
875
876 std::vector<std::string> after;
877
878 for ( Elf_Word i = 0; i < rel.get_entries_num(); i++ ) {
879 Elf64_Addr offset;
880 Elf_Word symbol;
881 Elf_Word rtype;
882 Elf_Sxword addend;
883
884 rel.get_entry( i, offset, symbol, rtype, addend );
885 syms.get_symbol( symbol, name, value, size, bind, type, section_index,
886 other );
887 after.push_back( name );
888 }
889
890 BOOST_CHECK_EQUAL_COLLECTIONS( before.begin(), before.end(), after.begin(),
891 after.end() );
892 }
893
BOOST_AUTO_TEST_CASE(detect_mismatched_section_segment_tables)894 BOOST_AUTO_TEST_CASE( detect_mismatched_section_segment_tables )
895 {
896 /* This file is a hacked copy of hello_32
897 * The error introduced is:
898 * Virtual address of segment 3 (0x804948c) conflicts
899 * with address of section .ctors (0x804948e) at offset 0x48e
900 */
901 std::string in = "elf_examples/mismatched_segments.elf";
902 elfio elf;
903 BOOST_REQUIRE_EQUAL( elf.load( in ), true );
904 BOOST_REQUIRE( elf.validate().length() > 0 );
905 }
906