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

4.104.115
Last change on this file since cad8b53 was cad8b53, checked in by Chris Johns <chrisj@…>, on 11/26/12 at 00:09:06

Updated to reflect the framework changes.

  • Property mode set to 100644
File size: 14.2 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  { "out-format",  required_argument,      NULL,           'O' },
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            << " -O format : linker output format, default is 'rap' (also --out-format)" << 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            << "Output Formats:" << std::endl
113            << " rap     - RTEMS application (LZ77, single image)" << std::endl
114            << " elf     - ELF application (script, ELF files)" << std::endl
115            << " script  - Script format (list of object files)" << std::endl
116            << " archive - Archive format (collection of ELF files)" << std::endl;
117  ::exit (exit_code);
118}
119
120static void
121fatal_signal (int signum)
122{
123  signal (signum, SIG_DFL);
124
125  rld::process::temporaries.clean_up ();
126
127  /*
128   * Get the same signal again, this time not handled, so its normal effect
129   * occurs.
130   */
131  kill (getpid (), signum);
132}
133
134static void
135setup_signals (void)
136{
137  if (signal (SIGINT, SIG_IGN) != SIG_IGN)
138    signal (SIGINT, fatal_signal);
139#ifdef SIGHUP
140  if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
141    signal (SIGHUP, fatal_signal);
142#endif
143  if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
144    signal (SIGTERM, fatal_signal);
145#ifdef SIGPIPE
146  if (signal (SIGPIPE, SIG_IGN) != SIG_IGN)
147    signal (SIGPIPE, fatal_signal);
148#endif
149#ifdef SIGCHLD
150  signal (SIGCHLD, SIG_DFL);
151#endif
152}
153
154int
155main (int argc, char* argv[])
156{
157  int ec = 0;
158
159  setup_signals ();
160
161  try
162  {
163    rld::files::cache    cache;
164    rld::files::cache    base;
165    rld::files::paths    libpaths;
166    rld::files::paths    libs;
167    rld::files::paths    objects;
168    rld::files::paths    libraries;
169    rld::symbols::bucket defines;
170    rld::symbols::bucket undefines;
171    rld::symbols::table  base_symbols;
172    rld::symbols::table  symbols;
173    rld::symbols::table  undefined;
174    std::string          entry = "rtems";
175    std::string          exit;
176    std::string          output = "a.out";
177    std::string          base_name;
178    std::string          cc_name;
179    std::string          output_type = "rap";
180    bool                 standard_libs = true;
181    bool                 exec_prefix_set = false;
182    bool                 map = false;
183    bool                 warnings = false;
184
185    libpaths.push_back (".");
186
187    while (true)
188    {
189      int opt = ::getopt_long (argc, argv, "hvwVMnb:E:o:O:L:l:a:c:e:d:u:C:", rld_opts, NULL);
190      if (opt < 0)
191        break;
192
193      switch (opt)
194      {
195        case 'V':
196          std::cout << "rtems-ld (RTEMS Linker) " << rld::version ()
197                    << std::endl;
198          ::exit (0);
199          break;
200
201        case 'v':
202          rld::verbose_inc ();
203          break;
204
205        case 'M':
206          map = true;
207          break;
208
209        case 'w':
210          warnings = true;
211          break;
212
213        case 'o':
214          if (output != "a.out")
215            std::cerr << "warning: output already set" << std::endl;
216          output = optarg;
217          break;
218
219        case 'O':
220          output_type = optarg;
221          break;
222
223        case 'l':
224          /*
225           * The order is important. It is the search order.
226           */
227          libs.push_back (optarg);
228          break;
229
230        case 'L':
231          if ((optarg[::strlen (optarg) - 1] == '/') ||
232              (optarg[::strlen (optarg) - 1] == '\\'))
233            optarg[::strlen (optarg) - 1] = '\0';
234          libpaths.push_back (optarg);
235          break;
236
237        case 'n':
238          standard_libs = false;
239          break;
240
241        case 'C':
242          if (exec_prefix_set == true)
243            std::cerr << "warning: exec-prefix ignored when CC provided" << std::endl;
244          rld::cc::cc = optarg;
245          break;
246
247        case 'E':
248          exec_prefix_set = true;
249          rld::cc::exec_prefix = optarg;
250          break;
251
252        case 'a':
253          rld::cc::march = optarg;
254          break;
255
256        case 'c':
257          rld::cc::mcpu = optarg;
258          break;
259
260        case 'e':
261          entry = optarg;
262          break;
263
264        case 'd':
265          defines.push_back (rld::symbols::symbol (optarg));
266          break;
267
268        case 'u':
269          undefines.push_back (rld::symbols::symbol (optarg));
270          break;
271
272        case 'b':
273          base_name = optarg;
274          break;
275
276        case '?':
277          usage (3);
278          break;
279
280        case 'h':
281          usage (0);
282          break;
283      }
284    }
285
286    argc -= optind;
287    argv += optind;
288
289    if (rld::verbose () || map)
290      std::cout << "RTEMS Linker " << rld::version () << std::endl;
291
292    /*
293     * If there are no object files there is nothing to link.
294     */
295    if ((argc == 0) && !map)
296      throw rld::error ("no object files", "options");
297
298    /*
299     * Check the output format is valid.
300     */
301    if ((output_type != "rap") &&
302        (output_type != "elf") &&
303        (output_type != "script") &&
304        (output_type != "archive"))
305      throw rld::error ("invalid output format", "options");
306
307    /*
308     * Load the remaining command line arguments into the cache as object
309     * files.
310     */
311    while (argc--)
312      objects.push_back (*argv++);
313
314    /*
315     * The 'entry' point symbol needs to be added to the undefines so it is
316     * resolved.
317     */
318    undefines.push_back (rld::symbols::symbol (entry));
319
320    /*
321     * Load the symbol table with the defined symbols from the defines bucket.
322     */
323    rld::symbols::load (defines, symbols);
324
325    /*
326     * Load the undefined table with the undefined symbols from the undefines
327     * bucket.
328     */
329    rld::symbols::load (undefines, undefined);
330
331    /*
332     * Add the object files to the cache.
333     */
334    cache.add (objects);
335
336    /*
337     * Open the cache.
338     */
339    cache.open ();
340
341    /*
342     * If the full path to CC is not provided and the exec-prefix is not set by
343     * the command line see if it can be detected from the object file
344     * types. This must be after we have added the object files because they
345     * are used when detecting.
346     */
347    if (rld::cc::cc.empty () && !exec_prefix_set)
348      rld::cc::exec_prefix = rld::elf::machine_type ();
349
350    /*
351     * If we have a base image add it.
352     */
353    if (base_name.length ())
354    {
355      if (rld::verbose ())
356        std::cout << "base-image: " << base_name << std::endl;
357      base.open ();
358      base.add (base_name);
359      base.load_symbols (base_symbols, true);
360    }
361
362    /*
363     * Get the standard library paths
364     */
365    if (standard_libs)
366      rld::cc::get_standard_libpaths (libpaths);
367
368    /*
369     * Get the command line libraries.
370     */
371    rld::files::find_libraries (libraries, libpaths, libs);
372
373    /*
374     * Are we to load standard libraries ?
375     */
376    if (standard_libs)
377      rld::cc::get_standard_libs (libraries, libpaths);
378
379    /*
380     * Load the library to the cache.
381     */
382    cache.add_libraries (libraries);
383
384    /*
385     * Begin the archive session. This opens the archives and leaves them open
386     * while we the symbol table is being used. The symbols reference object
387     * files and the object files may reference archives and it is assumed they
388     * are open and available. It is also assumed the number of library
389     * archives being managed is less than the maximum file handles this
390     * process can have open at any one time. If this is not the case this
391     * approach would need to be reconsidered and the overhead of opening and
392     * closing archives added.
393     */
394    try
395    {
396      cache.archives_begin ();
397
398      /*
399       * Load the symbol table.
400       */
401      cache.load_symbols (symbols);
402
403      /*
404       * Map ?
405       */
406      if (map)
407      {
408        if (base_name.length ())
409          rld::map (base, base_symbols);
410        rld::map (cache, symbols);
411      }
412
413      if (cache.path_count ())
414      {
415        /*
416         * This structure allows us to add different operations with the same
417         * structure.
418         */
419        rld::files::object_list dependents;
420        rld::resolver::resolve (dependents, cache,
421                                base_symbols, symbols, undefined);
422
423        /**
424         * Output the file.
425         */
426        if (output_type == "script")
427          rld::outputter::script (output, entry, exit, dependents, cache);
428        else if (output_type == "archive")
429          rld::outputter::archive (output, entry, exit, dependents, cache);
430        else if (output_type == "elf")
431          rld::outputter::elf_application (output, entry, exit,
432                                           dependents, cache);
433        else if (output_type == "rap")
434          rld::outputter::application (output, entry, exit,
435                                       dependents, cache, symbols);
436        else
437          throw rld::error ("invalid output type", "output");
438
439        /**
440         * Check for warnings.
441         */
442        if (warnings)
443        {
444          rld::warn_unused_externals (dependents);
445        }
446      }
447    }
448    catch (...)
449    {
450      cache.archives_end ();
451      throw;
452    }
453
454    cache.archives_end ();
455  }
456  catch (rld::error re)
457  {
458    std::cerr << "error: "
459              << re.where << ": " << re.what
460              << std::endl;
461    ec = 10;
462  }
463  catch (std::exception e)
464  {
465    int   status;
466    char* realname;
467    realname = abi::__cxa_demangle (e.what(), 0, 0, &status);
468    std::cerr << "error: exception: " << realname << " [";
469    ::free (realname);
470    const std::type_info &ti = typeid (e);
471    realname = abi::__cxa_demangle (ti.name(), 0, 0, &status);
472    std::cerr << realname << "] " << e.what () << std::endl;
473    ::free (realname);
474    ec = 11;
475  }
476  catch (...)
477  {
478    /*
479     * Helps to know if this happens.
480     */
481    std::cout << "error: unhandled exception" << std::endl;
482    ec = 12;
483  }
484
485  return ec;
486}
Note: See TracBrowser for help on using the repository browser.