source: rtems-tools/linkers/rld-files.cpp @ 427acf3

4.104.115
Last change on this file since 427acf3 was 5eb6604, checked in by Peng Fan <van.freenix@…>, on 08/29/13 at 11:41:23

Fix archive writer

  1. align to even address
  2. Fix the use of GElf_Ehdr and Elf32_Ehdr
  3. Fix the header related
  • Property mode set to 100644
File size: 39.4 KB
Line 
1/*
2 * Copyright (c) 2011, 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#if HAVE_CONFIG_H
18#include "config.h"
19#endif
20
21#include <algorithm>
22
23#include <errno.h>
24#include <fcntl.h>
25#include <stdio.h>
26#include <string.h>
27#include <sys/stat.h>
28
29#include <rld.h>
30
31#if __WIN32__
32#define CREATE_MODE (S_IRUSR | S_IWUSR)
33#define OPEN_FLAGS  (O_BINARY)
34#else
35#define CREATE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH)
36#define OPEN_FLAGS  (0)
37#endif
38
39namespace rld
40{
41  namespace files
42  {
43    /**
44     * Scan the decimal number returning the value found.
45     */
46    uint64_t
47    scan_decimal (const uint8_t* string, size_t len)
48    {
49      uint64_t value = 0;
50
51      while (len && (*string != ' '))
52      {
53        value *= 10;
54        value += *string - '0';
55        ++string;
56        --len;
57      }
58
59      return value;
60    }
61
62    void
63    set_number (uint32_t value, uint8_t* string, size_t len, bool octal = false)
64    {
65      std::ostringstream oss;
66      if (octal)
67        oss << std::oct;
68      oss << value;
69      size_t l = oss.str ().length ();
70      if (l > len)
71        l = len;
72      memcpy (string, oss.str ().c_str (), l);
73    }
74
75    std::string
76    basename (const std::string& name)
77    {
78      size_t b = name.find_last_of (RLD_PATH_SEPARATOR);
79      if (b != std::string::npos)
80        return name.substr (b + 1);
81      return name;
82    }
83
84    std::string
85    dirname (const std::string& name)
86    {
87      size_t b = name.find_last_of (RLD_PATH_SEPARATOR);
88      if (b != std::string::npos)
89        return name.substr (0, b - 1);
90      return name;
91    }
92
93    std::string
94    extension (const std::string& name)
95    {
96      size_t b = name.find_last_of ('.');
97      if (b != std::string::npos)
98        return name.substr (b);
99      return name;
100    }
101
102    void
103    path_split (const std::string& path, rld::files::paths& paths)
104    {
105      strings ps;
106      rld::split (path, ps, RLD_PATHSTR_SEPARATOR);
107      if (ps.size ())
108      {
109        for (strings::iterator psi = ps.begin ();
110             psi != ps.end ();
111             ++psi)
112        {
113          if (check_directory (*psi))
114            paths.push_back (*psi);
115        }
116      }
117    }
118
119    void
120    path_join (const std::string& path_, const std::string& file_, std::string& joined)
121    {
122      if ((path_[path_.size () - 1] != RLD_PATH_SEPARATOR) &&
123          (file_[0] != RLD_PATH_SEPARATOR))
124        joined = path_ + RLD_PATH_SEPARATOR + file_;
125      else if ((path_[path_.size () - 1] == RLD_PATH_SEPARATOR) &&
126               (file_[0] == RLD_PATH_SEPARATOR))
127        joined = path_ + &file_[1];
128      else
129        joined = path_ + file_;
130    }
131
132    bool
133    check_file (const std::string& path)
134    {
135      struct stat sb;
136      if (::stat (path.c_str (), &sb) == 0)
137        if (S_ISREG (sb.st_mode))
138          return true;
139      return false;
140    }
141
142    bool
143    check_directory (const std::string& path)
144    {
145      struct stat sb;
146      if (::stat (path.c_str (), &sb) == 0)
147        if (S_ISDIR (sb.st_mode))
148          return true;
149      return false;
150    }
151
152    void
153    find_file (std::string& path, const std::string& name, paths& search_paths)
154    {
155      for (rld::files::paths::iterator pi = search_paths.begin ();
156           pi != search_paths.end ();
157           ++pi)
158      {
159        path_join (*pi, name, path);
160        if (check_file (path))
161          return;
162      }
163      path.clear ();
164    }
165
166    file::file (const std::string& aname,
167                const std::string& oname,
168                off_t              offset,
169                size_t             size)
170      : aname_ (aname),
171        oname_ (oname),
172        offset_ (offset),
173        size_ (size)
174    {
175    }
176
177    file::file (const std::string& path, bool is_object)
178      : offset_ (0),
179        size_ (0)
180    {
181      set (path, is_object);
182    }
183
184    file::file ()
185      : offset_ (0),
186        size_ (0)
187    {
188    }
189
190    void
191    file::set (const std::string& path, bool is_object)
192    {
193      /*
194       * If there is a path look for a colon. If there is no colon we assume
195       * it is an object file. If the colon is the last character in the path
196       * it is just an archive.
197       */
198      if (!path.empty ())
199      {
200        bool get_size = false;
201        if (is_object)
202        {
203          size_t colon = path.find_last_of (':');
204          if ((colon != std::string::npos) && (colon > RLD_DRIVE_SEPARATOR))
205          {
206            aname_ = path.substr (0, colon - 1);
207            oname_ = path.substr (colon + 1);
208            // @todo Add offset scanning.
209          }
210          else
211          {
212            oname_ = path;
213            get_size = true;
214          }
215        }
216        else
217        {
218          aname_ = path;
219            get_size = true;
220        }
221
222        if (get_size)
223        {
224          struct stat sb;
225          if (::stat (path.c_str (), &sb) == 0)
226            size_ = sb.st_size;
227        }
228      }
229    }
230
231    bool
232    file::is_archive () const
233    {
234      return !aname_.empty () && oname_.empty ();
235    }
236
237    bool
238    file::is_object () const
239    {
240      return !oname_.empty ();
241    }
242
243    bool
244    file::is_valid () const
245    {
246      return !aname_.empty () || ~oname_.empty ();
247    }
248
249    bool
250    file::exists () const
251    {
252      /*
253       * No name set returns false.
254       */
255      bool result = false;
256      const std::string p = path ();
257      if (!p.empty ())
258        result = check_file (p);
259      return result;
260    }
261
262    const std::string
263    file::path () const
264    {
265      if (!aname_.empty ())
266        return aname_;
267      return oname_;
268    }
269
270    const std::string
271    file::full () const
272    {
273      std::string f;
274      if (!aname_.empty ())
275      {
276        f = aname_;
277        if (!oname_.empty ())
278          f += ':';
279      }
280      if (!oname_.empty ())
281        f += oname_;
282      if (!aname_.empty () && !oname_.empty ())
283        f += '@' + rld::to_string (offset_);
284      return f;
285    }
286
287    const std::string
288    file::basename () const
289    {
290      return rld::files::basename (full ());
291    }
292
293    const std::string&
294    file::aname () const
295    {
296      return aname_;
297    }
298
299    const std::string&
300    file::oname () const
301    {
302      return oname_;
303    }
304
305    off_t
306    file::offset () const
307    {
308       return offset_;
309    }
310
311    size_t
312    file::size () const
313    {
314       return size_;
315    }
316
317    image::image (file& name)
318      : name_ (name),
319        references_ (0),
320        fd_ (-1),
321        symbol_refs (0),
322        writable (false)
323    {
324    }
325
326    image::image (const std::string& path, bool is_object)
327      : name_ (path, is_object),
328        references_ (0),
329        fd_ (-1),
330        symbol_refs (0),
331        writable (false)
332    {
333    }
334
335    image::image ()
336      : references_ (0),
337        fd_ (-1),
338        symbol_refs (0),
339        writable (false)
340    {
341    }
342
343    image::~image ()
344    {
345      if (references_)
346        throw rld_error_at ("references when destructing image");
347      if (fd_ >= 0)
348        ::close (fd_);
349    }
350
351    void
352    image::open (file& name)
353    {
354      name_ = name;
355      open ();
356    }
357
358    void
359    image::open (bool writable_)
360    {
361      const std::string path = name_.path ();
362
363      if (path.empty ())
364        throw rld::error ("No file name", "open:" + path);
365
366      if (rld::verbose () >= RLD_VERBOSE_TRACE_FILE)
367        std::cout << "image::open:  " << name (). full ()
368                  << " refs:" << references_ + 1
369                  << " writable:" << (char*) (writable_ ? "yes" : "no")
370                  << std::endl;
371
372      if (fd_ < 0)
373      {
374        writable = writable_;
375
376        if (writable)
377          fd_ = ::open (path.c_str (), OPEN_FLAGS | O_RDWR | O_CREAT | O_TRUNC, CREATE_MODE);
378        else
379          fd_ = ::open (path.c_str (), OPEN_FLAGS | O_RDONLY);
380        if (fd_ < 0)
381          throw rld::error (::strerror (errno), "open:" + path);
382      }
383      else
384      {
385        if (writable_ != writable)
386          throw rld::error ("Cannot change write status", "open:" + path);
387      }
388
389      ++references_;
390    }
391
392    void
393    image::close ()
394    {
395      if (references_ > 0)
396      {
397        if (rld::verbose () >= RLD_VERBOSE_TRACE_FILE)
398          std::cout << "image::close: " << name ().full ()
399                    << " refs:" << references_ << std::endl;
400
401        --references_;
402        if (references_ == 0)
403        {
404          ::close (fd_);
405          fd_ = -1;
406        }
407      }
408    }
409
410    ssize_t
411    image::read (void* buffer_, size_t size)
412    {
413      uint8_t* buffer = static_cast <uint8_t*> (buffer_);
414      size_t   have_read = 0;
415      size_t   to_read = size;
416      while (have_read < size)
417      {
418        const ssize_t rsize = ::read (fd (), buffer, to_read);
419        if (rsize < 0)
420          throw rld::error (strerror (errno), "read:" + name ().path ());
421        if (rsize == 0)
422          break;
423        have_read += rsize;
424        to_read -= rsize;
425        buffer += rsize;
426      }
427      return have_read;
428    }
429
430    ssize_t
431    image::write (const void* buffer_, size_t size)
432    {
433      const uint8_t* buffer = static_cast <const uint8_t*> (buffer_);
434      size_t         have_written = 0;
435      size_t         to_write = size;
436      while (have_written < size)
437      {
438        const ssize_t wsize = ::write (fd (), buffer, to_write);
439        if (wsize < 0)
440          throw rld::error (strerror (errno), "write:" + name ().path ());
441        have_written += wsize;
442        to_write -= wsize;
443        buffer += wsize;
444      }
445      return have_written;
446    }
447
448    void
449    image::seek (off_t offset)
450    {
451      if (::lseek (fd (), name_.offset () + offset, SEEK_SET) < 0)
452        throw rld::error (strerror (errno), "lseek:" + name ().path ());
453    }
454
455    bool
456    image::seek_read (off_t offset, uint8_t* buffer, size_t size)
457    {
458      seek (offset);
459      return size == (size_t) read (buffer, size);
460    }
461
462    bool
463    image::seek_write (off_t offset, const void* buffer, size_t size)
464    {
465      seek (offset);
466      return size == (size_t) write (buffer, size);
467    }
468
469    const file&
470    image::name () const
471    {
472      return name_;
473    }
474
475    int
476    image::references () const
477    {
478      return references_;
479    }
480
481    size_t
482    image::size () const
483    {
484      return name ().size ();
485    }
486
487    int
488    image::fd () const
489    {
490      return fd_;
491    }
492
493    rld::elf::file&
494    image::elf ()
495    {
496      return elf_;
497    }
498
499    void
500    image::symbol_referenced ()
501    {
502      ++symbol_refs;
503    }
504
505    int
506    image::symbol_references () const
507    {
508      return symbol_refs;
509    }
510
511    void
512    copy_file (image& in, image& out, size_t size)
513    {
514      #define COPY_FILE_BUFFER_SIZE (8 * 1024)
515      uint8_t* buffer = 0;
516
517      if (size == 0)
518        size = in.name ().size ();
519
520      try
521      {
522        buffer = new uint8_t[COPY_FILE_BUFFER_SIZE];
523        while (size)
524        {
525          /*
526           * @fixme the reading and writing are not POSIX; sigints could split them.
527           */
528
529          size_t l = size < COPY_FILE_BUFFER_SIZE ? size : COPY_FILE_BUFFER_SIZE;
530          ssize_t r = ::read (in.fd (), buffer, l);
531
532          if (r < 0)
533            throw rld::error (::strerror (errno), "reading: " + in.name ().full ());
534
535          if (r == 0)
536          {
537            std::ostringstream oss;
538            oss << "reading: " + in.name ().full () << " (" << size << ')';
539            throw rld::error ("input too short", oss.str ());
540          }
541
542          ssize_t w = ::write (out.fd (), buffer, r);
543
544          if (w < 0)
545            throw rld::error (::strerror (errno), "writing: " + out.name ().full ());
546
547          if (w != r)
548            throw rld::error ("output trucated", "writing: " + out.name ().full ());
549
550          size -= r;
551        }
552      }
553      catch (...)
554      {
555        delete [] buffer;
556        throw;
557      }
558
559      if (buffer)
560        delete [] buffer;
561    }
562
563    /**
564     * Defines for the header of an archive.
565     */
566    #define rld_archive_ident         "!<arch>\n"
567    #define rld_archive_ident_size    (sizeof (rld_archive_ident) - 1)
568    #define rld_archive_fhdr_base     rld_archive_ident_size
569    #define rld_archive_fname         (0)
570    #define rld_archive_fname_size    (16)
571    #define rld_archive_mtime         (16)
572    #define rld_archive_mtime_size    (12)
573    #define rld_archive_uid           (28)
574    #define rld_archive_uid_size      (6)
575    #define rld_archive_gid           (34)
576    #define rld_archive_gid_size      (6)
577    #define rld_archive_mode          (40)
578    #define rld_archive_mode_size     (8)
579    #define rld_archive_size          (48)
580    #define rld_archive_size_size     (10)
581    #define rld_archive_magic         (58)
582    #define rld_archive_magic_size    (2)
583    #define rld_archive_fhdr_size     (60)
584    #define rld_archive_max_file_size (1024)
585
586    archive::archive (const std::string& path)
587      : image (path, false)
588    {
589      if (!name ().is_valid ())
590        throw rld_error_at ("name is empty");
591      if (!name ().is_archive ())
592        throw rld_error_at ("name is not an archive: " + name ().oname ());
593    }
594
595    archive::~archive ()
596    {
597      end ();
598      close ();
599    }
600
601    void
602    archive::begin ()
603    {
604      if (references () == 1)
605      {
606        elf ().begin (name ().full (), fd ());
607
608        /*
609         * Make sure it is an archive.
610         */
611        if (!elf ().is_archive ())
612          throw rld::error ("Not an archive.",
613                            "archive-begin:" + name ().full ());
614      }
615    }
616
617    void
618    archive::end ()
619    {
620      if (references () == 1)
621        elf ().end ();
622    }
623
624    bool
625    archive::is (const std::string& path) const
626    {
627      return name ().path () == path;
628    }
629
630    bool
631    archive::is_valid ()
632    {
633      open ();
634      uint8_t header[rld_archive_ident_size];
635      seek_read (0, &header[0], rld_archive_ident_size);
636      bool result = ::memcmp (header, rld_archive_ident,
637                              rld_archive_ident_size) == 0 ? true : false;
638      close ();
639      return result;
640    }
641
642    void
643    archive::load_objects (objects& objs)
644    {
645      off_t extended_file_names = 0;
646      off_t offset = rld_archive_fhdr_base;
647      size_t size = 0;
648
649      while (true)
650      {
651        uint8_t header[rld_archive_fhdr_size];
652
653        if (!read_header (offset, &header[0]))
654          break;
655
656        /*
657         * The archive file headers are always aligned to an even address.
658         */
659        size =
660          (scan_decimal (&header[rld_archive_size],
661                         rld_archive_size_size) + 1) & ~1;
662
663        /*
664         * Check for the GNU extensions.
665         */
666        if (header[0] == '/')
667        {
668          off_t extended_off;
669
670          switch (header[1])
671          {
672            case ' ':
673              /*
674               * Symbols table. Ignore the table.
675               */
676              break;
677            case '/':
678              /*
679               * Extended file names table. Remember.
680               */
681              extended_file_names = offset + rld_archive_fhdr_size;
682              break;
683            case '0':
684            case '1':
685            case '2':
686            case '3':
687            case '4':
688            case '5':
689            case '6':
690            case '7':
691            case '8':
692            case '9':
693              /*
694               * Offset into the extended file name table. If we do not have the
695               * offset to the extended file name table find it.
696               */
697              extended_off = scan_decimal (&header[1], rld_archive_fname_size);
698
699              if (extended_file_names == 0)
700              {
701                off_t off = offset;
702                while (extended_file_names == 0)
703                {
704                  size_t esize =
705                    (scan_decimal (&header[rld_archive_size],
706                                   rld_archive_size_size) + 1) & ~1;
707                  off += esize + rld_archive_fhdr_size;
708
709                  if (!read_header (off, &header[0]))
710                    throw rld::error ("No GNU extended file name section found",
711                                      "get-names:" + name ().path ());
712
713                  if ((header[0] == '/') && (header[1] == '/'))
714                  {
715                    extended_file_names = off + rld_archive_fhdr_size;
716                    break;
717                  }
718                }
719              }
720
721              if (extended_file_names)
722              {
723                /*
724                 * We know the offset in the archive to the extended file. Read
725                 * the name from the table and compare with the name we are
726                 * after.
727                 */
728                char cname[rld_archive_max_file_size];
729                seek_read (extended_file_names + extended_off,
730                           (uint8_t*) &cname[0], rld_archive_max_file_size);
731                add_object (objs, cname,
732                            offset + rld_archive_fhdr_size, size);
733              }
734              break;
735            default:
736              /*
737               * Ignore the file because we do not know what it it.
738               */
739              break;
740          }
741        }
742        else
743        {
744          /*
745           * Normal archive name.
746           */
747          add_object (objs,
748                      (char*) &header[rld_archive_fname],
749                      offset + rld_archive_fhdr_size, size);
750        }
751
752        offset += size + rld_archive_fhdr_size;
753      }
754    }
755
756    bool
757    archive::operator< (const archive& rhs) const
758    {
759      return name ().path () < rhs.name ().path ();
760    }
761
762    bool
763    archive::read_header (off_t offset, uint8_t* header)
764    {
765      if (!seek_read (offset, header, rld_archive_fhdr_size))
766        return false;
767
768      if ((header[rld_archive_magic] != 0x60) ||
769          (header[rld_archive_magic + 1] != 0x0a))
770        throw rld::error ("Invalid header magic numbers at " +
771                          rld::to_string (offset), "read-header:" + name ().path ());
772
773      return true;
774    }
775
776    void
777    archive::add_object (objects& objs, const char* path, off_t offset, size_t size)
778    {
779      const char* end = path;
780      while ((*end != '\0') && (*end != '/') && (*end != '\n'))
781        ++end;
782
783      std::string str;
784      str.append (path, end - path);
785
786      if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
787        std::cout << "archive::add-object: " << str << std::endl;
788
789      file n (name ().path (), str, offset, size);
790      objs[n.full()] = new object (*this, n);
791    }
792
793    void
794    archive::write_header (const std::string& name,
795                           uint32_t           mtime,
796                           int                uid,
797                           int                gid,
798                           int                mode,
799                           size_t             size)
800    {
801        uint8_t header[rld_archive_fhdr_size];
802
803        memset (header, ' ', sizeof (header));
804
805        size_t len = name.length ();
806        if (len > rld_archive_fname_size)
807          len = rld_archive_fname_size;
808        memcpy (&header[rld_archive_fname], &name[0], len);
809
810        set_number (mtime, header + rld_archive_mtime, rld_archive_mtime_size);
811        set_number (uid, header + rld_archive_uid, rld_archive_uid_size);
812        set_number (gid, header + rld_archive_gid, rld_archive_gid_size);
813        set_number (mode, header + rld_archive_mode, rld_archive_mode_size, true);
814        set_number (size, header + rld_archive_size, rld_archive_size_size);
815
816        header[rld_archive_magic] = 0x60;
817        header[rld_archive_magic + 1] = 0x0a;
818
819        write (header, sizeof (header));
820    }
821
822    void
823    archive::create (object_list& objects)
824    {
825      if (rld::verbose () >= RLD_VERBOSE_DETAILS)
826        std::cout << "archive::create: " << name ().full ()
827                  << ", objects: " << objects.size () << std::endl;
828
829      open (true);
830
831      try
832      {
833        seek_write (0, rld_archive_ident, rld_archive_ident_size);
834
835        /*
836         * GNU extended filenames.
837         */
838        std::string extended_file_names;
839
840        for (object_list::iterator oi = objects.begin ();
841             oi != objects.end ();
842             ++oi)
843        {
844          object& obj = *(*oi);
845          const std::string&  oname = basename (obj.name ().oname ());
846          if (oname.length () >= rld_archive_fname_size)
847            extended_file_names += oname + '\n';
848        }
849
850        if (!extended_file_names.empty ())
851        {
852          if (extended_file_names.length () & 1)
853          {
854            extended_file_names += ' ';
855          }
856          write_header ("//", 0, 0, 0, 0, extended_file_names.length ());
857          write (extended_file_names.c_str (), extended_file_names.length ());
858        }
859
860        for (object_list::iterator oi = objects.begin ();
861             oi != objects.end ();
862             ++oi)
863        {
864          object& obj = *(*oi);
865
866          obj.open ();
867
868          try
869          {
870            std::string oname = basename (obj.name ().oname ());
871
872            /*
873             * Convert the file name to an offset into the extended file name
874             * table if the file name is too long for the header.
875             */
876
877            if (oname.length () >= rld_archive_fname_size)
878            {
879              size_t pos = extended_file_names.find (oname + '\n');
880              if (pos == std::string::npos)
881                throw rld_error_at ("extended file name not found");
882              std::ostringstream oss;
883              oss << '/' << pos;
884              oname = oss.str ();
885            }
886            else oname += '/';
887
888            write_header (oname, 0, 0, 0, 0666, (obj.name ().size () + 1) & ~1);
889            obj.seek (0);
890            copy_file (obj, *this);
891            if (obj.name ().size () & 1)
892              write ("\n", 1);
893          }
894          catch (...)
895          {
896            obj.close ();
897            throw;
898          }
899
900          obj.close ();
901        }
902      }
903      catch (...)
904      {
905        close ();
906        throw;
907      }
908
909      close ();
910    }
911
912    relocation::relocation (const elf::relocation& er)
913      : offset (er.offset ()),
914        type (er.type ()),
915        info (er.info ()),
916        addend (er.addend ()),
917        symname (er.symbol ().name ()),
918        symtype (er.symbol ().type ()),
919        symsect (er.symbol ().section_index ()),
920        symvalue (er.symbol ().value ()),
921        symbinding (er.symbol ().binding ())
922    {
923    }
924
925    section::section (const elf::section& es)
926      : name (es.name ()),
927        index (es.index ()),
928        type (es.type ()),
929        size (es.size ()),
930        alignment (es.alignment ()),
931        link (es.link ()),
932        info (es.info ()),
933        flags (es.flags ()),
934        offset (es.offset ()),
935        rela (es.get_reloc_type ())
936    {
937    }
938
939    void
940    section::load_relocations (const elf::section& es)
941    {
942      const elf::relocations& es_relocs = es.get_relocations ();
943      for (elf::relocations::const_iterator ri = es_relocs.begin ();
944           ri != es_relocs.end ();
945           ++ri)
946      {
947        relocs.push_back (relocation (*ri));
948      }
949      rela = es.get_reloc_type ();
950    }
951
952    size_t
953    sum_sizes (const sections& secs)
954    {
955      size_t size = 0;
956
957      for (sections::const_iterator si = secs.begin ();
958           si != secs.end ();
959           ++si)
960      {
961        const section& sec = *si;
962
963        if ((size % sec.alignment) != 0)
964          size -= (size % sec.alignment) + sec.alignment;
965        size += sec.size;
966      }
967
968      return size;
969    }
970
971    const section*
972    find (const sections& secs, const int index)
973    {
974      for (sections::const_iterator si = secs.begin ();
975           si != secs.end ();
976           ++si)
977      {
978        const section& sec = *si;
979
980        if (index == sec.index)
981          return &sec;
982      }
983
984      return 0;
985    }
986
987    object::object (archive& archive_, file& name_)
988      : image (name_),
989        archive_ (&archive_),
990        valid_ (false),
991        resolving_ (false),
992        resolved_ (false)
993    {
994      if (!name ().is_valid ())
995        throw rld_error_at ("name is empty");
996    }
997
998    object::object (const std::string& path)
999      : image (path),
1000        archive_ (0),
1001        valid_ (false),
1002        resolving_ (false),
1003        resolved_ (false)
1004    {
1005      if (!name ().is_valid ())
1006        throw rld_error_at ("name is empty");
1007    }
1008
1009    object::object ()
1010      : archive_ (0),
1011        valid_ (false),
1012        resolving_ (false),
1013        resolved_ (false)
1014    {
1015    }
1016
1017    object::~object ()
1018    {
1019      end ();
1020      close ();
1021    }
1022
1023    void
1024    object::open (bool writable)
1025    {
1026      if (archive_)
1027      {
1028        if (writable)
1029          throw rld_error_at ("object files in archives are not writable");
1030        archive_->open ();
1031      }
1032      else
1033        image::open (writable);
1034    }
1035
1036    void
1037    object::close ()
1038    {
1039      if (archive_)
1040      {
1041        archive_->end ();
1042        archive_->close ();
1043      }
1044      else
1045      {
1046        end ();
1047        image::close ();
1048      }
1049    }
1050
1051    void
1052    object::begin ()
1053    {
1054      /*
1055       * Begin a session.
1056       */
1057
1058      if (rld::verbose () >= RLD_VERBOSE_TRACE_FILE)
1059        std::cout << "object:begin: " << name ().full () << " in-archive:"
1060                  << ((char*) (archive_ ? "yes" : "no")) << std::endl;
1061
1062      if (archive_)
1063        elf ().begin (name ().full (), archive_->elf(), name ().offset ());
1064      else
1065        elf ().begin (name ().full (), fd (), is_writable ());
1066
1067      /*
1068       * Cannot be an archive.
1069       */
1070      if (elf ().is_archive ())
1071        throw rld::error ("Is an archive not an object file.",
1072                          "object-begin:" + name ().full ());
1073
1074      /*
1075       * We only support executable or relocatable ELF files.
1076       */
1077      if (!is_writable ())
1078      {
1079        if (!elf ().is_executable () && !elf ().is_relocatable ())
1080          throw rld::error ("Invalid ELF type (only ET_EXEC/ET_REL supported).",
1081                            "object-begin:" + name ().full ());
1082
1083        elf::check_file (elf ());
1084
1085        /**
1086         * We assume the ELF file is invariant over the linking process.
1087         */
1088
1089        if (secs.empty ())
1090        {
1091          elf::sections elf_secs;
1092
1093          elf ().get_sections (elf_secs, 0);
1094
1095          for (elf::sections::const_iterator esi = elf_secs.begin ();
1096               esi != elf_secs.end ();
1097               ++esi)
1098          {
1099            secs.push_back (section (*(*esi)));
1100          }
1101        }
1102      }
1103
1104      /*
1105       * This is a valid object file. The file format checks out.
1106       */
1107      valid_ = true;
1108    }
1109
1110    void
1111    object::end ()
1112    {
1113      if (rld::verbose () >= RLD_VERBOSE_TRACE_FILE)
1114        std::cout << "object:end: " << name ().full () << std::endl;
1115
1116      elf ().end ();
1117    }
1118
1119    bool
1120    object::valid () const
1121    {
1122      return valid_;
1123    }
1124
1125    void
1126    object::load_symbols (rld::symbols::table& symbols, bool local)
1127    {
1128      if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
1129        std::cout << "object:load-sym: " << name ().full () << std::endl;
1130
1131      rld::symbols::pointers syms;
1132
1133      elf ().get_symbols (syms, false, local, false, true);
1134
1135      if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
1136        std::cout << "object:load-sym: exported: total "
1137                  << syms.size () << std::endl;
1138
1139      for (symbols::pointers::iterator si = syms.begin ();
1140           si != syms.end ();
1141           ++si)
1142      {
1143        symbols::symbol& sym = *(*si);
1144
1145        if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
1146          std::cout << "object:load-sym: exported: " << sym << std::endl;
1147
1148        sym.set_object (*this);
1149        symbols.add_external (sym);
1150        externals.push_back (&sym);
1151      }
1152
1153      elf ().get_symbols (syms, false, false, true, false);
1154
1155      if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
1156        std::cout << "object:load-sym: weak: total "
1157                  << syms.size () << std::endl;
1158
1159      for (symbols::pointers::iterator si = syms.begin ();
1160           si != syms.end ();
1161           ++si)
1162      {
1163        symbols::symbol& sym = *(*si);
1164
1165        if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
1166          std::cout << "object:load-sym: weak: " << sym << std::endl;
1167
1168        sym.set_object (*this);
1169        symbols.add_weak (sym);
1170        externals.push_back (&sym);
1171      }
1172
1173      elf ().get_symbols (syms, true, false, true, true);
1174
1175      if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
1176        std::cout << "object:load-sym: unresolved: total "
1177                  << syms.size () << std::endl;
1178
1179      for (symbols::pointers::iterator si = syms.begin ();
1180           si != syms.end ();
1181           ++si)
1182      {
1183        symbols::symbol& sym = *(*si);
1184
1185        if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
1186        {
1187          std::cout << "object:load-sym: unresolved: ";
1188          sym.output (std::cout);
1189          std::cout << std::endl;
1190        }
1191
1192        unresolved[sym.name ()] = &sym;
1193      }
1194    }
1195
1196    void
1197    object::load_relocations ()
1198    {
1199      if (rld::verbose () >= RLD_VERBOSE_TRACE)
1200        std::cout << "object:load-relocs: " << name ().full () << std::endl;
1201
1202      elf ().load_relocations ();
1203
1204      for (sections::iterator si = secs.begin ();
1205           si != secs.end ();
1206           ++si)
1207      {
1208        section&            sec = *si;
1209        const elf::section& elf_sec = elf ().get_section (sec.index);
1210        sec.load_relocations (elf_sec);
1211      }
1212    }
1213
1214    int
1215    object::references () const
1216    {
1217      if (archive_)
1218        return archive_->references ();
1219      return image::references ();
1220    }
1221
1222    size_t
1223    object::size () const
1224    {
1225      if (archive_)
1226        return archive_->size ();
1227      return image::size ();
1228    }
1229
1230    int
1231    object::fd () const
1232    {
1233      if (archive_)
1234        return archive_->fd ();
1235      return image::fd ();
1236    }
1237
1238    void
1239    object::symbol_referenced ()
1240    {
1241      image::symbol_referenced ();
1242      if (archive_)
1243        archive_->symbol_referenced ();
1244    }
1245
1246    archive*
1247    object::get_archive ()
1248    {
1249      return archive_;
1250    }
1251
1252    rld::symbols::symtab&
1253    object::unresolved_symbols ()
1254    {
1255      return unresolved;
1256    }
1257
1258    rld::symbols::pointers&
1259    object::external_symbols ()
1260    {
1261      return externals;
1262    }
1263
1264    void
1265    object::get_sections (sections& filtered_secs,
1266                          uint32_t  type,
1267                          uint64_t  flags_in,
1268                          uint64_t  flags_out)
1269    {
1270      for (sections::const_iterator si = secs.begin ();
1271           si != secs.end ();
1272           ++si)
1273      {
1274        const section& sec = *si;
1275        if ((type == 0) || (type == sec.type))
1276        {
1277          if ((flags_in == 0) ||
1278              (((sec.flags & flags_in) == flags_in) &&
1279               ((sec.flags & flags_out) == 0)))
1280          {
1281            filtered_secs.push_back (sec);
1282          }
1283        }
1284      }
1285    }
1286
1287    void
1288    object::get_sections (sections& filtered_secs, const std::string& matching_name)
1289    {
1290      for (sections::const_iterator si = secs.begin ();
1291           si != secs.end ();
1292           ++si)
1293      {
1294        const section& sec = *si;
1295        if (sec.name == matching_name)
1296        {
1297          filtered_secs.push_back (sec);
1298        }
1299      }
1300    }
1301
1302    const section&
1303    object::get_section (int index) const
1304    {
1305      for (sections::const_iterator si = secs.begin ();
1306           si != secs.end ();
1307           ++si)
1308      {
1309        const section& sec = *si;
1310        if (sec.index == index)
1311          return sec;
1312      }
1313
1314      throw rld::error ("Section index '" + rld::to_string (index) +
1315                        "' not found: " + name ().full (), "object::get-section");
1316    }
1317
1318    void
1319    object::resolve_set ()
1320    {
1321      resolving_ = true;
1322    }
1323
1324    void
1325    object::resolve_clear ()
1326    {
1327      resolving_ = false;
1328    }
1329
1330    bool
1331    object::resolving () const
1332    {
1333      return resolving_;
1334    }
1335
1336    void
1337    object::resolved_set ()
1338    {
1339      resolved_ = true;
1340    }
1341
1342    bool
1343    object::resolved () const
1344    {
1345      return resolved_;
1346    }
1347
1348    cache::cache ()
1349      : opened (false)
1350    {
1351    }
1352
1353    cache::~cache ()
1354    {
1355      close ();
1356    }
1357
1358    void
1359    cache::open ()
1360    {
1361      if (!opened)
1362      {
1363        collect_object_files ();
1364        archives_begin ();
1365        opened = true;
1366      }
1367    }
1368
1369    void
1370    cache::close ()
1371    {
1372      if (opened)
1373      {
1374        /*
1375         * Must delete the object first as they could depend on archives.
1376         */
1377        for (objects::iterator oi = objects_.begin (); oi != objects_.end (); ++oi)
1378          delete (*oi).second;
1379        for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai)
1380          delete (*ai).second;
1381        opened = false;
1382      }
1383    }
1384
1385    void
1386    cache::add (const std::string& path)
1387    {
1388        paths_.push_back (path);
1389        input (path);
1390    }
1391
1392    void
1393    cache::add (paths& paths__)
1394    {
1395      for (paths::iterator pi = paths__.begin();
1396           pi != paths__.end();
1397           ++pi)
1398        add (*pi);
1399    }
1400
1401    void
1402    cache::add_libraries (paths& paths__)
1403    {
1404      for (paths::iterator pi = paths__.begin();
1405           pi != paths__.end();
1406           ++pi)
1407        input (*pi);
1408    }
1409
1410    void
1411    cache::archive_begin (const std::string& path)
1412    {
1413      archives::iterator ai = archives_.find (path);
1414      if (ai != archives_.end ())
1415      {
1416        archive* ar = (*ai).second;
1417        if (!ar->is_open ())
1418        {
1419          if (rld::verbose () >= RLD_VERBOSE_TRACE)
1420            std::cout << "cache:archive-begin: " << path << std::endl;
1421          ar->open ();
1422          ar->begin ();
1423        }
1424      }
1425    }
1426
1427    void
1428    cache::archive_end (const std::string& path)
1429    {
1430      archives::iterator ai = archives_.find (path);
1431      if (ai != archives_.end ())
1432      {
1433        archive* ar = (*ai).second;
1434        if (ar->is_open ())
1435        {
1436          if (rld::verbose () >= RLD_VERBOSE_TRACE)
1437            std::cout << "cache:archive-end: " << path << std::endl;
1438          ar->end ();
1439          ar->close ();
1440        }
1441      }
1442    }
1443
1444    void
1445    cache::archives_begin ()
1446    {
1447      for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai)
1448        archive_begin (((*ai).second)->path ());
1449    }
1450
1451    void
1452    cache::archives_end ()
1453    {
1454      for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai)
1455        archive_end (((*ai).second)->path ());
1456    }
1457
1458    void
1459    cache::collect_object_files ()
1460    {
1461      for (paths::iterator ni = paths_.begin (); ni != paths_.end (); ++ni)
1462        collect_object_files (*ni);
1463    }
1464
1465    void
1466    cache::collect_object_files (const std::string& path)
1467    {
1468      archive* ar = new archive (path);
1469
1470      if (ar->is_valid ())
1471      {
1472        try
1473        {
1474          ar->open ();
1475          ar->load_objects (objects_);
1476          ar->close ();
1477          archives_[path] = ar;
1478        }
1479        catch (...)
1480        {
1481          delete ar;
1482          throw;
1483        }
1484      }
1485      else
1486      {
1487        delete ar;
1488        object* obj = new object (path);
1489        if (!obj->name ().exists ())
1490        {
1491          delete obj;
1492          throw rld::error ("'" + path + "', Not found or a regular file.",
1493                            "file-check");
1494        }
1495        try
1496        {
1497          obj->open ();
1498          obj->begin ();
1499          obj->end ();
1500          obj->close ();
1501          objects_[path] = obj;
1502        }
1503        catch (...)
1504        {
1505          delete obj;
1506          throw;
1507        }
1508      }
1509    }
1510
1511    void
1512    cache::load_symbols (rld::symbols::table& symbols, bool local)
1513    {
1514      if (rld::verbose () >= RLD_VERBOSE_INFO)
1515        std::cout << "cache:load-sym: object files: " << objects_.size ()
1516                  << std::endl;
1517
1518      for (objects::iterator oi = objects_.begin ();
1519           oi != objects_.end ();
1520           ++oi)
1521      {
1522        object* obj = (*oi).second;
1523        obj->open ();
1524        obj->begin ();
1525        obj->load_symbols (symbols, local);
1526        obj->end ();
1527        obj->close ();
1528      }
1529
1530      if (rld::verbose () >= RLD_VERBOSE_INFO)
1531        std::cout << "cache:load-sym: symbols: " << symbols.size ()
1532                  << std::endl;
1533    }
1534
1535    void
1536    cache::output_unresolved_symbols (std::ostream& out)
1537    {
1538      for (objects::iterator oi = objects_.begin ();
1539           oi != objects_.end ();
1540           ++oi)
1541      {
1542        object* obj = (*oi).second;
1543        if (obj)
1544        {
1545          out << obj->name ().full () << ':' << std::endl;
1546          rld::symbols::output (out, obj->unresolved_symbols ());
1547        }
1548      }
1549    }
1550
1551    archives&
1552    cache::get_archives ()
1553    {
1554      return archives_;
1555    }
1556
1557    objects&
1558    cache::get_objects ()
1559    {
1560      return objects_;
1561    }
1562
1563    void
1564    cache::get_objects (object_list& list) const
1565    {
1566      list.clear ();
1567      for (paths::const_iterator pi = paths_.begin ();
1568           pi != paths_.end ();
1569           ++pi)
1570      {
1571        objects::const_iterator oi = objects_.find (*pi);
1572        if (oi == objects_.end ())
1573          throw rld_error_at ("path not found in objects");
1574        list.push_back ((*oi).second);
1575      }
1576    }
1577
1578    const paths&
1579    cache::get_paths () const
1580    {
1581      return paths_;
1582    }
1583
1584    int
1585    cache::archive_count () const
1586    {
1587      return archives_.size ();
1588    }
1589
1590    int
1591    cache::object_count () const
1592    {
1593      return objects_.size ();
1594    }
1595
1596    int
1597    cache::path_count () const
1598    {
1599      return paths_.size ();
1600    }
1601
1602    void
1603    cache::get_archive_files (files& afiles)
1604    {
1605      for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai)
1606        afiles.push_back ((*ai).second->name ().full ());
1607    }
1608
1609    void
1610    cache::get_object_files (files& ofiles)
1611    {
1612      for (objects::iterator oi = objects_.begin (); oi != objects_.end (); ++oi)
1613        ofiles.push_back ((*oi).second->name ());
1614    }
1615
1616    void
1617    cache::output_archive_files (std::ostream& out)
1618    {
1619      for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai)
1620        out << ' ' << (*ai).second->name ().full () << std::endl;
1621    }
1622
1623    void
1624    cache::output_object_files (std::ostream& out)
1625    {
1626      for (objects::iterator oi = objects_.begin (); oi != objects_.end (); ++oi)
1627        out << ' ' << (*oi).second->name ().full () << std::endl;
1628    }
1629
1630    void
1631    cache::input (const std::string& path)
1632    {
1633      if (opened)
1634      {
1635        collect_object_files (path);
1636        archive_begin (path);
1637      }
1638    }
1639
1640    void
1641    find_libraries (paths& libraries, paths& libpaths, paths& libs)
1642    {
1643      if (rld::verbose () >= RLD_VERBOSE_INFO)
1644        std::cout << "Finding libraries:." << std::endl;
1645      libraries.clear ();
1646      for (paths::size_type l = 0; l < libs.size (); ++l)
1647      {
1648        std::string lib = "lib" + libs[l] + ".a";
1649        if (rld::verbose () >= RLD_VERBOSE_DETAILS)
1650          std::cout << " searching: " << lib << std::endl;
1651        bool found = false;
1652        for (paths::size_type p = 0; p < libpaths.size (); ++p)
1653        {
1654          std::string plib;
1655          path_join (libpaths[p], lib, plib);
1656          if (rld::verbose () >= RLD_VERBOSE_DETAILS)
1657              std::cout << " checking: " << plib << std::endl;
1658          if (check_file (plib))
1659          {
1660            if (rld::verbose () >= RLD_VERBOSE_INFO)
1661              std::cout << " found: " << plib << std::endl;
1662            libraries.push_back (plib);
1663            found = true;
1664            break;
1665          }
1666        }
1667
1668        if (!found)
1669          throw rld::error ("Not found", lib);
1670      }
1671    }
1672
1673  }
1674}
Note: See TracBrowser for help on using the repository browser.