source: rtems-tools/linkers/rld-rap.cpp @ 544de91

4.104.115
Last change on this file since 544de91 was 800d4fd, checked in by Chris Johns <chrisj@…>, on 12/24/12 at 06:18:23

Add the symsect offset to the section reloc.

  • Property mode set to 100644
File size: 37.5 KB
Line 
1/*
2 * Copyright (c) 2012, Chris Johns <chrisj@rtems.org>
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16/**
17 * @file
18 *
19 * @ingroup rtems_ld
20 *
21 * @brief RTEMS Linker.
22 *
23 */
24
25#if HAVE_CONFIG_H
26#include "config.h"
27#endif
28
29#include <algorithm>
30#include <list>
31#include <iomanip>
32
33#include <rld.h>
34#include <rld-compression.h>
35#include <rld-rap.h>
36
37namespace rld
38{
39  namespace rap
40  {
41    /**
42     * The names of the RAP sections.
43     */
44    static const char* section_names[rap_secs] =
45    {
46      ".text",
47      ".const",
48      ".ctor",
49      ".dtor",
50      ".data",
51      ".bss"
52    };
53
54    /**
55     * RAP relocation record. This one does not have const fields.
56     */
57    struct relocation
58    {
59      uint32_t    offset;   //< The offset in the section to apply the fixup.
60      uint32_t    info;     //< The ELF info record.
61      uint32_t    addend;   //< The ELF constant addend.
62      std::string symname;  //< The symbol name if there is one.
63      uint32_t    symtype;  //< The type of symbol.
64      int         symsect;  //< The symbol's RAP section.
65      uint32_t    symvalue; //< The symbol's default value.
66
67      /**
68       * Construct the relocation using the file relocation, the offset of the
69       * section in the target RAP section and the RAP section of the symbol.
70       */
71      relocation (const files::relocation& reloc, const uint32_t offset);
72    };
73
74    /**
75     * Relocation records.
76     */
77    typedef std::list < relocation > relocations;
78
79    /**
80     * Map of object file section offsets keyed by the object file section
81     * index. This is used when adding the external symbols so the symbol's
82     * value can be adjusted by the offset of the section in the RAP section.
83     */
84    typedef std::map < int, uint32_t > osections;
85
86    /**
87     * The RAP section data.
88     */
89    struct section
90    {
91      std::string name;   //< The name of the section.
92      uint32_t    size;   //< The size of the section.
93      uint32_t    offset; //< The offset of the section.
94      uint32_t    align;  //< The alignment of the section.
95      bool        rela;   //< The relocation record has an addend field.
96      relocations relocs; //< The relocations for this section.
97      osections   osecs;  //< The object section index.
98
99      /**
100       * Operator to add up section data.
101       */
102      section& operator += (const section& sec);
103
104      /**
105       * Default constructor.
106       */
107      section ();
108
109      /**
110       * Clear the section.
111       */
112      void clear ();
113
114      /**
115       * Update based on the section in the object file.
116       */
117      void update (const files::sections& secs);
118
119      /**
120       * Set the offset of this section based on the previous section.
121       */
122      void set_offset (const section& sec);
123
124      /**
125       * Set the alignment.
126       */
127      void set_alignment (const section& sec);
128    };
129
130    /**
131     * A symbol. This matches the symbol structure 'rtems_rtl_obj_sym_t' in the
132     * target code.
133     */
134    struct external
135    {
136      /**
137       * Size of an external in the RAP file.
138       */
139      static const uint32_t rap_size = sizeof (uint32_t) * 3;
140
141      const uint32_t name;  //< The string table's name index.
142      const sections sec;   //< The section the symbols belongs to.
143      const uint32_t value; //< The offset from the section base.
144      const uint32_t data;  //< The ELF st.info field.
145
146      /**
147       * The constructor.
148       */
149      external (const uint32_t name,
150                const sections sec,
151                const uint32_t value,
152                const uint32_t data);
153
154      /**
155       * Copy constructor.
156       */
157      external (const external& orig);
158
159    };
160
161    /**
162     * A container of externals.
163     */
164    typedef std::list < external > externals;
165
166    /**
167     * The specific data for each object we need to collect to create the RAP
168     * format file.
169     */
170    struct object
171    {
172
173      files::object&  obj;            //< The object file.
174      files::sections text;           //< All executable code.
175      files::sections const_;         //< All read only data.
176      files::sections ctor;           //< The static constructor table.
177      files::sections dtor;           //< The static destructor table.
178      files::sections data;           //< All initialised read/write data.
179      files::sections bss;            //< All uninitialised read/write data
180      files::sections symtab;         //< All exported symbols.
181      files::sections strtab;         //< All exported strings.
182      section         secs[rap_secs]; //< The sections of interest.
183
184      /**
185       * The constructor. Need to have an object file to create.
186       */
187      object (files::object& obj);
188
189      /**
190       * The copy constructor.
191       */
192      object (const object& orig);
193
194      /**
195       * Find the section type that matches the section index.
196       */
197      sections find (const uint32_t index) const;
198
199      /**
200       * The total number of relocations in the object file.
201       */
202      uint32_t get_relocations () const;
203
204      /**
205       * The total number of relocations for a specific RAP section in the
206       * object file.
207       */
208      uint32_t get_relocations (int sec) const;
209
210      /**
211       * Output the object file details..
212       */
213      void output ();
214
215    private:
216      /**
217       * No default constructor allowed.
218       */
219      object ();
220    };
221
222    /**
223     * A container of objects.
224     */
225    typedef std::list < object > objects;
226
227    /**
228     * The RAP image.
229     */
230    class image
231    {
232    public:
233      /**
234       * Construct the image.
235       */
236      image ();
237
238      /**
239       * Load the layout data from the object files.
240       *
241       * @param app_objects The object files in the application.
242       * @param init The initialisation entry point label.
243       * @param fini The finish entry point label.
244       */
245      void layout (const files::object_list& app_objects,
246                   const std::string&        init,
247                   const std::string&        fini);
248
249      /**
250       * Collection the symbols from the object file.
251       *
252       * @param obj The object file to collection the symbol from.
253       */
254      void collect_symbols (object& obj);
255
256      /**
257       * Write the compressed output file.
258       *
259       * @param comp The compressor.
260       */
261      void write (compress::compressor& comp);
262
263      /**
264       * Write the sections to the compressed output file. The file sections
265       * are used to ensure the alignment. The offset is used to ensure the
266       * alignment of the first section of the object when it is written.
267       *
268       * @param comp The compressor.
269       * @param obj The object file the sections are part of.
270       * @param secs The container of file sections to write.
271       * @param offset The current offset in the RAP section.
272       */
273      void write (compress::compressor&  comp,
274                  files::object&         obj,
275                  const files::sections& secs,
276                  uint32_t&              offset);
277
278      /**
279       * Write the external symbols.
280       */
281      void write_externals (compress::compressor& comp);
282
283      /**
284       * Write the relocation records for all the object files.
285       */
286      void write_relocations (compress::compressor& comp);
287
288      /**
289       * The total number of relocations for a specific RAP section in the
290       * image.
291       */
292      uint32_t get_relocations (int sec) const;
293
294      /**
295       * Clear the image values.
296       */
297      void clear ();
298
299      /**
300       * Update the section values.
301       *
302       * @param index The RAP section index to update.
303       * @param sec The object's RAP section.
304       */
305      void update_section (int index, const section& sec);
306
307    private:
308
309      objects     objs;                //< The RAP objects
310      uint32_t    sec_size[rap_secs];  //< The sections of interest.
311      uint32_t    sec_align[rap_secs]; //< The sections of interest.
312      bool        sec_rela[rap_secs];  //< The sections of interest.
313      externals   externs;             //< The symbols in the image
314      uint32_t    symtab_size;         //< The size of the symbols.
315      std::string strtab;              //< The strings table.
316      uint32_t    relocs_size;         //< The relocations size.
317      uint32_t    init_off;            //< The strtab offset to the init label.
318      uint32_t    fini_off;            //< The strtab offset to the fini label.
319    };
320
321    const char*
322    section_name (int sec)
323    {
324      if (sec < rap_secs)
325        return section_names[sec];
326      throw rld::error ("Invalid section '" + rld::to_string (sec) + "'",
327                        "rap::section-name");
328    }
329
330    /**
331     * Update the offset taking into account the alignment.
332     *
333     * @param offset The current offset.
334     * @param size The size to move the offset by.
335     * @param alignment The alignment of the offset.
336     * @return uint32_t The new aligned offset.
337     */
338    uint32_t align_offset (uint32_t offset, uint32_t size, uint32_t alignment)
339    {
340      offset += size;
341
342      if (alignment > 1)
343      {
344        uint32_t mask = alignment - 1;
345        if (offset & mask)
346        {
347          offset &= ~mask;
348          offset += alignment;
349        }
350      }
351
352      return offset;
353    }
354
355    /**
356     * Output helper function to report the sections in an object file.
357     * This is useful when seeing the flags in the sections.
358     *
359     * @param sec The RAP section to output.
360     * @param secs The container of sections in the group from the object file.
361     */
362    void
363    output (section& sec, const files::sections& osecs)
364    {
365      if (sec.size)
366      {
367        std::cout << ' ' << sec.name
368                  << ": size: " << sec.size
369                  << " offset: " << sec.offset
370                  << std::endl;
371
372        for (files::sections::const_iterator osi = osecs.begin ();
373             osi != osecs.end ();
374             ++osi)
375        {
376          files::section osec = *osi;
377
378          if (osec.size)
379          {
380            #define SF(f, i, c) if (osec.flags & (f)) flags[i] = c
381
382            std::string flags ("--------------");
383
384            SF (SHF_WRITE,            0, 'W');
385            SF (SHF_ALLOC,            1, 'A');
386            SF (SHF_EXECINSTR,        2, 'E');
387            SF (SHF_MERGE,            3, 'M');
388            SF (SHF_STRINGS,          4, 'S');
389            SF (SHF_INFO_LINK,        5, 'I');
390            SF (SHF_LINK_ORDER,       6, 'L');
391            SF (SHF_OS_NONCONFORMING, 7, 'N');
392            SF (SHF_GROUP,            8, 'G');
393            SF (SHF_TLS,              9, 'T');
394            SF (SHF_AMD64_LARGE,     10, 'a');
395            SF (SHF_ENTRYSECT,       11, 'e');
396            SF (SHF_COMDEF,          12, 'c');
397            SF (SHF_ORDERED,         13, 'O');
398
399            std::cout << "  " << std::left
400                      << std::setw (15) << osec.name
401                      << " " << flags
402                      << " size: " << std::setw (5) << osec.size
403                      << " align: " << std::setw (3) << osec.alignment
404                      << " relocs: " << std::setw (4) << osec.relocs.size ()
405                      << " offset: " << std::setw (5) << sec.osecs[osec.index]
406                      << std::hex
407                      << " image: 0x" << sec.offset + sec.osecs[osec.index]
408                      << std::dec << std::right << std::endl;
409          }
410        }
411      }
412    }
413
414    relocation::relocation (const files::relocation& reloc,
415                            const uint32_t           offset)
416      : offset (reloc.offset + offset),
417        info (reloc.info),
418        addend (reloc.addend),
419        symname (reloc.symname),
420        symtype (reloc.symtype),
421        symsect (reloc.symsect),
422        symvalue (reloc.symvalue)
423    {
424    }
425
426    section::section ()
427      : size (0),
428        offset (0),
429        align (0),
430        rela (false)
431    {
432    }
433
434    void
435    section::clear ()
436    {
437      size = 0;
438      offset = 0;
439      align = 0;
440      rela = false;
441    }
442
443    section&
444    section::operator += (const section& sec)
445    {
446      if (sec.size)
447      {
448        if (align < sec.align)
449          align = sec.align;
450
451        if (size && (align == 0))
452          throw rld::error ("Invalid alignment '" + name + "'",
453                            "rap::section");
454
455        size += sec.size;
456      }
457
458      rela = sec.rela;
459
460      return *this;
461    }
462
463    void
464    section::set_alignment (const section& sec)
465    {
466      if (align < sec.align)
467        align = sec.align;
468    }
469
470    void
471    section::set_offset (const section& sec)
472    {
473      offset = align_offset (sec.offset, sec.size, align);
474    }
475
476    void
477    section::update (const files::sections& secs)
478    {
479      if (!secs.empty ())
480      {
481        align = (*(secs.begin ())).alignment;
482        size = files::sum_sizes (secs);
483      }
484    }
485
486    /**
487     * Helper for for_each to merge the related object sections into the RAP
488     * section.
489     */
490    class section_merge:
491      public std::unary_function < const files::section, void >
492    {
493    public:
494
495      section_merge (object& obj, section& sec);
496
497      void operator () (const files::section& fsec);
498
499    private:
500
501      object&  obj;
502      section& sec;
503    };
504
505    section_merge::section_merge (object& obj, section& sec)
506      : obj (obj),
507        sec (sec)
508    {
509      sec.align = 0;
510      sec.offset = 0;
511      sec.size = 0;
512      sec.rela = false;
513    }
514
515    void
516    section_merge::operator () (const files::section& fsec)
517    {
518      /*
519       * The RAP section alignment is the largest of all sections that are
520       * being merged. This object file section however can aligned at its
521       * specific alignment. You see this with .const sections which can be say
522       * 4 .eh_frame and 1 for strings.
523       */
524      if (sec.align < fsec.alignment)
525        sec.align = fsec.alignment;
526
527      /*
528       * Align the size up to the next alignment boundary and use that as the
529       * offset for this object file section.
530       */
531      uint32_t offset = align_offset (sec.size, 0, fsec.alignment);
532
533      if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
534        std::cout << "rap:section-merge: " << fsec.name
535                  << " relocs=" << fsec.relocs.size ()
536                  << " offset=" << offset
537                  << " fsec.size=" << fsec.size
538                  << " fsec.alignment=" << fsec.alignment
539                  << " " << obj.obj.name ().full ()  << std::endl;
540
541      /*
542       * Add the object file's section offset to the map. This is needed
543       * to adjust the external symbol offsets.
544       */
545      sec.osecs[fsec.index] = offset;
546
547      uint32_t rc = 0;
548
549      for (files::relocations::const_iterator fri = fsec.relocs.begin ();
550           fri != fsec.relocs.end ();
551           ++fri, ++rc)
552      {
553        const files::relocation& freloc = *fri;
554
555        if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
556          std::cout << " " << std::setw (2) << sec.relocs.size ()
557                    << '/' << std::setw (2) << rc
558                    << std::hex << ": reloc.info=0x" << freloc.info << std::dec
559                    << " reloc.offset=" << freloc.offset
560                    << " reloc.addend=" << freloc.addend
561                    << " reloc.symtype=" << freloc.symtype
562                    << " reloc.symsect=" << freloc.symsect
563                    << std::endl;
564
565        sec.relocs.push_back (relocation (freloc, offset));
566      }
567
568      sec.rela = fsec.rela;
569      sec.size = offset + fsec.size;
570    }
571
572    external::external (const uint32_t name,
573                        const sections sec,
574                        const uint32_t value,
575                        const uint32_t data)
576      : name (name),
577        sec (sec),
578        value (value),
579        data (data)
580    {
581    }
582
583    external::external (const external& orig)
584      : name (orig.name),
585        sec (orig.sec),
586        value (orig.value),
587        data (orig.data)
588    {
589    }
590
591    object::object (files::object& obj)
592      : obj (obj)
593    {
594      /*
595       * Set up the names of the sections.
596       */
597      for (int s = 0; s < rap_secs; ++s)
598        secs[s].name = section_names[s];
599
600      /*
601       * Get the relocation records. Collect the various section types from the
602       * object file into the RAP sections. Merge those sections into the RAP
603       * sections.
604       */
605
606      obj.open ();
607      try
608      {
609        obj.begin ();
610        obj.load_relocations ();
611        obj.end ();
612      }
613      catch (...)
614      {
615        obj.close ();
616        throw;
617      }
618      obj.close ();
619
620      obj.get_sections (text,   SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR);
621      obj.get_sections (const_, SHT_PROGBITS, SHF_ALLOC, SHF_WRITE | SHF_EXECINSTR);
622      obj.get_sections (ctor,   ".ctors");
623      obj.get_sections (dtor,   ".dtors");
624      obj.get_sections (data,   SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
625      obj.get_sections (bss,    SHT_NOBITS,   SHF_ALLOC | SHF_WRITE);
626      obj.get_sections (symtab, SHT_SYMTAB);
627      obj.get_sections (strtab, ".strtab");
628
629      std::for_each (text.begin (), text.end (),
630                     section_merge (*this, secs[rap_text]));
631      std::for_each (const_.begin (), const_.end (),
632                     section_merge (*this, secs[rap_const]));
633      std::for_each (ctor.begin (), ctor.end (),
634                     section_merge (*this, secs[rap_ctor]));
635      std::for_each (dtor.begin (), dtor.end (),
636                     section_merge (*this, secs[rap_dtor]));
637      std::for_each (data.begin (), data.end (),
638                     section_merge (*this, secs[rap_data]));
639      std::for_each (bss.begin (), bss.end (),
640                     section_merge (*this, secs[rap_bss]));
641    }
642
643    object::object (const object& orig)
644      : obj (orig.obj),
645        text (orig.text),
646        const_ (orig.const_),
647        ctor (orig.ctor),
648        dtor (orig.dtor),
649        data (orig.data),
650        bss (orig.bss),
651        symtab (orig.symtab),
652        strtab (orig.strtab)
653    {
654      for (int s = 0; s < rap_secs; ++s)
655        secs[s] = orig.secs[s];
656    }
657
658    sections
659    object::find (const uint32_t index) const
660    {
661      const files::section* sec;
662
663      sec = files::find (text, index);
664      if (sec)
665        return rap_text;
666
667      sec = files::find (const_, index);
668      if (sec)
669        return rap_const;
670
671      sec = files::find (ctor, index);
672      if (sec)
673        return rap_ctor;
674
675      sec = files::find (dtor, index);
676      if (sec)
677        return rap_dtor;
678
679      sec = files::find (data, index);
680      if (sec)
681        return rap_data;
682
683      sec = files::find (bss, index);
684      if (sec)
685        return rap_bss;
686
687      throw rld::error ("Section index '" + rld::to_string (index) +
688                        "' not found: " + obj.name ().full (), "rap::object");
689    }
690
691    uint32_t
692    object::get_relocations () const
693    {
694      uint32_t relocs = 0;
695      for (int s = 0; s < rap_secs; ++s)
696        relocs += secs[s].relocs.size ();
697      return relocs;
698    }
699
700    uint32_t
701    object::get_relocations (int sec) const
702    {
703      if ((sec < 0) || (sec >= rap_secs))
704        throw rld::error ("Invalid section index '" + rld::to_string (index),
705                          "rap::relocations");
706      return secs[sec].relocs.size ();
707    }
708
709    void
710    object::output ()
711    {
712      std::cout << "rap:object: " << obj.name ().full () << std::endl;
713      rap::output (secs[rap_text], text);
714      rap::output (secs[rap_const], const_);
715      rap::output (secs[rap_ctor], ctor);
716      rap::output (secs[rap_dtor], dtor);
717      rap::output (secs[rap_data], data);
718      if (secs[rap_bss].size)
719        std::cout << " bss: size: " << secs[rap_bss].size << std::endl;
720    }
721
722    image::image ()
723    {
724      clear ();
725    }
726
727    void
728    image::layout (const files::object_list& app_objects,
729                   const std::string&        init,
730                   const std::string&        fini)
731    {
732      clear ();
733
734      /*
735       * Create the local objects which contain the layout information.
736       */
737      for (files::object_list::const_iterator aoi = app_objects.begin ();
738           aoi != app_objects.end ();
739           ++aoi)
740      {
741        files::object& app_obj = *(*aoi);
742
743        if (!app_obj.valid ())
744          throw rld::error ("Not valid: " + app_obj.name ().full (),
745                            "rap::layout");
746
747        objs.push_back (object (app_obj));
748      }
749
750      for (objects::iterator oi = objs.begin (), poi = objs.begin ();
751           oi != objs.end ();
752           ++oi)
753      {
754        object& obj = *oi;
755
756        /*
757         * Update the offsets in the object file. We need the object's offset
758         * to set the relocation offset's correctly as they are relative to the
759         * object file.
760         */
761        if (oi != objs.begin ())
762        {
763          object& pobj = *poi;
764          for (int s = 0; s < rap_secs; ++s)
765            obj.secs[s].set_offset (pobj.secs[s]);
766          ++poi;
767        }
768
769        for (int s = 0; s < rap_secs; ++s)
770          update_section (s, obj.secs[s]);
771
772        collect_symbols (obj);
773
774        relocs_size += obj.get_relocations ();
775
776        if (rld::verbose () >= RLD_VERBOSE_DETAILS)
777          obj.output ();
778      }
779
780      init_off = strtab.size () + 1;
781      strtab += '\0';
782      strtab += init;
783
784      fini_off = strtab.size () + 1;
785      strtab += '\0';
786      strtab += fini;
787
788      if (rld::verbose () >= RLD_VERBOSE_INFO)
789      {
790        uint32_t total = (sec_size[rap_text] + sec_size[rap_data] +
791                          sec_size[rap_data] + sec_size[rap_bss] +
792                          symtab_size + strtab.size() + relocs_size);
793        std::cout << "rap::layout: total:" << total
794                  << " text:" << sec_size[rap_text]
795                  << " const:" << sec_size[rap_const]
796                  << " ctor:" << sec_size[rap_ctor]
797                  << " dtor:" << sec_size[rap_dtor]
798                  << " data:" << sec_size[rap_data]
799                  << " bss:" << sec_size[rap_bss]
800                  << " symbols:" << symtab_size << " (" << externs.size () << ')'
801                  << " strings:" << strtab.size () + 1
802                  << " relocs:" << relocs_size
803                  << std::endl;
804      }
805    }
806
807    void
808    image::collect_symbols (object& obj)
809    {
810      symbols::pointers& esyms = obj.obj.external_symbols ();
811      for (symbols::pointers::const_iterator ei = esyms.begin ();
812           ei != esyms.end ();
813           ++ei)
814      {
815        const symbols::symbol& sym = *(*ei);
816
817        if ((sym.type () == STT_OBJECT) || (sym.type () == STT_FUNC))
818        {
819          if ((sym.binding () == STB_GLOBAL) || (sym.binding () == STB_WEAK))
820          {
821            int         symsec = sym.section_index ();
822            sections    rap_sec = obj.find (symsec);
823            section&    sec = obj.secs[rap_sec];
824            std::size_t name;
825
826            /*
827             * See if the name is already in the string table.
828             */
829            name = strtab.find (sym.name ());
830
831            if (name == std::string::npos)
832            {
833              name = strtab.size () + 1;
834              strtab += '\0';
835              strtab += sym.name ();
836            }
837
838            /*
839             * The symbol's value is the symbols value plus the offset of the
840             * object file's section offset in the RAP section.
841             */
842            externs.push_back (external (name,
843                                         rap_sec,
844                                         sec.offset + sec.osecs[symsec] +
845                                         sym.value (),
846                                         sym.info ()));
847
848            symtab_size += external::rap_size;
849          }
850        }
851      }
852    }
853
854    /**
855     * Helper for for_each to write out the various sections.
856     */
857    class section_writer:
858      public std::unary_function < object, void >
859    {
860    public:
861
862      section_writer (image&                img,
863                      compress::compressor& comp,
864                      sections              sec);
865
866      void operator () (object& obj);
867
868    private:
869
870      image&                img;
871      compress::compressor& comp;
872      sections              sec;
873      uint32_t              offset;
874    };
875
876    section_writer::section_writer (image&                img,
877                                    compress::compressor& comp,
878                                    sections              sec)
879      : img (img),
880        comp (comp),
881        sec (sec),
882        offset (0)
883    {
884      if (rld::verbose () >= RLD_VERBOSE_INFO)
885        std::cout << "rap:output: " << section_names[sec]
886                  << '=' << comp.transferred () << std::endl;
887    }
888
889    void
890    section_writer::operator () (object& obj)
891    {
892      if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
893        std::cout << "rap:writing: " << section_names[sec] << std::endl;
894
895      switch (sec)
896      {
897        case rap_text:
898          img.write (comp, obj.obj, obj.text, offset);
899          break;
900        case rap_const:
901          img.write (comp, obj.obj, obj.const_, offset);
902          break;
903        case rap_ctor:
904          img.write (comp, obj.obj, obj.ctor, offset);
905          break;
906        case rap_dtor:
907          img.write (comp, obj.obj, obj.dtor, offset);
908          break;
909        case rap_data:
910          img.write (comp, obj.obj, obj.data, offset);
911          break;
912        default:
913          break;
914      }
915    }
916
917    void
918    image::write (compress::compressor& comp)
919    {
920      /*
921       * Start with the machine type so the target can check the applicatiion
922       * is ok and can be loaded. Add the init and fini labels to the string
923       * table and add the references to the string table next. Follow this
924       * with the section details then the string table and symbol table then
925       * finally the relocation records.
926       */
927
928      if (rld::verbose () >= RLD_VERBOSE_INFO)
929        std::cout << "rap:output: machine=" << comp.transferred () << std::endl;
930
931      comp << elf::object_machine_type ()
932           << elf::object_datatype ()
933           << elf::object_class ();
934
935      /*
936       * The init and fini label offsets. Then the symbol table and string
937       * table sizes.
938       */
939
940      if (rld::verbose () >= RLD_VERBOSE_INFO)
941        std::cout << "rap:output: header=" << comp.transferred () << std::endl;
942
943      comp << init_off
944           << fini_off
945           << symtab_size
946           << (uint32_t) strtab.size () + 1
947           << (uint32_t) 0;
948
949      /*
950       * The sections.
951       */
952      for (int s = 0; s < rap_secs; ++s)
953        comp << sec_size[s]
954             << sec_align[s];
955
956      /*
957       * Output the sections from each object file.
958       */
959      std::for_each (objs.begin (), objs.end (),
960                     section_writer (*this, comp, rap_text));
961      std::for_each (objs.begin (), objs.end (),
962                     section_writer (*this, comp, rap_const));
963      std::for_each (objs.begin (), objs.end (),
964                     section_writer (*this, comp, rap_ctor));
965      std::for_each (objs.begin (), objs.end (),
966                     section_writer (*this, comp, rap_dtor));
967      std::for_each (objs.begin (), objs.end (),
968                     section_writer (*this, comp, rap_data));
969
970      if (rld::verbose () >= RLD_VERBOSE_INFO)
971        std::cout << "rap:output: strtab=" << comp.transferred () << std::endl;
972
973      strtab += '\0';
974      comp << strtab;
975
976      if (rld::verbose () >= RLD_VERBOSE_INFO)
977        std::cout << "rap:output: symbols=" << comp.transferred () << std::endl;
978
979      write_externals (comp);
980
981      if (rld::verbose () >= RLD_VERBOSE_INFO)
982        std::cout << "rap:output: relocs=" << comp.transferred () << std::endl;
983
984      write_relocations (comp);
985    }
986
987    void
988    image::write (compress::compressor&  comp,
989                  files::object&         obj,
990                  const files::sections& secs,
991                  uint32_t&              offset)
992    {
993      uint32_t size = 0;
994
995      obj.open ();
996
997      try
998      {
999        obj.begin ();
1000
1001        if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
1002          std::cout << "rap:write sections: " << obj.name ().full () << std::endl;
1003
1004        for (files::sections::const_iterator si = secs.begin ();
1005             si != secs.end ();
1006             ++si)
1007        {
1008          const files::section& sec = *si;
1009          uint32_t              unaligned_offset = offset + size;
1010
1011          offset = align_offset (offset, size, sec.alignment);
1012
1013          if (offset != unaligned_offset)
1014          {
1015            char ee = '\xee';
1016            for (uint32_t p = 0; p < (offset - unaligned_offset); ++p)
1017              comp.write (&ee, 1);
1018          }
1019
1020          comp.write (obj, sec.offset, sec.size);
1021
1022          if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
1023            std::cout << " sec: " << sec.index << ' ' << sec.name
1024                      << " size=" << sec.size
1025                      << " offset=" << offset
1026                      << " align=" << sec.alignment
1027                      << " padding=" << (offset - unaligned_offset)  << std::endl;
1028
1029          size = sec.size;
1030        }
1031
1032        offset += size;
1033
1034        if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
1035          std::cout << " total size=" << offset << std::endl;
1036
1037        obj.end ();
1038      }
1039      catch (...)
1040      {
1041        obj.close ();
1042        throw;
1043      }
1044
1045      obj.close ();
1046    }
1047
1048    void
1049    image::write_externals (compress::compressor& comp)
1050    {
1051      int count = 0;
1052      for (externals::const_iterator ei = externs.begin ();
1053           ei != externs.end ();
1054           ++ei, ++count)
1055      {
1056        const external& ext = *ei;
1057
1058        if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
1059          std::cout << "rap:externs: " << count
1060                    << " name=" << &strtab[ext.name] << " (" << ext.name << ')'
1061                    << " section=" << section_names[ext.sec]
1062                    << " data=" << ext.data
1063                    << " value=0x" << std::hex << ext.value << std::dec
1064                    << std::endl;
1065
1066        if ((ext.data & 0xffff0000) != 0)
1067          throw rld::error ("Data value has data in bits higher than 15",
1068                            "rap::write-externs");
1069
1070        comp << (uint32_t) ((ext.sec << 16) | ext.data)
1071             << ext.name
1072             << ext.value;
1073      }
1074    }
1075
1076    void
1077    image::write_relocations (compress::compressor& comp)
1078    {
1079      for (int s = 0; s < rap_secs; ++s)
1080      {
1081        uint32_t count = get_relocations (s);
1082        uint32_t sr = 0;
1083        uint32_t header;
1084
1085        if (rld::verbose () >= RLD_VERBOSE_TRACE)
1086          std::cout << "rap:relocation: section:" << section_names[s]
1087                    << " relocs=" << count
1088                    << " rela=" << (char*) (sec_rela[s] ? "yes" : "no")
1089                    << std::endl;
1090
1091        header = count;
1092        header |= sec_rela[s] ? RAP_RELOC_RELA : 0;
1093
1094        comp << header;
1095
1096        for (objects::iterator oi = objs.begin ();
1097             oi != objs.end ();
1098             ++oi)
1099        {
1100          object&      obj = *oi;
1101          section&     sec = obj.secs[s];
1102          relocations& relocs = sec.relocs;
1103          uint32_t     rc = 0;
1104
1105          if (rld::verbose () >= RLD_VERBOSE_TRACE)
1106            std::cout << " relocs=" << sec.relocs.size ()
1107                      << " sec.offset=" << sec.offset
1108                      << " sec.size=" << sec.size
1109                      << " sec.align=" << sec.align
1110                      << "  " << obj.obj.name ().full ()  << std::endl;
1111
1112          for (relocations::const_iterator ri = relocs.begin ();
1113               ri != relocs.end ();
1114               ++ri, ++sr, ++rc)
1115          {
1116            const relocation& reloc = *ri;
1117            uint32_t          info = GELF_R_TYPE (reloc.info);
1118            uint32_t          offset;
1119            uint32_t          addend = reloc.addend;
1120            bool              write_addend = sec.rela;
1121            bool              write_symname = false;
1122
1123            offset = sec.offset + reloc.offset;
1124
1125            if (reloc.symtype == STT_SECTION)
1126            {
1127              int rap_symsect = obj.find (reloc.symsect);
1128
1129              /*
1130               * Bit 31 clear, bits 30:8 RAP section index.
1131               */
1132              info |= rap_symsect << 8;
1133
1134              addend += (obj.secs[rap_symsect].offset +
1135                         obj.secs[rap_symsect].osecs[reloc.symsect] +
1136                         reloc.symvalue);
1137
1138              write_addend = true;
1139
1140              if (rld::verbose () >= RLD_VERBOSE_TRACE)
1141                std::cout << "  " << std::setw (2) << sr
1142                          << '/' << std::setw (2) << rc
1143                          <<":  rsym: sect=" << section_names[rap_symsect]
1144                          << " rap_symsect=" << rap_symsect
1145                          << " sec.offset=" << obj.secs[rap_symsect].offset
1146                          << " sec.osecs=" << obj.secs[rap_symsect].osecs[reloc.symsect]
1147                          << " (" << obj.obj.get_section (reloc.symsect).name << ')'
1148                          << " reloc.symsect=" << reloc.symsect
1149                          << " reloc.symvalue=" << reloc.symvalue
1150                          << " reloc.addend=" << reloc.addend
1151                          << " addend=" << addend
1152                          << std::endl;
1153            }
1154            else
1155            {
1156              /*
1157               * Bit 31 must be set. Bit 30 determines the type of string and
1158               * bits 29:8 the strtab offset or the size of the appended
1159               * string.
1160               */
1161
1162              info |= RAP_RELOC_STRING;
1163
1164              std::size_t size = strtab.find (reloc.symname);
1165
1166              if (size == std::string::npos)
1167              {
1168                /*
1169                 * Bit 30 clear, the size of the symbol name.
1170                 */
1171                info |= reloc.symname.size () << 8;
1172                write_symname = true;
1173              }
1174              else
1175              {
1176                /*
1177                 * Bit 30 set, the offset in the strtab.
1178                 */
1179                info |= RAP_RELOC_STRING_EMBED | (size << 8);
1180              }
1181            }
1182
1183            if (rld::verbose () >= RLD_VERBOSE_TRACE)
1184            {
1185              std::cout << "  " << std::setw (2) << sr << '/'
1186                        << std::setw (2) << rc
1187                        << std::hex << ": reloc: info=0x" << info << std::dec
1188                        << " offset=" << offset;
1189              if (write_addend)
1190                std::cout << " addend=" << addend;
1191              if (write_symname)
1192                std::cout << " symname=" << reloc.symname;
1193              std::cout << std::hex
1194                        << " reloc.info=0x" << reloc.info << std::dec
1195                        << " reloc.offset=" << reloc.offset
1196                        << " reloc.symtype=" << reloc.symtype
1197                        << std::endl;
1198            }
1199
1200            comp << info << offset;
1201
1202            if (write_addend)
1203              comp << addend;
1204
1205            if (write_symname)
1206              comp << reloc.symname;
1207          }
1208        }
1209      }
1210    }
1211
1212    uint32_t
1213    image::get_relocations (int sec) const
1214    {
1215      if ((sec < 0) || (sec >= rap_secs))
1216        throw rld::error ("Invalid section index '" + rld::to_string (index),
1217                          "rap::image::relocations");
1218
1219      uint32_t relocs = 0;
1220
1221      for (objects::const_iterator oi = objs.begin ();
1222           oi != objs.end ();
1223           ++oi)
1224      {
1225        const object& obj = *oi;
1226        relocs += obj.get_relocations (sec);
1227      }
1228
1229      return relocs;
1230    }
1231
1232    void
1233    image::clear ()
1234    {
1235      for (int s = 0; s < rap_secs; ++s)
1236      {
1237        sec_size[s] = 0;
1238        sec_align[s] = 0;
1239        sec_rela[s] = false;
1240      }
1241      symtab_size = 0;
1242      strtab.clear ();
1243      relocs_size = 0;
1244      init_off = 0;
1245      fini_off = 0;
1246    }
1247
1248    void
1249    image::update_section (int index, const section& sec)
1250    {
1251      sec_size[index] = align_offset (sec_size[index], 0, sec.align);
1252      sec_size[index] += sec.size;
1253      sec_align[index] = sec.align;
1254      sec_rela[index] = sec.rela;
1255    }
1256
1257    void
1258    write (files::image&             app,
1259           const std::string&        init,
1260           const std::string&        fini,
1261           const files::object_list& app_objects,
1262           const symbols::table&     /* symbols */) /* Add back for incremental
1263                                                     * linking */
1264    {
1265      std::string header;
1266
1267      header = "RAP,00000000,0001,LZ77,00000000\n";
1268      app.write (header.c_str (), header.size ());
1269
1270      compress::compressor compressor (app, 2 * 1024);
1271      image                rap;
1272
1273      rap.layout (app_objects, init, fini);
1274      rap.write (compressor);
1275
1276      compressor.flush ();
1277
1278      std::ostringstream length;
1279
1280      length << std::setfill ('0') << std::setw (8)
1281             << header.size () + compressor.compressed ();
1282
1283      header.replace (4, 8, length.str ());
1284
1285      app.seek (0);
1286      app.write (header.c_str (), header.size ());
1287
1288      if (rld::verbose () >= RLD_VERBOSE_INFO)
1289      {
1290        int pcent = (compressor.compressed () * 100) / compressor.transferred ();
1291        int premand = (((compressor.compressed () * 1000) + 500) /
1292                       compressor.transferred ()) % 10;
1293        std::cout << "rap: objects: " << app_objects.size ()
1294                  << ", size: " << compressor.compressed ()
1295                  << ", compression: " << pcent << '.' << premand << '%'
1296                  << std::endl;
1297      }
1298    }
1299
1300  }
1301}
Note: See TracBrowser for help on using the repository browser.