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

4.104.115
Last change on this file since 9ba89e1 was 9ba89e1, checked in by Chris Johns <chrisj@…>, on 11/30/12 at 21:09:02

Remove the trace on hack.

  • Property mode set to 100644
File size: 20.8 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 sections of interest in a RAP file.
43     */
44    enum sections
45    {
46      rap_text = 0,
47      rap_const = 1,
48      rap_ctor = 2,
49      rap_dtor = 3,
50      rap_data = 4,
51      rap_bss = 5,
52      rap_secs = 6
53    };
54
55    /**
56     * The names of the RAP sections.
57     */
58    static const char* section_names[rap_secs] =
59    {
60      ".text",
61      ".const",
62      ".ctor",
63      ".dtor",
64      ".data",
65      ".bss"
66    };
67
68    /**
69     * The RAP section data.
70     */
71    struct section
72    {
73      std::string name;   //< The name of the section.
74      uint32_t    size;   //< The size of the section.
75      uint32_t    offset; //< The offset of the section.
76      uint32_t    align;  //< The alignment of the section.
77
78      /**
79       * Operator to add up section data.
80       */
81      section& operator += (const section& sec);
82
83      /**
84       * Default constructor.
85       */
86      section ();
87    };
88
89    /**
90     * A symbol. This matches the symbol structure 'rtems_rtl_obj_sym_t' in the
91     * target code.
92     */
93    struct external
94    {
95      /**
96       * Size of an external in the RAP file.
97       */
98      static const uint32_t rap_size = sizeof (uint32_t) * 3;
99
100      const uint32_t name;  //< The string table's name index.
101      const sections sec;   //< The section the symbols belongs to.
102      const uint32_t value; //< The offset from the section base.
103      const uint32_t data;  //< The ELF st.info field.
104
105      /**
106       * The default constructor.
107       */
108      external (const uint32_t name,
109                const sections sec,
110                const uint32_t value,
111                const uint32_t info);
112
113      /**
114       * Copy constructor.
115       */
116      external (const external& orig);
117
118    };
119
120    /**
121     * A container of externals.
122     */
123    typedef std::list < external > externals;
124
125    /**
126     * The specific data for each object we need to collect to create the RAP
127     * format file.
128     */
129    struct object
130    {
131
132      files::object&  obj;            //< The object file.
133      files::sections text;           //< All executable code.
134      files::sections const_;         //< All read only data.
135      files::sections ctor;           //< The static constructor table.
136      files::sections dtor;           //< The static destructor table.
137      files::sections data;           //< All initialised read/write data.
138      files::sections bss;            //< All uninitialised read/write data
139      files::sections relocs;         //< All relocation records.
140      files::sections symtab;         //< All exported symbols.
141      files::sections strtab;         //< All exported strings.
142      section         secs[rap_secs]; //< The sections of interest.
143      uint32_t        symtab_off;     //< The symbols section file offset.
144      uint32_t        symtab_size;    //< The symbols section size.
145      uint32_t        strtab_off;     //< The strings section file offset.
146      uint32_t        strtab_size;    //< The strings section size.
147      uint32_t        relocs_off;     //< The reloc's section file offset.
148      uint32_t        relocs_size;    //< The reloc's section size.
149
150      /**
151       * The constructor. Need to have an object file to create.
152       */
153      object (files::object& obj);
154
155      /**
156       * The copy constructor.
157       */
158      object (const object& orig);
159
160      /**
161       * Find the section type that matches the section index.
162       */
163      sections find (const uint32_t index) const;
164
165    private:
166      /**
167       * No default constructor allowed.
168       */
169      object ();
170    };
171
172    /**
173     * A container of objects.
174     */
175    typedef std::list < object > objects;
176
177    /**
178     * The RAP image.
179     */
180    class image
181    {
182    public:
183      /**
184       * Construct the image.
185       */
186      image ();
187
188      /**
189       * Load the layout data from the object files.
190       */
191      void layout (const files::object_list& app_objects);
192
193      /**
194       * Write the compressed output file.
195       */
196      void write (compress::compressor& comp,
197                  const std::string&    init,
198                  const std::string&    fini);
199
200      /**
201       * Write the sections to the compressed output file.
202       */
203      void write (compress::compressor&  comp,
204                  files::object&         obj,
205                  const files::sections& secs);
206
207    private:
208
209      objects     objs;           //< The RAP objects
210      section     secs[rap_secs]; //< The sections of interest.
211      externals   externs;        //< The symbols in the image
212      uint32_t    symtab_size;    //< The size of the symbols.
213      std::string strtab;         //< The strings table.
214      uint32_t    relocs_size;    //< The relocations size.
215    };
216
217    /**
218     * Output helper function to report the sections in an object file.
219     * This is useful when seeing the flags in the sections.
220     *
221     * @param name The name of the section group in the RAP file.
222     * @param size The total of the section size's in the group.
223     * @param secs The container of sections in the group.
224     */
225    void
226    output (const char* name, size_t size, const files::sections& secs)
227    {
228      if (size)
229      {
230        std::cout << ' ' << name << ": size: " << size << std::endl;
231
232        for (files::sections::const_iterator si = secs.begin ();
233             si != secs.end ();
234             ++si)
235        {
236          files::section sec = *si;
237
238          if (sec.size)
239          {
240            #define SF(f, i, c) if (sec.flags & (f)) flags[i] = c
241
242            std::string flags ("--------------");
243
244            SF (SHF_WRITE,            0, 'W');
245            SF (SHF_ALLOC,            1, 'A');
246            SF (SHF_EXECINSTR,        2, 'E');
247            SF (SHF_MERGE,            3, 'M');
248            SF (SHF_STRINGS,          4, 'S');
249            SF (SHF_INFO_LINK,        5, 'I');
250            SF (SHF_LINK_ORDER,       6, 'L');
251            SF (SHF_OS_NONCONFORMING, 7, 'N');
252            SF (SHF_GROUP,            8, 'G');
253            SF (SHF_TLS,              9, 'T');
254            SF (SHF_AMD64_LARGE,     10, 'a');
255            SF (SHF_ENTRYSECT,       11, 'e');
256            SF (SHF_COMDEF,          12, 'c');
257            SF (SHF_ORDERED,         13, 'O');
258
259            std::cout << "  " << std::left
260                      << std::setw (15) << sec.name
261                      << " " << flags
262                      << " size: " << std::setw (5) << sec.size
263                      << " align: " << sec.alignment
264                      << std::right << std::endl;
265          }
266        }
267      }
268    }
269
270    section::section ()
271      : size (0),
272        offset (0),
273        align (0)
274    {
275    }
276
277    section&
278    section::operator += (const section& sec)
279    {
280      if (sec.size)
281      {
282        if (align == 0)
283          align = sec.align;
284        else if (align != sec.align)
285          throw rld::error ("Alignments do not match for section '" + name + "'",
286                            "rap::section");
287
288        if (size && (align == 0))
289          throw rld::error ("Invalid alignment '" + name + "'",
290                            "rap::section");
291
292        size += sec.size;
293        offset = sec.offset + sec.size;
294
295        uint32_t mask = (1 << (align - 1)) - 1;
296
297        if (offset & mask)
298        {
299          offset &= ~mask;
300          offset += (1 << align);
301        }
302      }
303
304      return *this;
305    }
306
307    external::external (const uint32_t name,
308                        const sections sec,
309                        const uint32_t value,
310                        const uint32_t data)
311      : name (name),
312        sec (sec),
313        value (value),
314        data (data)
315    {
316    }
317
318    external::external (const external& orig)
319      : name (orig.name),
320        sec (orig.sec),
321        value (orig.value),
322        data (orig.data)
323    {
324    }
325
326    object::object (files::object& obj)
327      : obj (obj),
328        symtab_off (0),
329        symtab_size (0),
330        strtab_off (0),
331        strtab_size (0),
332        relocs_off (0),
333        relocs_size (0)
334    {
335      /*
336       * Set up the names of the sections.
337       */
338      for (int s = 0; s < rap_secs; ++s)
339        secs[s].name = section_names[s];
340
341      /*
342       * Get from the object file the various sections we need to format a
343       * memory layout.
344       */
345
346      obj.get_sections (text,   SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR);
347      obj.get_sections (const_, SHT_PROGBITS, SHF_ALLOC | SHF_MERGE, SHF_WRITE | SHF_EXECINSTR);
348      obj.get_sections (ctor,   ".ctors");
349      obj.get_sections (dtor,   ".dtors");
350      obj.get_sections (data,   SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
351      obj.get_sections (bss,    SHT_NOBITS,   SHF_ALLOC | SHF_WRITE);
352      obj.get_sections (symtab, SHT_SYMTAB);
353      obj.get_sections (strtab, ".strtab");
354
355      /*
356       * Only interested in the relocation records for the text sections.
357       */
358      for (files::sections::const_iterator ti = text.begin ();
359           ti != text.end ();
360           ++ti)
361      {
362        files::section sec = *ti;
363        obj.get_sections (relocs, ".rel" + sec.name);
364        obj.get_sections (relocs, ".rela" + sec.name);
365      }
366
367      secs[rap_text].size = files::sum_sizes (text);
368      if (!text.empty ())
369        secs[rap_text].align = (*text.begin ()).alignment;
370
371      secs[rap_const].size = files::sum_sizes (const_);
372      if (!const_.empty ())
373        secs[rap_const].align = (*const_.begin ()).alignment;
374
375      secs[rap_ctor].size = files::sum_sizes (ctor);
376      if (!ctor.empty ())
377        secs[rap_ctor].align = (*ctor.begin ()).alignment;
378
379      secs[rap_dtor].size = files::sum_sizes (dtor);
380      if (!dtor.empty ())
381        secs[rap_dtor].align = (*dtor.begin ()).alignment;
382
383      secs[rap_data].size = files::sum_sizes (data);
384      if (!data.empty ())
385        secs[rap_data].align = (*data.begin ()).alignment;
386
387      secs[rap_bss].size = files::sum_sizes (bss);
388      if (!bss.empty ())
389        secs[rap_bss].align = (*bss.begin ()).alignment;
390
391      symtab_size = files::sum_sizes (symtab);
392      strtab_size = files::sum_sizes (strtab);
393      relocs_size = files::sum_sizes (relocs);
394
395      if (rld::verbose () >= RLD_VERBOSE_TRACE)
396      {
397        std::cout << "rap:object: " << obj.name ().full () << std::endl;
398        output ("text", secs[rap_text].size, text);
399        output ("const", secs[rap_const].size, const_);
400        output ("ctor", secs[rap_ctor].size, ctor);
401        output ("dtor", secs[rap_dtor].size, dtor);
402        output ("data", secs[rap_data].size, data);
403        if (secs[rap_bss].size)
404          std::cout << " bss: size: " << secs[rap_bss].size << std::endl;
405        output ("relocs", relocs_size, relocs);
406        output ("symtab", symtab_size, symtab);
407        output ("strtab", strtab_size, strtab);
408      }
409    }
410
411    object::object (const object& orig)
412      : obj (orig.obj),
413        text (orig.text),
414        const_ (orig.const_),
415        ctor (orig.ctor),
416        dtor (orig.dtor),
417        data (orig.data),
418        bss (orig.bss),
419        relocs (orig.relocs),
420        symtab (orig.symtab),
421        strtab (orig.strtab),
422        symtab_off (orig.symtab_off),
423        symtab_size (orig.symtab_size),
424        strtab_off (orig.strtab_off),
425        strtab_size (orig.strtab_size),
426        relocs_off (orig.relocs_off),
427        relocs_size (orig.relocs_size)
428    {
429      for (int s = 0; s < rap_secs; ++s)
430        secs[s] = orig.secs[s];
431    }
432
433    sections
434    object::find (const uint32_t index) const
435    {
436      const files::section* sec;
437
438      sec = files::find (text, index);
439      if (sec)
440        return rap_text;
441
442      sec = files::find (const_, index);
443      if (sec)
444        return rap_const;
445
446      sec = files::find (ctor, index);
447      if (sec)
448        return rap_ctor;
449
450      sec = files::find (dtor, index);
451      if (sec)
452        return rap_dtor;
453
454      sec = files::find (data, index);
455      if (sec)
456        return rap_data;
457
458      sec = files::find (bss, index);
459      if (sec)
460        return rap_bss;
461
462      throw rld::error ("Section index not found: " + obj.name ().full (),
463                        "rap::object");
464    }
465
466    image::image ()
467      : symtab_size (0),
468        relocs_size (0)
469    {
470      /*
471       * Set up the names of the sections.
472       */
473      for (int s = 0; s < rap_secs; ++s)
474        secs[s].name = section_names[s];
475    }
476
477    void
478    image::layout (const files::object_list& app_objects)
479    {
480      /*
481       * Create the local objects which contain the layout information.
482       */
483      for (files::object_list::const_iterator aoi = app_objects.begin ();
484           aoi != app_objects.end ();
485           ++aoi)
486      {
487        files::object& app_obj = *(*aoi);
488
489        if (!app_obj.valid ())
490          throw rld::error ("Not valid: " + app_obj.name ().full (),
491                            "rap::layout");
492
493        objs.push_back (object (app_obj));
494      }
495
496      for (int s = 0; s < rap_secs; ++s)
497      {
498        secs[s].size = 0;
499        secs[s].offset = 0;
500        secs[s].align = 0;
501      }
502
503      for (objects::iterator oi = objs.begin ();
504           oi != objs.end ();
505           ++oi)
506      {
507        object& obj = *oi;
508
509        secs[rap_text] += obj.secs[rap_text];
510        secs[rap_const] += obj.secs[rap_const];
511        secs[rap_ctor] += obj.secs[rap_ctor];
512        secs[rap_dtor] += obj.secs[rap_dtor];
513        secs[rap_data] += obj.secs[rap_data];
514        secs[rap_bss] += obj.secs[rap_bss];
515
516        symtab_size = 0;
517        strtab.clear ();
518
519        uint32_t sym_count = 0;
520
521        symbols::pointers& esyms = obj.obj.external_symbols ();
522        for (symbols::pointers::const_iterator ei = esyms.begin ();
523             ei != esyms.end ();
524             ++ei, ++sym_count)
525        {
526          const symbols::symbol& sym = *(*ei);
527
528          if ((sym.type () == STT_OBJECT) || (sym.type () == STT_FUNC))
529          {
530            if ((sym.binding () == STB_GLOBAL) || (sym.binding () == STB_WEAK))
531            {
532              externs.push_back (external (sym_count,
533                                           obj.find (sym.index ()),
534                                           sym.value (),
535                                           sym.info ()));
536              symtab_size += external::rap_size;
537              strtab += sym.name ();
538              strtab += '\0';
539            }
540          }
541        }
542
543        relocs_size += obj.relocs_size;
544      }
545
546      if (rld::verbose () >= RLD_VERBOSE_INFO)
547      {
548        uint32_t total = (secs[rap_text].size + secs[rap_data].size +
549                          secs[rap_data].size + secs[rap_bss].size +
550                          symtab_size + strtab.size() + relocs_size);
551        std::cout << "rap::layout: total:" << total
552                  << " text:" << secs[rap_text].size
553                  << " const:" << secs[rap_const].size
554                  << " ctor:" << secs[rap_ctor].size
555                  << " dtor:" << secs[rap_dtor].size
556                  << " data:" << secs[rap_data].size
557                  << " bss:" << secs[rap_bss].size
558                  << " symbols:" << symtab_size << " (" << externs.size () << ')'
559                  << " strings:" << strtab.size ()
560                  << " relocs:" << relocs_size
561                  << std::endl;
562      }
563    }
564
565    /**
566     * Helper for for_each to write out the various sections.
567     */
568    class section_writer:
569      public std::unary_function < object, void >
570    {
571    public:
572
573      section_writer (image&                img,
574                      compress::compressor& comp,
575                      sections              sec);
576
577      void operator () (object& obj);
578
579    private:
580
581      image&                img;
582      compress::compressor& comp;
583      sections              sec;
584    };
585
586    section_writer::section_writer (image&                img,
587                                    compress::compressor& comp,
588                                    sections              sec)
589      : img (img),
590        comp (comp),
591        sec (sec)
592    {
593    }
594
595    void
596    section_writer::operator () (object& obj)
597    {
598      switch (sec)
599      {
600        case rap_text:
601          img.write (comp, obj.obj, obj.text);
602          break;
603        case rap_const:
604          img.write (comp, obj.obj, obj.const_);
605          break;
606        case rap_ctor:
607          img.write (comp, obj.obj, obj.ctor);
608          break;
609        case rap_dtor:
610          img.write (comp, obj.obj, obj.dtor);
611          break;
612        case rap_data:
613          img.write (comp, obj.obj, obj.data);
614          break;
615          default:
616            break;
617      }
618    }
619
620    void
621    image::write (compress::compressor& comp,
622                  const std::string&    init,
623                  const std::string&    fini)
624    {
625      /*
626       * Start with the machine type so the target can check the applicatiion
627       * is ok and can be loaded. Add the init and fini labels to the string
628       * table and add the references to the string table next. Follow this
629       * with the section details then the string table and symbol table then
630       * finally the relocation records.
631       */
632
633      comp << elf::object_machine_type ()
634           << elf::object_datatype ()
635           << elf::object_class ();
636
637      comp << (uint32_t) strtab.size ();
638      strtab += init;
639      strtab += '\0';
640
641      comp << (uint32_t) strtab.size ();
642      strtab += fini;
643      strtab += '\0';
644
645      comp << symtab_size
646           << (uint32_t) strtab.size ()
647           << (uint32_t) 0;
648
649      for (int s = 0; s < rap_secs; ++s)
650        comp << secs[s].size
651             << secs[s].align
652             << secs[s].offset;
653
654      /*
655       * Output the sections from each object file.
656       */
657
658      std::for_each (objs.begin (), objs.end (),
659                     section_writer (*this, comp, rap_text));
660      std::for_each (objs.begin (), objs.end (),
661                     section_writer (*this, comp, rap_const));
662      std::for_each (objs.begin (), objs.end (),
663                     section_writer (*this, comp, rap_ctor));
664      std::for_each (objs.begin (), objs.end (),
665                     section_writer (*this, comp, rap_dtor));
666      std::for_each (objs.begin (), objs.end (),
667                     section_writer (*this, comp, rap_data));
668
669      comp << strtab;
670
671      for (externals::const_iterator ei = externs.begin ();
672           ei != externs.end ();
673           ++ei)
674      {
675        const external& ext = *ei;
676        comp << (uint32_t) ((ext.sec << 16) | ext.data)
677             << ext.name
678             << ext.value;
679      }
680    }
681
682    void
683    image::write (compress::compressor&  comp,
684                  files::object&         obj,
685                  const files::sections& secs)
686    {
687      obj.open ();
688
689      try
690      {
691        obj.begin ();
692        for (files::sections::const_iterator si = secs.begin ();
693             si != secs.end ();
694             ++si)
695        {
696          const files::section& sec = *si;
697          comp.write (obj, sec.offset, sec.size);
698        }
699
700        obj.end ();
701      }
702      catch (...)
703      {
704        obj.close ();
705        throw;
706      }
707
708      obj.close ();
709    }
710
711    void
712    write (files::image&             app,
713           const std::string&        init,
714           const std::string&        fini,
715           const files::object_list& app_objects,
716           const symbols::table&     /* symbols */) /* Add back for incremental
717                                                     * linking */
718    {
719      compress::compressor compressor (app, 2 * 1024);
720      image                rap;
721
722      rap.layout (app_objects);
723      rap.write (compressor, init, fini);
724
725      compressor.flush ();
726
727      if (rld::verbose () >= RLD_VERBOSE_INFO)
728      {
729        int pcent = (compressor.compressed () * 100) / compressor.transferred ();
730        int premand = (((compressor.compressed () * 1000) + 500) /
731                       compressor.transferred ()) % 10;
732        std::cout << "rap: objects: " << app_objects.size ()
733                  << ", size: " << compressor.compressed ()
734                  << ", compression: " << pcent << '.' << premand << '%'
735                  << std::endl;
736      }
737    }
738
739  }
740}
Note: See TracBrowser for help on using the repository browser.