• 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 #ifndef ELFIO_HPP
24 #define ELFIO_HPP
25 
26 #ifdef _MSC_VER
27 #pragma warning( push )
28 #pragma warning( disable : 4996 )
29 #pragma warning( disable : 4355 )
30 #pragma warning( disable : 4244 )
31 #endif
32 
33 #include <string>
34 #include <iostream>
35 #include <fstream>
36 #include <functional>
37 #include <algorithm>
38 #include <vector>
39 #include <deque>
40 #include <iterator>
41 
42 #include <elfio/elf_types.hpp>
43 #include <elfio/elfio_version.hpp>
44 #include <elfio/elfio_utils.hpp>
45 #include <elfio/elfio_header.hpp>
46 #include <elfio/elfio_section.hpp>
47 #include <elfio/elfio_segment.hpp>
48 #include <elfio/elfio_strings.hpp>
49 
50 #define ELFIO_HEADER_ACCESS_GET( TYPE, FNAME ) \
51     TYPE get_##FNAME() const { return header ? ( header->get_##FNAME() ) : 0; }
52 
53 #define ELFIO_HEADER_ACCESS_GET_SET( TYPE, FNAME )     \
54     TYPE get_##FNAME() const                           \
55     {                                                  \
56         return header ? ( header->get_##FNAME() ) : 0; \
57     }                                                  \
58     void set_##FNAME( TYPE val )                       \
59     {                                                  \
60         if ( header ) {                                \
61             header->set_##FNAME( val );                \
62         }                                              \
63     }
64 
65 namespace ELFIO {
66 
67 //------------------------------------------------------------------------------
68 class elfio
69 {
70   public:
71     //------------------------------------------------------------------------------
elfio()72     elfio() : sections( this ), segments( this )
73     {
74         header           = 0;
75         current_file_pos = 0;
76         create( ELFCLASS32, ELFDATA2LSB );
77     }
78 
79     //------------------------------------------------------------------------------
~elfio()80     ~elfio() { clean(); }
81 
82     //------------------------------------------------------------------------------
create(unsigned char file_class,unsigned char encoding)83     void create( unsigned char file_class, unsigned char encoding )
84     {
85         clean();
86         convertor.setup( encoding );
87         header = create_header( file_class, encoding );
88         create_mandatory_sections();
89     }
90 
91     //------------------------------------------------------------------------------
load(const std::string & file_name)92     bool load( const std::string& file_name )
93     {
94         std::ifstream stream;
95         stream.open( file_name.c_str(), std::ios::in | std::ios::binary );
96         if ( !stream ) {
97             return false;
98         }
99 
100         return load( stream );
101     }
102 
103     //------------------------------------------------------------------------------
load(std::istream & stream)104     bool load( std::istream& stream )
105     {
106         clean();
107 
108         unsigned char e_ident[EI_NIDENT];
109         // Read ELF file signature
110         stream.read( reinterpret_cast<char*>( &e_ident ), sizeof( e_ident ) );
111 
112         // Is it ELF file?
113         if ( stream.gcount() != sizeof( e_ident ) ||
114              e_ident[EI_MAG0] != ELFMAG0 || e_ident[EI_MAG1] != ELFMAG1 ||
115              e_ident[EI_MAG2] != ELFMAG2 || e_ident[EI_MAG3] != ELFMAG3 ) {
116             return false;
117         }
118 
119         if ( ( e_ident[EI_CLASS] != ELFCLASS64 ) &&
120              ( e_ident[EI_CLASS] != ELFCLASS32 ) ) {
121             return false;
122         }
123 
124         convertor.setup( e_ident[EI_DATA] );
125         header = create_header( e_ident[EI_CLASS], e_ident[EI_DATA] );
126         if ( 0 == header ) {
127             return false;
128         }
129         if ( !header->load( stream ) ) {
130             return false;
131         }
132 
133         load_sections( stream );
134         bool is_still_good = load_segments( stream );
135         return is_still_good;
136     }
137 
138     //------------------------------------------------------------------------------
save(const std::string & file_name)139     bool save( const std::string& file_name )
140     {
141         std::ofstream stream;
142         stream.open( file_name.c_str(), std::ios::out | std::ios::binary );
143         if ( !stream ) {
144             return false;
145         }
146 
147         return save( stream );
148     }
149 
150     //------------------------------------------------------------------------------
save(std::ostream & stream)151     bool save( std::ostream& stream )
152     {
153         if ( !stream || !header ) {
154             return false;
155         }
156 
157         bool is_still_good = true;
158         // Define layout specific header fields
159         // The position of the segment table is fixed after the header.
160         // The position of the section table is variable and needs to be fixed
161         // before saving.
162         header->set_segments_num( segments.size() );
163         header->set_segments_offset( segments.size() ? header->get_header_size()
164                                                      : 0 );
165         header->set_sections_num( sections.size() );
166         header->set_sections_offset( 0 );
167 
168         // Layout the first section right after the segment table
169         current_file_pos = header->get_header_size() +
170                            header->get_segment_entry_size() *
171                                (Elf_Xword)header->get_segments_num();
172 
173         calc_segment_alignment();
174 
175         is_still_good = layout_segments_and_their_sections();
176         is_still_good = is_still_good && layout_sections_without_segments();
177         is_still_good = is_still_good && layout_section_table();
178 
179         is_still_good = is_still_good && save_header( stream );
180         is_still_good = is_still_good && save_sections( stream );
181         is_still_good = is_still_good && save_segments( stream );
182 
183         return is_still_good;
184     }
185 
186     //------------------------------------------------------------------------------
187     // ELF header access functions
188     ELFIO_HEADER_ACCESS_GET( unsigned char, class );
189     ELFIO_HEADER_ACCESS_GET( unsigned char, elf_version );
190     ELFIO_HEADER_ACCESS_GET( unsigned char, encoding );
191     ELFIO_HEADER_ACCESS_GET( Elf_Word, version );
192     ELFIO_HEADER_ACCESS_GET( Elf_Half, header_size );
193     ELFIO_HEADER_ACCESS_GET( Elf_Half, section_entry_size );
194     ELFIO_HEADER_ACCESS_GET( Elf_Half, segment_entry_size );
195 
196     ELFIO_HEADER_ACCESS_GET_SET( unsigned char, os_abi );
197     ELFIO_HEADER_ACCESS_GET_SET( unsigned char, abi_version );
198     ELFIO_HEADER_ACCESS_GET_SET( Elf_Half, type );
199     ELFIO_HEADER_ACCESS_GET_SET( Elf_Half, machine );
200     ELFIO_HEADER_ACCESS_GET_SET( Elf_Word, flags );
201     ELFIO_HEADER_ACCESS_GET_SET( Elf64_Addr, entry );
202     ELFIO_HEADER_ACCESS_GET_SET( Elf64_Off, sections_offset );
203     ELFIO_HEADER_ACCESS_GET_SET( Elf64_Off, segments_offset );
204     ELFIO_HEADER_ACCESS_GET_SET( Elf_Half, section_name_str_index );
205 
206     //------------------------------------------------------------------------------
get_convertor() const207     const endianess_convertor& get_convertor() const { return convertor; }
208 
209     //------------------------------------------------------------------------------
get_default_entry_size(Elf_Word section_type) const210     Elf_Xword get_default_entry_size( Elf_Word section_type ) const
211     {
212         switch ( section_type ) {
213         case SHT_RELA:
214             if ( header->get_class() == ELFCLASS64 ) {
215                 return sizeof( Elf64_Rela );
216             }
217             else {
218                 return sizeof( Elf32_Rela );
219             }
220         case SHT_REL:
221             if ( header->get_class() == ELFCLASS64 ) {
222                 return sizeof( Elf64_Rel );
223             }
224             else {
225                 return sizeof( Elf32_Rel );
226             }
227         case SHT_SYMTAB:
228             if ( header->get_class() == ELFCLASS64 ) {
229                 return sizeof( Elf64_Sym );
230             }
231             else {
232                 return sizeof( Elf32_Sym );
233             }
234         case SHT_DYNAMIC:
235             if ( header->get_class() == ELFCLASS64 ) {
236                 return sizeof( Elf64_Dyn );
237             }
238             else {
239                 return sizeof( Elf32_Dyn );
240             }
241         default:
242             return 0;
243         }
244     }
245 
246     //------------------------------------------------------------------------------
247     //! returns an empty string if no problems are detected,
248     //! or a string containing an error message if problems are found,
249     //! with one error per line.
validate() const250     std::string validate() const
251     {
252         // clang-format off
253 
254         std::string errors;
255         // Check for overlapping sections in the file
256         // This is explicitly forbidden by ELF specification
257         for ( int i = 0; i < sections.size(); ++i) {
258             for ( int j = i+1; j < sections.size(); ++j ) {
259                 const section* a = sections[i];
260                 const section* b = sections[j];
261                 if (   !(a->get_type() & SHT_NOBITS)
262                     && !(b->get_type() & SHT_NOBITS)
263                     &&  (a->get_size() > 0)
264                     &&  (b->get_size() > 0)
265                     &&  (a->get_offset() > 0)
266                     &&  (b->get_offset() > 0)) {
267                     if (   is_offset_in_section( a->get_offset(), b )
268                         || is_offset_in_section( a->get_offset()+a->get_size()-1, b )
269                         || is_offset_in_section( b->get_offset(), a )
270                         || is_offset_in_section( b->get_offset()+b->get_size()-1, a )) {
271                         errors += "Sections " + a->get_name() + " and " + b->get_name() + " overlap in file\n";
272                     }
273                 }
274             }
275         }
276 
277         // Check for conflicting section / program header tables, where
278         // the same offset has different vaddresses in section table and
279         // program header table.
280         // This doesn't seem to be  explicitly forbidden by ELF specification,
281         // but:
282         // - it doesn't make any sense
283         // - ELFIO relies on this being consistent when writing ELF files,
284         //   since offsets are re-calculated from vaddress
285         for ( int h = 0; h < segments.size(); ++h ) {
286             const segment* seg = segments[h];
287             if ( seg->get_type() == PT_LOAD && seg->get_file_size() > 0 ) {
288                 auto sec = find_prog_section_for_offset( seg->get_offset() );
289                 if ( sec ) {
290                     auto sec_addr = get_virtual_addr( seg->get_offset(), sec );
291                     if ( sec_addr != seg->get_virtual_address() ) {
292                         errors += "Virtual address of segment " + std::to_string( h ) + " (" + to_hex_string( seg->get_virtual_address() ) + ")"
293                                +  " conflicts with address of section " + sec->get_name() + " (" + to_hex_string( sec_addr ) + ")"
294                                +  " at offset " + to_hex_string( seg->get_offset() ) + "\n";
295                     }
296                 }
297             }
298         }
299 
300         // more checks to be added here...
301 
302         return errors;
303         // clang-format on
304     }
305 
306   private:
307     //------------------------------------------------------------------------------
is_offset_in_section(Elf64_Off offset,const section * sec) const308     bool is_offset_in_section( Elf64_Off offset, const section* sec ) const
309     {
310         return ( offset >= sec->get_offset() ) &&
311                ( offset < ( sec->get_offset() + sec->get_size() ) );
312     }
313 
314     //------------------------------------------------------------------------------
get_virtual_addr(Elf64_Off offset,const section * sec) const315     Elf64_Addr get_virtual_addr( Elf64_Off offset, const section* sec ) const
316     {
317         return sec->get_address() + offset - sec->get_offset();
318     }
319 
320     //------------------------------------------------------------------------------
find_prog_section_for_offset(Elf64_Off offset) const321     const section* find_prog_section_for_offset( Elf64_Off offset ) const
322     {
323         for ( int i = 0; i < sections.size(); ++i ) {
324             const section* sec = sections[i];
325             if ( sec->get_type() == SHT_PROGBITS )
326                 if ( is_offset_in_section( offset, sec ) )
327                     return sec;
328         }
329         return NULL;
330     }
331 
332     //------------------------------------------------------------------------------
clean()333     void clean()
334     {
335         delete header;
336         header = 0;
337 
338         std::vector<section*>::const_iterator it;
339         for ( it = sections_.begin(); it != sections_.end(); ++it ) {
340             delete *it;
341         }
342         sections_.clear();
343 
344         std::vector<segment*>::const_iterator it1;
345         for ( it1 = segments_.begin(); it1 != segments_.end(); ++it1 ) {
346             delete *it1;
347         }
348         segments_.clear();
349     }
350 
351     //------------------------------------------------------------------------------
create_header(unsigned char file_class,unsigned char encoding)352     elf_header* create_header( unsigned char file_class,
353                                unsigned char encoding )
354     {
355         elf_header* new_header = 0;
356 
357         if ( file_class == ELFCLASS64 ) {
358             new_header =
359                 new elf_header_impl<Elf64_Ehdr>( &convertor, encoding );
360         }
361         else if ( file_class == ELFCLASS32 ) {
362             new_header =
363                 new elf_header_impl<Elf32_Ehdr>( &convertor, encoding );
364         }
365         else {
366             return 0;
367         }
368 
369         return new_header;
370     }
371 
372     //------------------------------------------------------------------------------
create_section()373     section* create_section()
374     {
375         section*      new_section;
376         unsigned char file_class = get_class();
377 
378         if ( file_class == ELFCLASS64 ) {
379             new_section = new section_impl<Elf64_Shdr>( &convertor );
380         }
381         else if ( file_class == ELFCLASS32 ) {
382             new_section = new section_impl<Elf32_Shdr>( &convertor );
383         }
384         else {
385             return 0;
386         }
387 
388         new_section->set_index( (Elf_Half)sections_.size() );
389         sections_.push_back( new_section );
390 
391         return new_section;
392     }
393 
394     //------------------------------------------------------------------------------
create_segment()395     segment* create_segment()
396     {
397         segment*      new_segment;
398         unsigned char file_class = header->get_class();
399 
400         if ( file_class == ELFCLASS64 ) {
401             new_segment = new segment_impl<Elf64_Phdr>( &convertor );
402         }
403         else if ( file_class == ELFCLASS32 ) {
404             new_segment = new segment_impl<Elf32_Phdr>( &convertor );
405         }
406         else {
407             return 0;
408         }
409 
410         new_segment->set_index( (Elf_Half)segments_.size() );
411         segments_.push_back( new_segment );
412 
413         return new_segment;
414     }
415 
416     //------------------------------------------------------------------------------
create_mandatory_sections()417     void create_mandatory_sections()
418     {
419         // Create null section without calling to 'add_section' as no string
420         // section containing section names exists yet
421         section* sec0 = create_section();
422         sec0->set_index( 0 );
423         sec0->set_name( "" );
424         sec0->set_name_string_offset( 0 );
425 
426         set_section_name_str_index( 1 );
427         section* shstrtab = sections.add( ".shstrtab" );
428         shstrtab->set_type( SHT_STRTAB );
429         shstrtab->set_addr_align( 1 );
430     }
431 
432     //------------------------------------------------------------------------------
load_sections(std::istream & stream)433     Elf_Half load_sections( std::istream& stream )
434     {
435         Elf_Half  entry_size = header->get_section_entry_size();
436         Elf_Half  num        = header->get_sections_num();
437         Elf64_Off offset     = header->get_sections_offset();
438 
439         for ( Elf_Half i = 0; i < num; ++i ) {
440             section* sec = create_section();
441             sec->load( stream, (std::streamoff)offset +
442                                    (std::streampos)i * entry_size );
443             sec->set_index( i );
444             // To mark that the section is not permitted to reassign address
445             // during layout calculation
446             sec->set_address( sec->get_address() );
447         }
448 
449         Elf_Half shstrndx = get_section_name_str_index();
450 
451         if ( SHN_UNDEF != shstrndx ) {
452             string_section_accessor str_reader( sections[shstrndx] );
453             for ( Elf_Half i = 0; i < num; ++i ) {
454                 Elf_Word section_offset = sections[i]->get_name_string_offset();
455                 const char* p = str_reader.get_string( section_offset );
456                 if ( p != 0 ) {
457                     sections[i]->set_name( p );
458                 }
459             }
460         }
461 
462         return num;
463     }
464 
465     //------------------------------------------------------------------------------
466     //! Checks whether the addresses of the section entirely fall within the given segment.
467     //! It doesn't matter if the addresses are memory addresses, or file offsets,
468     //!  they just need to be in the same address space
is_sect_in_seg(Elf64_Off sect_begin,Elf_Xword sect_size,Elf64_Off seg_begin,Elf64_Off seg_end)469     bool is_sect_in_seg( Elf64_Off sect_begin,
470                          Elf_Xword sect_size,
471                          Elf64_Off seg_begin,
472                          Elf64_Off seg_end )
473     {
474         return ( seg_begin <= sect_begin ) &&
475                ( sect_begin + sect_size <= seg_end ) &&
476                ( sect_begin <
477                  seg_end ); // this is important criteria when sect_size == 0
478         // Example:  seg_begin=10, seg_end=12 (-> covering the bytes 10 and 11)
479         //           sect_begin=12, sect_size=0  -> shall return false!
480     }
481 
482     //------------------------------------------------------------------------------
load_segments(std::istream & stream)483     bool load_segments( std::istream& stream )
484     {
485         Elf_Half  entry_size = header->get_segment_entry_size();
486         Elf_Half  num        = header->get_segments_num();
487         Elf64_Off offset     = header->get_segments_offset();
488 
489         for ( Elf_Half i = 0; i < num; ++i ) {
490             segment*      seg;
491             unsigned char file_class = header->get_class();
492 
493             if ( file_class == ELFCLASS64 ) {
494                 seg = new segment_impl<Elf64_Phdr>( &convertor );
495             }
496             else if ( file_class == ELFCLASS32 ) {
497                 seg = new segment_impl<Elf32_Phdr>( &convertor );
498             }
499             else {
500                 return false;
501             }
502 
503             seg->load( stream, (std::streamoff)offset +
504                                    (std::streampos)i * entry_size );
505             seg->set_index( i );
506 
507             // Add sections to the segments (similar to readelfs algorithm)
508             Elf64_Off segBaseOffset = seg->get_offset();
509             Elf64_Off segEndOffset  = segBaseOffset + seg->get_file_size();
510             Elf64_Off segVBaseAddr  = seg->get_virtual_address();
511             Elf64_Off segVEndAddr   = segVBaseAddr + seg->get_memory_size();
512             for ( Elf_Half j = 0; j < sections.size(); ++j ) {
513                 const section* psec = sections[j];
514 
515                 // SHF_ALLOC sections are matched based on the virtual address
516                 // otherwise the file offset is matched
517                 if ( ( psec->get_flags() & SHF_ALLOC )
518                          ? is_sect_in_seg( psec->get_address(),
519                                            psec->get_size(), segVBaseAddr,
520                                            segVEndAddr )
521                          : is_sect_in_seg( psec->get_offset(), psec->get_size(),
522                                            segBaseOffset, segEndOffset ) ) {
523                     // Alignment of segment shall not be updated, to preserve original value
524                     // It will be re-calculated on saving.
525                     seg->add_section_index( psec->get_index(), 0 );
526                 }
527             }
528 
529             // Add section into the segments' container
530             segments_.push_back( seg );
531         }
532 
533         return true;
534     }
535 
536     //------------------------------------------------------------------------------
save_header(std::ostream & stream)537     bool save_header( std::ostream& stream ) { return header->save( stream ); }
538 
539     //------------------------------------------------------------------------------
save_sections(std::ostream & stream)540     bool save_sections( std::ostream& stream )
541     {
542         for ( unsigned int i = 0; i < sections_.size(); ++i ) {
543             section* sec = sections_.at( i );
544 
545             std::streampos headerPosition =
546                 (std::streamoff)header->get_sections_offset() +
547                 (std::streampos)header->get_section_entry_size() *
548                     sec->get_index();
549 
550             sec->save( stream, headerPosition, sec->get_offset() );
551         }
552         return true;
553     }
554 
555     //------------------------------------------------------------------------------
save_segments(std::ostream & stream)556     bool save_segments( std::ostream& stream )
557     {
558         for ( unsigned int i = 0; i < segments_.size(); ++i ) {
559             segment* seg = segments_.at( i );
560 
561             std::streampos headerPosition =
562                 header->get_segments_offset() +
563                 (std::streampos)header->get_segment_entry_size() *
564                     seg->get_index();
565 
566             seg->save( stream, headerPosition, seg->get_offset() );
567         }
568         return true;
569     }
570 
571     //------------------------------------------------------------------------------
is_section_without_segment(unsigned int section_index)572     bool is_section_without_segment( unsigned int section_index )
573     {
574         bool found = false;
575 
576         for ( unsigned int j = 0; !found && ( j < segments.size() ); ++j ) {
577             for ( unsigned int k = 0;
578                   !found && ( k < segments[j]->get_sections_num() ); ++k ) {
579                 found = segments[j]->get_section_index_at( k ) == section_index;
580             }
581         }
582 
583         return !found;
584     }
585 
586     //------------------------------------------------------------------------------
is_subsequence_of(segment * seg1,segment * seg2)587     bool is_subsequence_of( segment* seg1, segment* seg2 )
588     {
589         // Return 'true' if sections of seg1 are a subset of sections in seg2
590         const std::vector<Elf_Half>& sections1 = seg1->get_sections();
591         const std::vector<Elf_Half>& sections2 = seg2->get_sections();
592 
593         bool found = false;
594         if ( sections1.size() < sections2.size() ) {
595             found = std::includes( sections2.begin(), sections2.end(),
596                                    sections1.begin(), sections1.end() );
597         }
598 
599         return found;
600     }
601 
602     //------------------------------------------------------------------------------
get_ordered_segments()603     std::vector<segment*> get_ordered_segments()
604     {
605         std::vector<segment*> res;
606         std::deque<segment*>  worklist;
607 
608         res.reserve( segments.size() );
609         std::copy( segments_.begin(), segments_.end(),
610                    std::back_inserter( worklist ) );
611 
612         // Bring the segments which start at address 0 to the front
613         size_t nextSlot = 0;
614         for ( size_t i = 0; i < worklist.size(); ++i ) {
615             if ( i != nextSlot && worklist[i]->is_offset_initialized() &&
616                  worklist[i]->get_offset() == 0 ) {
617                 if ( worklist[nextSlot]->get_offset() == 0 ) {
618                     ++nextSlot;
619                 }
620                 std::swap( worklist[i], worklist[nextSlot] );
621                 ++nextSlot;
622             }
623         }
624 
625         while ( !worklist.empty() ) {
626             segment* seg = worklist.front();
627             worklist.pop_front();
628 
629             size_t i = 0;
630             for ( ; i < worklist.size(); ++i ) {
631                 if ( is_subsequence_of( seg, worklist[i] ) ) {
632                     break;
633                 }
634             }
635 
636             if ( i < worklist.size() )
637                 worklist.push_back( seg );
638             else
639                 res.push_back( seg );
640         }
641 
642         return res;
643     }
644 
645     //------------------------------------------------------------------------------
layout_sections_without_segments()646     bool layout_sections_without_segments()
647     {
648         for ( unsigned int i = 0; i < sections_.size(); ++i ) {
649             if ( is_section_without_segment( i ) ) {
650                 section* sec = sections_[i];
651 
652                 Elf_Xword section_align = sec->get_addr_align();
653                 if ( section_align > 1 &&
654                      current_file_pos % section_align != 0 ) {
655                     current_file_pos +=
656                         section_align - current_file_pos % section_align;
657                 }
658 
659                 if ( 0 != sec->get_index() )
660                     sec->set_offset( current_file_pos );
661 
662                 if ( SHT_NOBITS != sec->get_type() &&
663                      SHT_NULL != sec->get_type() ) {
664                     current_file_pos += sec->get_size();
665                 }
666             }
667         }
668 
669         return true;
670     }
671 
672     //------------------------------------------------------------------------------
calc_segment_alignment()673     void calc_segment_alignment()
674     {
675         for ( std::vector<segment*>::iterator s = segments_.begin();
676               s != segments_.end(); ++s ) {
677             segment* seg = *s;
678             for ( int i = 0; i < seg->get_sections_num(); ++i ) {
679                 section* sect = sections_[seg->get_section_index_at( i )];
680                 if ( sect->get_addr_align() > seg->get_align() ) {
681                     seg->set_align( sect->get_addr_align() );
682                 }
683             }
684         }
685     }
686 
687     //------------------------------------------------------------------------------
layout_segments_and_their_sections()688     bool layout_segments_and_their_sections()
689     {
690         std::vector<segment*> worklist;
691         std::vector<bool>     section_generated( sections.size(), false );
692 
693         // Get segments in a order in where segments which contain a
694         // sub sequence of other segments are located at the end
695         worklist = get_ordered_segments();
696 
697         for ( unsigned int i = 0; i < worklist.size(); ++i ) {
698             Elf_Xword segment_memory   = 0;
699             Elf_Xword segment_filesize = 0;
700             Elf_Xword seg_start_pos    = current_file_pos;
701             segment*  seg              = worklist[i];
702 
703             // Special case: PHDR segment
704             // This segment contains the program headers but no sections
705             if ( seg->get_type() == PT_PHDR && seg->get_sections_num() == 0 ) {
706                 seg_start_pos  = header->get_segments_offset();
707                 segment_memory = segment_filesize =
708                     header->get_segment_entry_size() *
709                     (Elf_Xword)header->get_segments_num();
710             }
711             // Special case:
712             else if ( seg->is_offset_initialized() && seg->get_offset() == 0 ) {
713                 seg_start_pos = 0;
714                 if ( seg->get_sections_num() ) {
715                     segment_memory = segment_filesize = current_file_pos;
716                 }
717             }
718             // New segments with not generated sections
719             // have to be aligned
720             else if ( seg->get_sections_num() &&
721                       !section_generated[seg->get_section_index_at( 0 )] ) {
722                 Elf_Xword align = seg->get_align() > 0 ? seg->get_align() : 1;
723                 Elf64_Off cur_page_alignment = current_file_pos % align;
724                 Elf64_Off req_page_alignment =
725                     seg->get_virtual_address() % align;
726                 Elf64_Off error = req_page_alignment - cur_page_alignment;
727 
728                 current_file_pos += ( seg->get_align() + error ) % align;
729                 seg_start_pos = current_file_pos;
730             }
731             else if ( seg->get_sections_num() ) {
732                 seg_start_pos =
733                     sections[seg->get_section_index_at( 0 )]->get_offset();
734             }
735 
736             // Write segment's data
737             for ( unsigned int j = 0; j < seg->get_sections_num(); ++j ) {
738                 Elf_Half index = seg->get_section_index_at( j );
739 
740                 section* sec = sections[index];
741 
742                 // The NULL section is always generated
743                 if ( SHT_NULL == sec->get_type() ) {
744                     section_generated[index] = true;
745                     continue;
746                 }
747 
748                 Elf_Xword secAlign = 0;
749                 // Fix up the alignment
750                 if ( !section_generated[index] &&
751                      sec->is_address_initialized() &&
752                      SHT_NOBITS != sec->get_type() &&
753                      SHT_NULL != sec->get_type() && 0 != sec->get_size() ) {
754                     // Align the sections based on the virtual addresses
755                     // when possible (this is what matters for execution)
756                     Elf64_Off req_offset =
757                         sec->get_address() - seg->get_virtual_address();
758                     Elf64_Off cur_offset = current_file_pos - seg_start_pos;
759                     if ( req_offset < cur_offset ) {
760                         // something has gone awfully wrong, abort!
761                         // secAlign would turn out negative, seeking backwards and overwriting previous data
762                         return false;
763                     }
764                     secAlign = req_offset - cur_offset;
765                 }
766                 else if ( !section_generated[index] &&
767                           !sec->is_address_initialized() ) {
768                     // If no address has been specified then only the section
769                     // alignment constraint has to be matched
770                     Elf_Xword align = sec->get_addr_align();
771                     if ( align == 0 ) {
772                         align = 1;
773                     }
774                     Elf64_Off error = current_file_pos % align;
775                     secAlign        = ( align - error ) % align;
776                 }
777                 else if ( section_generated[index] ) {
778                     // Alignment for already generated sections
779                     secAlign =
780                         sec->get_offset() - seg_start_pos - segment_filesize;
781                 }
782 
783                 // Determine the segment file and memory sizes
784                 // Special case .tbss section (NOBITS) in non TLS segment
785                 if ( ( sec->get_flags() & SHF_ALLOC ) &&
786                      !( ( sec->get_flags() & SHF_TLS ) &&
787                         ( seg->get_type() != PT_TLS ) &&
788                         ( SHT_NOBITS == sec->get_type() ) ) )
789                     segment_memory += sec->get_size() + secAlign;
790 
791                 if ( SHT_NOBITS != sec->get_type() )
792                     segment_filesize += sec->get_size() + secAlign;
793 
794                 // Nothing to be done when generating nested segments
795                 if ( section_generated[index] ) {
796                     continue;
797                 }
798 
799                 current_file_pos += secAlign;
800 
801                 // Set the section addresses when missing
802                 if ( !sec->is_address_initialized() )
803                     sec->set_address( seg->get_virtual_address() +
804                                       current_file_pos - seg_start_pos );
805 
806                 if ( 0 != sec->get_index() )
807                     sec->set_offset( current_file_pos );
808 
809                 if ( SHT_NOBITS != sec->get_type() )
810                     current_file_pos += sec->get_size();
811 
812                 section_generated[index] = true;
813             }
814 
815             seg->set_file_size( segment_filesize );
816 
817             // If we already have a memory size from loading an elf file (value > 0),
818             // it must not shrink!
819             // Memory size may be bigger than file size and it is the loader's job to do something
820             // with the surplus bytes in memory, like initializing them with a defined value.
821             if ( seg->get_memory_size() < segment_memory ) {
822                 seg->set_memory_size( segment_memory );
823             }
824 
825             seg->set_offset( seg_start_pos );
826         }
827 
828         return true;
829     }
830 
831     //------------------------------------------------------------------------------
layout_section_table()832     bool layout_section_table()
833     {
834         // Simply place the section table at the end for now
835         Elf64_Off alignmentError = current_file_pos % 4;
836         current_file_pos += ( 4 - alignmentError ) % 4;
837         header->set_sections_offset( current_file_pos );
838         return true;
839     }
840 
841     //------------------------------------------------------------------------------
842   public:
843     friend class Sections;
844     class Sections
845     {
846       public:
847         //------------------------------------------------------------------------------
Sections(elfio * parent)848         Sections( elfio* parent ) : parent( parent ) {}
849 
850         //------------------------------------------------------------------------------
size() const851         Elf_Half size() const { return (Elf_Half)parent->sections_.size(); }
852 
853         //------------------------------------------------------------------------------
operator [](unsigned int index) const854         section* operator[]( unsigned int index ) const
855         {
856             section* sec = 0;
857 
858             if ( index < parent->sections_.size() ) {
859                 sec = parent->sections_[index];
860             }
861 
862             return sec;
863         }
864 
865         //------------------------------------------------------------------------------
operator [](const std::string & name) const866         section* operator[]( const std::string& name ) const
867         {
868             section* sec = 0;
869 
870             std::vector<section*>::const_iterator it;
871             for ( it = parent->sections_.begin(); it != parent->sections_.end();
872                   ++it ) {
873                 if ( ( *it )->get_name() == name ) {
874                     sec = *it;
875                     break;
876                 }
877             }
878 
879             return sec;
880         }
881 
882         //------------------------------------------------------------------------------
add(const std::string & name)883         section* add( const std::string& name )
884         {
885             section* new_section = parent->create_section();
886             new_section->set_name( name );
887 
888             Elf_Half str_index = parent->get_section_name_str_index();
889             section* string_table( parent->sections_[str_index] );
890             string_section_accessor str_writer( string_table );
891             Elf_Word                pos = str_writer.add_string( name );
892             new_section->set_name_string_offset( pos );
893 
894             return new_section;
895         }
896 
897         //------------------------------------------------------------------------------
begin()898         std::vector<section*>::iterator begin()
899         {
900             return parent->sections_.begin();
901         }
902 
903         //------------------------------------------------------------------------------
end()904         std::vector<section*>::iterator end()
905         {
906             return parent->sections_.end();
907         }
908 
909         //------------------------------------------------------------------------------
begin() const910         std::vector<section*>::const_iterator begin() const
911         {
912             return parent->sections_.cbegin();
913         }
914 
915         //------------------------------------------------------------------------------
end() const916         std::vector<section*>::const_iterator end() const
917         {
918             return parent->sections_.cend();
919         }
920 
921         //------------------------------------------------------------------------------
922       private:
923         elfio* parent;
924     } sections;
925 
926     //------------------------------------------------------------------------------
927   public:
928     friend class Segments;
929     class Segments
930     {
931       public:
932         //------------------------------------------------------------------------------
Segments(elfio * parent)933         Segments( elfio* parent ) : parent( parent ) {}
934 
935         //------------------------------------------------------------------------------
size() const936         Elf_Half size() const { return (Elf_Half)parent->segments_.size(); }
937 
938         //------------------------------------------------------------------------------
operator [](unsigned int index) const939         segment* operator[]( unsigned int index ) const
940         {
941             return parent->segments_[index];
942         }
943 
944         //------------------------------------------------------------------------------
add()945         segment* add() { return parent->create_segment(); }
946 
947         //------------------------------------------------------------------------------
begin()948         std::vector<segment*>::iterator begin()
949         {
950             return parent->segments_.begin();
951         }
952 
953         //------------------------------------------------------------------------------
end()954         std::vector<segment*>::iterator end()
955         {
956             return parent->segments_.end();
957         }
958 
959         //------------------------------------------------------------------------------
begin() const960         std::vector<segment*>::const_iterator begin() const
961         {
962             return parent->segments_.cbegin();
963         }
964 
965         //------------------------------------------------------------------------------
end() const966         std::vector<segment*>::const_iterator end() const
967         {
968             return parent->segments_.cend();
969         }
970 
971         //------------------------------------------------------------------------------
972       private:
973         elfio* parent;
974     } segments;
975 
976     //------------------------------------------------------------------------------
977   private:
978     elf_header*           header;
979     std::vector<section*> sections_;
980     std::vector<segment*> segments_;
981     endianess_convertor   convertor;
982 
983     Elf_Xword current_file_pos;
984 };
985 
986 } // namespace ELFIO
987 
988 #include <elfio/elfio_symbols.hpp>
989 #include <elfio/elfio_note.hpp>
990 #include <elfio/elfio_relocation.hpp>
991 #include <elfio/elfio_dynamic.hpp>
992 #include <elfio/elfio_array.hpp>
993 #include <elfio/elfio_modinfo.hpp>
994 
995 #ifdef _MSC_VER
996 #pragma warning( pop )
997 #endif
998 
999 #endif // ELFIO_HPP
1000