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

4.104.11
Last change on this file since c46980e was c46980e, checked in by Chris Johns <chrisj@…>, on Nov 21, 2012 at 2:04:47 AM

Add entry point support.

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