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