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

Last change on this file since 3618a62 was 82c8788, checked in by Chris Johns <chrisj@…>, on Apr 14, 2018 at 4:15:07 AM

rtemstoolkit/rtl-file: Remove a file on close if requested

Close #3395

  • Property mode set to 100644
File size: 12.1 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        ::unlink (name.c_str ());
336        throw;
337      }
338
339      out.close ();
340    }
341
342    void
343    elf_application (const std::string&        name,
344                     const std::string&        entry,
345                     const std::string&        exit,
346                     const files::object_list& dependents,
347                     const files::cache&       cache)
348    {
349      if (rld::verbose () >= RLD_VERBOSE_INFO)
350        std::cout << "outputter:application: " << name << std::endl;
351
352      files::object_list dep_copy (dependents);
353      files::object_list objects;
354      std::string        header;
355      std::string        script;
356      files::image       app (name);
357
358      header = "RELF,00000000,0001,none,00000000\n";
359      header += '\0';
360
361      script = script_text (entry, exit, dependents, cache, true);
362
363      cache.get_objects (objects);
364      objects.merge (dep_copy);
365      objects.unique ();
366
367      app.open (true);
368      app.write (header.c_str (), header.size ());
369
370      #define APP_BUFFER_SIZE  (128 * 1024)
371
372      uint8_t* buffer = 0;
373
374      try
375      {
376        buffer = new uint8_t[APP_BUFFER_SIZE];
377
378        for (files::object_list::iterator oi = objects.begin ();
379             oi != objects.end ();
380             ++oi)
381        {
382          files::object& obj = *(*oi);
383
384          obj.open ();
385
386          try
387          {
388            obj.seek (0);
389
390            size_t in_size = obj.name ().size ();
391
392            while (in_size)
393            {
394              size_t reading =
395                in_size < APP_BUFFER_SIZE ? in_size : APP_BUFFER_SIZE;
396
397              app.write (buffer, obj.read (buffer, reading));
398
399              in_size -= reading;
400            }
401          }
402          catch (...)
403          {
404            obj.close ();
405            throw;
406          }
407
408          obj.close ();
409        }
410      }
411      catch (...)
412      {
413        delete [] buffer;
414        app.remove_on_close ();
415        app.close ();
416        throw;
417      }
418
419      delete [] buffer;
420
421      app.close ();
422    }
423
424    bool in_archive (files::object* object)
425    {
426      if (object->get_archive ())
427        return true;
428      return false;
429    }
430
431    void
432    rap_application (const std::string&        name,
433                     const std::string&        entry,
434                     const std::string&        exit,
435                     const files::object_list& dependents,
436                     const files::cache&       cache,
437                     const symbols::table&     symbols,
438                     bool                      one_file)
439    {
440      if (rld::verbose () >= RLD_VERBOSE_INFO)
441        std::cout << "outputter:application: " << name << std::endl;
442
443      files::object_list dep_copy (dependents);
444      files::object_list objects;
445      files::image       app (name);
446
447      if (!one_file)
448        dep_copy.remove_if (in_archive);
449
450      cache.get_objects (objects);
451      objects.merge (dep_copy);
452      objects.sort ();
453      objects.unique ();
454
455      app.open (true);
456
457      try
458      {
459        rap::write (app, entry, exit, objects, symbols);
460      }
461      catch (...)
462      {
463        app.remove_on_close ();
464        app.close ();
465        throw;
466      }
467
468      app.close ();
469    }
470
471  }
472}
Note: See TracBrowser for help on using the repository browser.