source: rtems-tools/linkers/rld-outputter.cpp @ 53ed116

4.104.115
Last change on this file since 53ed116 was 53ed116, checked in by Peng Fan <van.freenix@…>, on 08/30/13 at 13:42:58

Implement a new tool 'rtems-ra'

rtems-ra supports converting an elf archive file into a rap archive file.
It also support add, replace and delete rap files from the rap archive
file.

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