• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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