source: rtems-tools/rtemstoolkit/rld-outputter.cpp @ b249516

4.104.115
Last change on this file since b249516 was 87e0e76, checked in by Chris Johns <chrisj@…>, on 09/13/14 at 02:09:16

Refactor code into the RTEMS Toolkit.

  • Property mode set to 100644
File size: 12.0 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 * @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 <fstream>
30#include <iostream>
31
32#include <errno.h>
33#include <string.h>
34
35#include <rld.h>
36#include <rld-rap.h>
37
38#include <sys/types.h>
39#include <sys/stat.h>
40#include <unistd.h>
41#include "rld-process.h"
42
43namespace rld
44{
45  namespace outputter
46  {
47    int unlink (const char* path)
48    {
49#if _WIN32
50      return ::remove(path);
51#else
52      return ::unlink (path);
53#endif
54    }
55
56    int link (const char* path1, const char* path2)
57    {
58#if _WIN32
59      return ::rename(path1, path2);
60#else
61      return ::link (path1, path2);
62#endif
63    }
64
65    const std::string
66    script_text (const std::string&        entry,
67                 const std::string&        exit,
68                 const files::object_list& dependents,
69                 const files::cache&       cache,
70                 bool                      not_in_archive)
71    {
72      std::ostringstream out;
73      files::object_list objects;
74      files::object_list dep_copy (dependents);
75
76      cache.get_objects (objects);
77      objects.merge (dep_copy);
78      objects.unique ();
79
80      if (rld::verbose () >= RLD_VERBOSE_INFO)
81        std::cout << " E: " << entry << std::endl;
82
83      out << "E: " << entry << std::endl;
84
85      if (!exit.empty ())
86      {
87        if (rld::verbose () >= RLD_VERBOSE_INFO)
88          std::cout << " e: " << exit << std::endl;
89        out << "e: " << exit << std::endl;
90      }
91
92      for (files::object_list::iterator oi = objects.begin ();
93           oi != objects.end ();
94           ++oi)
95      {
96        files::object& obj = *(*oi);
97        std::string    name = obj.name ().basename ();
98
99        if (not_in_archive)
100        {
101          size_t pos = name.find (':');
102          if (pos != std::string::npos)
103            name[pos] = '_';
104          pos = name.find ('@');
105          if (pos != std::string::npos)
106            name = name.substr (0, pos);
107        }
108
109        if (rld::verbose () >= RLD_VERBOSE_INFO)
110          std::cout << " o: " << name << std::endl;
111
112        out << "o:" << name << std::endl;
113
114        symbols::symtab& unresolved = obj.unresolved_symbols ();
115
116        int count = 0;
117        for (symbols::symtab::iterator ursi = unresolved.begin ();
118             ursi != unresolved.begin ();
119             ++ursi)
120        {
121          symbols::symbol& urs = *((*ursi).second);
122
123          ++count;
124
125          if (rld::verbose () >= RLD_VERBOSE_INFO)
126            std::cout << " u: " << count << ':' << urs.name () << std::endl;
127
128          out << " u:" << count << ':' << urs.name () << std::endl;
129        }
130      }
131
132      return out.str ();
133    }
134
135    void
136    metadata_object (files::object&            metadata,
137                     const std::string&        entry,
138                     const std::string&        exit,
139                     const files::object_list& dependents,
140                     const files::cache&       cache)
141    {
142      if (rld::verbose () >= RLD_VERBOSE_INFO)
143        std::cout << "metadata: " << metadata.name ().full () << std::endl;
144
145      const std::string script =
146        script_text (entry, exit, dependents, cache, true);
147
148      metadata.open (true);
149      metadata.begin ();
150
151      elf::file& elf = metadata.elf ();
152
153      elf.set_header (ET_EXEC,
154                      elf::object_class (),
155                      elf::object_datatype (),
156                      elf::object_machine_type ());
157
158      elf::section md (elf,
159                       elf.section_count () + 1,
160                       ".rtemsmd",
161                       SHT_STRTAB,
162                       1,
163                       0,
164                       0,
165                       0,
166                       script.length ());
167
168      md.add_data (ELF_T_BYTE,
169                   1,
170                   script.length (),
171                   (void*) script.c_str ());
172
173      elf.add (md);
174      elf.write ();
175
176      metadata.end ();
177      metadata.close ();
178    }
179
180    void
181    archive (const std::string&        name,
182             const std::string&        entry,
183             const std::string&        exit,
184             const files::object_list& dependents,
185             const files::cache&       cache)
186    {
187      if (rld::verbose () >= RLD_VERBOSE_INFO)
188        std::cout << "outputter:archive: " << name
189                  << ", dependents: " << dependents.size () << std::endl;
190
191      std::string ext = path::extension (name);
192      std::string mdname =
193        name.substr (0, name.length () - ext.length ()) + "-metadata.o";
194
195      files::object metadata (mdname);
196
197      metadata_object (metadata, entry, exit, dependents, cache);
198
199      files::object_list dep_copy (dependents);
200      files::object_list objects;
201
202      cache.get_objects (objects);
203      objects.merge (dep_copy);
204      objects.push_front (&metadata);
205      objects.unique ();
206
207      files::archive arch (name);
208      arch.create (objects);
209    }
210
211    void
212    archivera (const std::string&        name,
213               const files::object_list& dependents,
214               files::cache&             cache,
215               bool                      ra_exist,
216               bool                      ra_rap)
217    {
218      files::object_list dep_copy (dependents);
219      files::object_list objects;
220
221      if (rld::verbose () >= RLD_VERBOSE_INFO)
222        std::cout << "outputter:archivera: " << name
223                  << ", dependents: " << dependents.size () << std::endl;
224
225      objects.clear ();
226
227      files::object_list::iterator oli;
228      for (oli = dep_copy.begin (); oli != dep_copy.end (); ++oli)
229      {
230        files::object& object = *(*oli);
231
232        if (ra_rap)
233          objects.push_back (&object);
234        else
235        {
236          if (object.get_archive ())
237            objects.push_back (&object);
238        }
239      }
240
241      bool exist = false;
242      files::object_list objects_tmp;
243      files::objects& objs = cache.get_objects ();
244      objects_tmp.clear ();
245      for (files::objects::iterator obi = objs.begin ();
246           obi != objs.end ();
247           ++obi)
248      {
249        files::object* obj = (*obi).second;
250        exist = false;
251
252        /**
253         * Replace the elf object file in ra file with elf object file
254         * in collected object files, if exist.
255         */
256        if (!ra_rap)
257        {
258          for (oli = objects.begin (); oli != objects.end (); ++oli)
259          {
260            files::object& object = *(*oli);
261            if (obj->name ().oname () == object.name ().oname ())
262            {
263              exist = true;
264              break;
265            }
266          }
267        }
268
269        if (!exist)
270          objects_tmp.push_back (obj);
271      }
272
273      objects.merge (objects_tmp);
274      objects.unique ();
275
276      if (objects.size ())
277      {
278        if (ra_exist)
279        {
280          std::string    new_name = "rld_XXXXXX";
281          files::archive arch (new_name);
282          struct stat    sb;
283
284          arch.create (objects);
285
286          if ((::stat (name.c_str (), &sb) >= 0) && S_ISREG (sb.st_mode))
287          {
288            if (unlink (name.c_str ()) < 0)
289              std::cerr << "error: unlinking temp file: " << name << std::endl;
290          }
291          if (link (new_name.c_str (), name.c_str ()) < 0)
292          {
293            std::cerr << "error: linking temp file: " << name << std::endl;
294          }
295          if ((::stat (new_name.c_str (), &sb) >= 0) && S_ISREG (sb.st_mode))
296          {
297            if (unlink (new_name.c_str ()) < 0)
298              std::cerr << "error: unlinking temp file: " << new_name << std::endl;
299          }
300        }
301        else
302        {
303          /* Create */
304          files::archive arch (name);
305          arch.create (objects);
306        }
307      }
308    }
309
310    void
311    script (const std::string&        name,
312            const std::string&        entry,
313            const std::string&        exit,
314            const files::object_list& dependents,
315            const files::cache&       cache)
316    {
317      if (rld::verbose () >= RLD_VERBOSE_INFO)
318        std::cout << "outputter:script: " << name << std::endl;
319
320      std::fstream out (name.c_str (),
321                        std::ios_base::out | std::ios_base::trunc);
322
323      /*
324       * Tag for the shell to use.
325       */
326      out << "!# rls" << std::endl;
327
328      try
329      {
330        out << script_text (entry, exit, dependents, cache, false);
331      }
332      catch (...)
333      {
334        out.close ();
335        throw;
336      }
337
338      out.close ();
339    }
340
341    void
342    elf_application (const std::string&        name,
343                     const std::string&        entry,
344                     const std::string&        exit,
345                     const files::object_list& dependents,
346                     const files::cache&       cache)
347    {
348      if (rld::verbose () >= RLD_VERBOSE_INFO)
349        std::cout << "outputter:application: " << name << std::endl;
350
351      files::object_list dep_copy (dependents);
352      files::object_list objects;
353      std::string        header;
354      std::string        script;
355      files::image       app (name);
356
357      header = "RELF,00000000,0001,none,00000000\n";
358      header += '\0';
359
360      script = script_text (entry, exit, dependents, cache, true);
361
362      cache.get_objects (objects);
363      objects.merge (dep_copy);
364      objects.unique ();
365
366      app.open (true);
367      app.write (header.c_str (), header.size ());
368
369      #define APP_BUFFER_SIZE  (128 * 1024)
370
371      uint8_t* buffer = 0;
372
373      try
374      {
375        buffer = new uint8_t[APP_BUFFER_SIZE];
376
377        for (files::object_list::iterator oi = objects.begin ();
378             oi != objects.end ();
379             ++oi)
380        {
381          files::object& obj = *(*oi);
382
383          obj.open ();
384
385          try
386          {
387            obj.seek (0);
388
389            size_t in_size = obj.name ().size ();
390
391            while (in_size)
392            {
393              size_t reading =
394                in_size < APP_BUFFER_SIZE ? in_size : APP_BUFFER_SIZE;
395
396              app.write (buffer, obj.read (buffer, reading));
397
398              in_size -= reading;
399            }
400          }
401          catch (...)
402          {
403            obj.close ();
404            throw;
405          }
406
407          obj.close ();
408        }
409      }
410      catch (...)
411      {
412        delete [] buffer;
413        app.close ();
414        throw;
415      }
416
417      delete [] buffer;
418
419      app.close ();
420    }
421
422    bool in_archive (files::object* object)
423    {
424      if (object->get_archive ())
425        return true;
426      return false;
427    }
428
429    void
430    application (const std::string&        name,
431                 const std::string&        entry,
432                 const std::string&        exit,
433                 const files::object_list& dependents,
434                 const files::cache&       cache,
435                 const symbols::table&     symbols,
436                 bool                      one_file)
437    {
438      if (rld::verbose () >= RLD_VERBOSE_INFO)
439        std::cout << "outputter:application: " << name << std::endl;
440
441      files::object_list dep_copy (dependents);
442      files::object_list objects;
443      files::image       app (name);
444
445      if (!one_file)
446        dep_copy.remove_if (in_archive);
447
448      cache.get_objects (objects);
449      objects.merge (dep_copy);
450      objects.sort ();
451      objects.unique ();
452
453      app.open (true);
454
455      try
456      {
457        rap::write (app, entry, exit, objects, symbols);
458      }
459      catch (...)
460      {
461        app.close ();
462        throw;
463      }
464
465      app.close ();
466    }
467
468  }
469}
Note: See TracBrowser for help on using the repository browser.