source: rtems-tools/linkers/rtems-ld.cpp @ eb34811

4.104.11
Last change on this file since eb34811 was eb34811, checked in by Chris Johns <chrisj@…>, on Nov 21, 2012 at 12:07:12 AM

Output application format files.

Added support for an RTEMS RAP format application file. The format is:

<header>
<LZ77>

<Application Script>
<[1..n] ELF Object files>

</LZ77>

Where the header is a text string of fields delimited by ',' and terminated
with a line feed (\n). It is variable length:

RTEMS-APP,0000000,01.00.00,LZ77,00000000\n\0

where:

RTEMS-APP : file tag for quick acceptance and rejection
Length : the length of the application in bytes including the

: header

Version : Version of the application format.
Compress : The compression format.
Checksum : CCITT CRC32 checksum.

Following the header is a nul ('\0') character then an LZ77 container
with the application loader script followed by the ELF object files.

Note, the script format will be documented else where.

Note, the final version may add a 32bit length field before each part
in the compressed container to delimit the size of the file to be
read. This is currently not in this version.

  • Property mode set to 100644
File size: 12.4 KB
Line 
1/*
2 * Copyright (c) 2011-2012, 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_rld
20 *
21 * @brief RTEMS Linker Main manages opions, sequence of operations and exceptions.
22 *
23 */
24
25#if HAVE_CONFIG_H
26#include "config.h"
27#endif
28
29#include <iostream>
30
31#include <cxxabi.h>
32#include <signal.h>
33#include <stdlib.h>
34#include <string.h>
35#include <unistd.h>
36
37#include <getopt.h>
38
39#include <rld.h>
40#include <rld-cc.h>
41#include <rld-outputter.h>
42#include <rld-process.h>
43#include <rld-resolver.h>
44
45#ifndef HAVE_KILL
46#define kill(p,s) raise(s)
47#endif
48
49/**
50 * RTEMS Linker options. This needs to be rewritten to be like cc where only a
51 * single '-' and long options is present.
52 */
53static struct option rld_opts[] = {
54  { "help",        no_argument,            NULL,           'h' },
55  { "version",     no_argument,            NULL,           'V' },
56  { "verbose",     no_argument,            NULL,           'v' },
57  { "warn",        no_argument,            NULL,           'w' },
58  { "map",         no_argument,            NULL,           'M' },
59  { "output",      required_argument,      NULL,           'o' },
60  { "script",      no_argument,            NULL,           'S' },
61  { "lib-path",    required_argument,      NULL,           'L' },
62  { "lib",         required_argument,      NULL,           'l' },
63  { "no-stdlibs",  no_argument,            NULL,           'n' },
64  { "entry",       required_argument,      NULL,           'e' },
65  { "define",      required_argument,      NULL,           'd' },
66  { "undefined",   required_argument,      NULL,           'u' },
67  { "base",        required_argument,      NULL,           'b' },
68  { "cc",          required_argument,      NULL,           'C' },
69  { "exec-prefix", required_argument,      NULL,           'E' },
70  { "march",       required_argument,      NULL,           'a' },
71  { "mcpu",        required_argument,      NULL,           'c' },
72  { NULL,          0,                      NULL,            0 }
73};
74
75#if TO_BE_USED_FOR_THE_UNDEFINES
76void
77split_on_equals (const std::string& opt, std::string& left, std::string& right)
78{
79  std::string::size_type eq = opt.find_first_of('=');
80}
81#endif
82
83void
84usage (int exit_code)
85{
86  std::cout << "rtems-ld [options] objects" << std::endl
87            << "Options and arguments:" << std::endl
88            << " -h        : help (also --help)" << std::endl
89            << " -V        : print linker version number and exit (also --version)" << std::endl
90            << " -v        : verbose (trace import parts), can be supply multiple times" << std::endl
91            << "             to increase verbosity (also --verbose)" << std::endl
92            << " -w        : generate warnings (also --warn)" << std::endl
93            << " -M        : generate map output (also --map)" << std::endl
94            << " -o file   : linker output is written to file (also --output)" << std::endl
95            << " -S        : linker output is a script file (also --script)" << std::endl
96            << " -L path   : path to a library, add multiple for more than" << std::endl
97            << "             one path (also --lib-path)" << std::endl
98            << " -l lib    : add lib to the libraries searched, add multiple" << std::endl
99            << "             for more than one library (also --lib)" << std::endl
100            << " -n        : do not search standard libraries (also --no-stdlibs)" << std::endl
101            << " -e entry  : entry point symbol (also --entry)" << std::endl
102            << " -d sym    : add the symbol definition, add multiple with" << std::endl
103            << "             more than one define (also --define)" << std::endl
104            << " -u sym    : add the undefined symbol definition, add multiple" << std::endl
105            << "             for more than one undefined symbol (also --undefined)" << std::endl
106            << " -b elf    : read the ELF file symbols as the base RTEMS kernel" << std::endl
107            << "             image (also --base)" << std::endl
108            << " -C file   : execute file as the target C compiler (also --cc)" << std::endl
109            << " -E prefix : the RTEMS tool prefix (also --exec-prefix)" << std::endl
110            << " -a march  : machine architecture (also --march)" << std::endl
111            << " -c cpu    : machine architecture's CPU (also --mcpu)" << std::endl;
112  ::exit (exit_code);
113}
114
115static void
116fatal_signal (int signum)
117{
118  signal (signum, SIG_DFL);
119
120  rld::process::temporaries.clean_up ();
121
122  /*
123   * Get the same signal again, this time not handled, so its normal effect
124   * occurs.
125   */
126  kill (getpid (), signum);
127}
128
129static void
130setup_signals (void)
131{
132  if (signal (SIGINT, SIG_IGN) != SIG_IGN)
133    signal (SIGINT, fatal_signal);
134#ifdef SIGHUP
135  if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
136    signal (SIGHUP, fatal_signal);
137#endif
138  if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
139    signal (SIGTERM, fatal_signal);
140#ifdef SIGPIPE
141  if (signal (SIGPIPE, SIG_IGN) != SIG_IGN)
142    signal (SIGPIPE, fatal_signal);
143#endif
144#ifdef SIGCHLD
145  signal (SIGCHLD, SIG_DFL);
146#endif
147}
148
149int
150main (int argc, char* argv[])
151{
152  int ec = 0;
153
154  setup_signals ();
155
156  try
157  {
158    rld::files::cache    cache;
159    rld::files::cache    base;
160    rld::files::paths    libpaths;
161    rld::files::paths    libs;
162    rld::files::paths    objects;
163    rld::files::paths    libraries;
164    rld::symbols::bucket defines;
165    rld::symbols::bucket undefines;
166    rld::symbols::table  base_symbols;
167    rld::symbols::table  symbols;
168    rld::symbols::table  undefined;
169    std::string          entry;
170    std::string          output = "a.out";
171    std::string          base_name;
172    std::string          cc_name;
173    rld::outputter::type output_type = rld::outputter::ot_application;
174    bool                 standard_libs = true;
175    bool                 exec_prefix_set = false;
176    bool                 map = false;
177    bool                 warnings = false;
178
179    libpaths.push_back (".");
180
181    while (true)
182    {
183      int opt = ::getopt_long (argc, argv, "hvwVMnSb:E:o:L:l:a:c:e:d:u:C:", rld_opts, NULL);
184      if (opt < 0)
185        break;
186
187      switch (opt)
188      {
189        case 'V':
190          std::cout << "rtems-ld (RTEMS Linker) " << rld::version ()
191                    << std::endl;
192          ::exit (0);
193          break;
194
195        case 'v':
196          rld::verbose_inc ();
197          break;
198
199        case 'M':
200          map = true;
201          break;
202
203        case 'w':
204          warnings = true;
205          break;
206
207        case 'o':
208          if (output != "a.out")
209            std::cerr << "warning: output already set" << std::endl;
210          output = optarg;
211          break;
212
213        case 'S':
214          output_type = rld::outputter::ot_script;
215          break;
216
217        case 'l':
218          /*
219           * The order is important. It is the search order.
220           */
221          libs.push_back (optarg);
222          break;
223
224        case 'L':
225          if ((optarg[::strlen (optarg) - 1] == '/') ||
226              (optarg[::strlen (optarg) - 1] == '\\'))
227            optarg[::strlen (optarg) - 1] = '\0';
228          libpaths.push_back (optarg);
229          break;
230
231        case 'n':
232          standard_libs = false;
233          break;
234
235        case 'C':
236          if (exec_prefix_set == true)
237            std::cerr << "warning: exec-prefix ignored when CC provided" << std::endl;
238          rld::cc::cc = optarg;
239          break;
240
241        case 'E':
242          exec_prefix_set = true;
243          rld::cc::exec_prefix = optarg;
244          break;
245
246        case 'a':
247          rld::cc::march = optarg;
248          break;
249
250        case 'c':
251          rld::cc::mcpu = optarg;
252          break;
253
254        case 'e':
255          entry = optarg;
256          break;
257
258        case 'd':
259          defines.push_back (rld::symbols::symbol (optarg));
260          break;
261
262        case 'u':
263          undefines.push_back (rld::symbols::symbol (optarg));
264          break;
265
266        case 'b':
267          base_name = optarg;
268          break;
269
270        case '?':
271          usage (3);
272          break;
273
274        case 'h':
275          usage (0);
276          break;
277      }
278    }
279
280    argc -= optind;
281    argv += optind;
282
283    if (rld::verbose () || map)
284      std::cout << "RTEMS Linker " << rld::version () << std::endl;
285
286    /*
287     * If there are no object files there is nothing to link.
288     */
289    if ((argc == 0) && !map)
290      throw rld::error ("no object files", "options");
291
292    /*
293     * Load the remaining command line arguments into the cache as object
294     * files.
295     */
296    while (argc--)
297      objects.push_back (*argv++);
298
299    /*
300     * Load the symbol table with the defined symbols from the defines bucket.
301     */
302    rld::symbols::load (defines, symbols);
303
304    /*
305     * Load the undefined table with the undefined symbols from the undefines
306     * bucket.
307     */
308    rld::symbols::load (undefines, undefined);
309
310    /*
311     * Add the object files to the cache.
312     */
313    cache.add (objects);
314
315    /*
316     * Open the cache.
317     */
318    cache.open ();
319
320    /*
321     * If the full path to CC is not provided and the exec-prefix is not set by
322     * the command line see if it can be detected from the object file
323     * types. This must be after we have added the object files because they
324     * are used when detecting.
325     */
326    if (rld::cc::cc.empty () && !exec_prefix_set)
327      rld::cc::exec_prefix = rld::elf::machine_type ();
328
329    /*
330     * If we have a base image add it.
331     */
332    if (base_name.length ())
333    {
334      base.open ();
335      base.add (base_name);
336      base.load_symbols (base_symbols, true);
337    }
338
339    /*
340     * Get the standard library paths
341     */
342    if (standard_libs)
343      rld::cc::get_standard_libpaths (libpaths);
344
345    /*
346     * Get the command line libraries.
347     */
348    rld::files::find_libraries (libraries, libpaths, libs);
349
350    /*
351     * Are we to load standard libraries ?
352     */
353    if (standard_libs)
354      rld::cc::get_standard_libs (libraries, libpaths);
355
356    /*
357     * Load the library to the cache.
358     */
359    cache.add_libraries (libraries);
360
361    /*
362     * Load the symbol table.
363     */
364    cache.load_symbols (symbols);
365
366    /*
367     * Map ?
368     */
369    if (map)
370    {
371      if (base_name.length ())
372        rld::map (base, base_symbols);
373      rld::map (cache, symbols);
374    }
375
376    if (cache.path_count ())
377    {
378      /*
379       * This structure allows us to add different operations with the same
380       * structure.
381       */
382      rld::files::object_list dependents;
383      rld::resolver::resolve (dependents, cache, base_symbols, symbols, undefined);
384
385      /**
386       * Output the file.
387       */
388      switch (output_type)
389      {
390        case rld::outputter::ot_script:
391          rld::outputter::script (output, dependents, cache);
392          break;
393        case rld::outputter::ot_archive:
394          rld::outputter::archive (output, dependents, cache);
395          break;
396        case rld::outputter::ot_application:
397          rld::outputter::application (output, dependents, cache);
398          break;
399        default:
400          throw rld::error ("invalid output type", "output");
401      }
402
403      /**
404       * Check for warnings.
405       */
406      if (warnings)
407      {
408        rld::warn_unused_externals (dependents);
409      }
410    }
411  }
412  catch (rld::error re)
413  {
414    std::cerr << "error: "
415              << re.where << ": " << re.what
416              << std::endl;
417    ec = 10;
418  }
419  catch (std::exception e)
420  {
421    int   status;
422    char* realname;
423    realname = abi::__cxa_demangle (e.what(), 0, 0, &status);
424    std::cerr << "error: exception: " << realname << " [";
425    ::free (realname);
426    const std::type_info &ti = typeid (e);
427    realname = abi::__cxa_demangle (ti.name(), 0, 0, &status);
428    std::cerr << realname << "] " << e.what () << std::endl;
429    ::free (realname);
430    ec = 11;
431  }
432  catch (...)
433  {
434    /*
435     * Helps to know if this happens.
436     */
437    std::cout << "error: unhandled exception" << std::endl;
438    ec = 12;
439  }
440
441  return ec;
442}
Note: See TracBrowser for help on using the repository browser.