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

4.104.115
Last change on this file since 5825009 was 6c28ffb, checked in by Chris Johns <chrisj@…>, on 12/21/12 at 06:10:18

Set header length. Make sections public.

Set the compressed file length in the RAP header. Move
the string from the outputter to the RAP file.

Make the sections public by moving to the RAP header.

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