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

4.104.11
Last change on this file since c1d1636 was c1d1636, checked in by Chris Johns <chrisj@…>, on Nov 21, 2012 at 1:11:49 AM

Add header to remove warning on Linux.

  • Property mode set to 100644
File size: 9.8 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
37#include "fastlz.h"
38
39namespace rld
40{
41  namespace outputter
42  {
43    const std::string
44    script_text (files::object_list& dependents,
45                 files::cache&       cache)
46    {
47      std::ostringstream out;
48      files::object_list objects;
49
50      /*
51       * The merge removes them from the dependent list.
52       */
53      files::object_list dep_copy (dependents);
54
55      cache.get_objects (objects);
56      objects.merge (dep_copy);
57      objects.unique ();
58
59      for (files::object_list::iterator oi = objects.begin ();
60           oi != objects.end ();
61           ++oi)
62      {
63        files::object& obj = *(*oi);
64
65        if (rld::verbose () >= RLD_VERBOSE_INFO)
66          std::cout << " o: " << obj.name ().full () << std::endl;
67
68        out << "o:" << obj.name ().basename () << std::endl;
69
70        symbols::table& unresolved = obj.unresolved_symbols ();
71
72        int count = 0;
73        for (symbols::table::iterator ursi = unresolved.begin ();
74             ursi != unresolved.begin ();
75             ++ursi)
76        {
77          symbols::symbol& urs = *((*ursi).second);
78
79          ++count;
80
81          if (rld::verbose () >= RLD_VERBOSE_INFO)
82            std::cout << " u: " << count << ':' << urs.name () << std::endl;
83
84          out << " u:" << count << ':' << urs.name () << std::endl;
85        }
86      }
87
88      return out.str ();
89    }
90
91    void
92    metadata_object (files::object&      metadata,
93                     files::object_list& dependents,
94                     files::cache&       cache)
95    {
96      if (rld::verbose () >= RLD_VERBOSE_INFO)
97        std::cout << "metadata: " << metadata.name ().full () << std::endl;
98
99      const std::string script = script_text (dependents, cache);
100
101      metadata.open (true);
102      metadata.begin ();
103
104      elf::file& elf = metadata.elf ();
105
106      elf.set_header (ET_EXEC,
107                      elf::object_class (),
108                      elf::object_datatype (),
109                      elf::object_machine_type ());
110
111      elf::section md (elf,
112                       elf.section_count () + 1,
113                       ".rtemsmd",
114                       SHT_STRTAB,
115                       1,
116                       0,
117                       0,
118                       0,
119                       script.length ());
120
121      md.add_data (ELF_T_BYTE,
122                   1,
123                   script.length (),
124                   (void*) script.c_str ());
125
126      elf.add (md);
127      elf.write ();
128
129      metadata.end ();
130      metadata.close ();
131    }
132
133    void
134    archive (const std::string&  name,
135             files::object_list& dependents,
136             files::cache&       cache)
137    {
138      if (rld::verbose () >= RLD_VERBOSE_INFO)
139        std::cout << "outputter:archive: " << name
140                  << ", dependents: " << dependents.size () << std::endl;
141
142      std::string ext = files::extension (name);
143      std::string mdname =
144        name.substr (0, name.length () - ext.length ()) + "-metadata.o";
145
146      files::object metadata (mdname);
147
148      metadata_object (metadata, dependents, cache);
149
150      /*
151       * The merge removes them from the dependent list.
152       */
153      files::object_list dep_copy (dependents);
154      files::object_list objects;
155
156      cache.get_objects (objects);
157      objects.merge (dep_copy);
158      objects.push_front (&metadata);
159      objects.unique ();
160
161      files::archive arch (name);
162      arch.create (objects);
163    }
164
165    void
166    script (const std::string&  name,
167            files::object_list& dependents,
168            files::cache&       cache)
169    {
170      if (rld::verbose () >= RLD_VERBOSE_INFO)
171        std::cout << "outputter:script: " << name << std::endl;
172
173      std::fstream out (name.c_str (),
174                        std::ios_base::out | std::ios_base::trunc);
175
176      /*
177       * Tag for the shell to use.
178       */
179      out << "!# rls" << std::endl;
180
181      try
182      {
183        out << script_text (dependents, cache);
184      }
185      catch (...)
186      {
187        out.close ();
188        throw;
189      }
190
191      out.close ();
192    }
193
194    /**
195     * Append the output data to the output buffer and if full compress and
196     * write to the output file. If the output buffer is 0 flush the output
197     * buffer.
198     */
199    static void
200    app_write_output (files::image&  out,
201                      const uint8_t* out_buffer,
202                      const size_t   out_buffer_size,
203                      size_t&        out_buffer_level,
204                      const void*    output_,
205                      size_t         outputting,
206                      uint8_t*       compress_buffer,
207                      size_t&        out_total)
208    {
209      const uint8_t* output = static_cast <const uint8_t*> (output_);
210
211      while (outputting)
212      {
213        if (output)
214        {
215          size_t appending;
216
217          if (outputting > (out_buffer_size - out_buffer_level))
218            appending = out_buffer_size - out_buffer_level;
219          else
220            appending = outputting;
221
222          ::memcpy ((void*) (out_buffer + out_buffer_level),
223                    output,
224                    appending);
225
226          out_buffer_level += appending;
227          outputting -= appending;
228        }
229        else
230        {
231          outputting = 0;
232        }
233
234        if (!output || (out_buffer_level >= out_buffer_size))
235        {
236          int writing =
237            ::fastlz_compress (out_buffer, out_buffer_level, compress_buffer);
238
239          out.write (compress_buffer, writing);
240
241          out_total += writing;
242
243          out_buffer_level = 0;
244        }
245      }
246    }
247
248    void
249    application (const std::string&  name,
250                 files::object_list& dependents,
251                 files::cache&       cache)
252    {
253      if (rld::verbose () >= RLD_VERBOSE_INFO)
254        std::cout << "outputter:application: " << name << std::endl;
255
256      files::object_list dep_copy (dependents);
257      files::object_list objects;
258      std::string        header;
259      std::string        script;
260      files::image       app (name);
261
262      header = "RTEMS-APP,00000000,01.00.00,LZ77,00000000\n";
263      header += '\0';
264
265      script = script_text (dependents, cache);
266
267      cache.get_objects (objects);
268      objects.merge (dep_copy);
269      objects.unique ();
270
271      app.open (true);
272      app.write (header.c_str (), header.size ());
273
274      #define INPUT_BUFFER_SIZE  (64 * 1024)
275      #define OUTPUT_BUFFER_SIZE (128 * 1024)
276      #define FASTLZ_BUFFER_SIZE (OUTPUT_BUFFER_SIZE + ((int) (OUTPUT_BUFFER_SIZE * 0.10)))
277
278      uint8_t* in_buffer = 0;
279      uint8_t* out_buffer = 0;
280      uint8_t* compress_buffer = 0;
281      size_t   out_level = 0;
282      size_t   in_total = 0;
283      size_t   out_total = 0;
284
285      try
286      {
287        in_buffer = new uint8_t[INPUT_BUFFER_SIZE];
288        out_buffer = new uint8_t[OUTPUT_BUFFER_SIZE];
289        compress_buffer = new uint8_t[FASTLZ_BUFFER_SIZE];
290
291        app_write_output (app,
292                          out_buffer, OUTPUT_BUFFER_SIZE, out_level,
293                          script.c_str (), script.size (),
294                          compress_buffer,
295                          out_total);
296
297        in_total += script.size ();
298
299        for (files::object_list::iterator oi = objects.begin ();
300             oi != objects.end ();
301             ++oi)
302        {
303          files::object& obj = *(*oi);
304
305          obj.open ();
306
307          try
308          {
309            obj.seek (0);
310
311            size_t in_size = obj.name ().size ();
312
313            while (in_size)
314            {
315              size_t reading =
316                in_size < INPUT_BUFFER_SIZE ? in_size : INPUT_BUFFER_SIZE;
317
318              obj.read (in_buffer, reading);
319
320              app_write_output (app,
321                                out_buffer, OUTPUT_BUFFER_SIZE, out_level,
322                                in_buffer, reading,
323                                compress_buffer,
324                                out_total);
325
326              in_size -= reading;
327              in_total += reading;
328            }
329          }
330          catch (...)
331          {
332            obj.close ();
333            throw;
334          }
335
336          obj.close ();
337        }
338      }
339      catch (...)
340      {
341        delete [] in_buffer;
342        delete [] out_buffer;
343        delete [] compress_buffer;
344        throw;
345      }
346
347      app_write_output (app,
348                        out_buffer, OUTPUT_BUFFER_SIZE, out_level,
349                        0, out_level,
350                        compress_buffer,
351                        out_total);
352
353      app.close ();
354
355      delete [] in_buffer;
356      delete [] out_buffer;
357      delete [] compress_buffer;
358
359      if (rld::verbose () >= RLD_VERBOSE_INFO)
360      {
361        int pcent = (out_total * 100) / in_total;
362        int premand = (((out_total * 1000) + 500) / in_total) % 10;
363        std::cout << "outputter:application: objects: " << objects.size ()
364                  << ", size: " << out_total
365                  << ", compression: " << pcent << '.' << premand << '%'
366                  << std::endl;
367      }
368    }
369
370  }
371}
Note: See TracBrowser for help on using the repository browser.