source: rtems-tools/linkers/rtems-ld.cpp @ 40fd7a0

4.104.115
Last change on this file since 40fd7a0 was 40fd7a0, checked in by Chris Johns <chrisj@…>, on 09/01/14 at 03:26:47

rld: Split the file into a path module for path specific functions.

This allows resued for other parts of the system not dependent on
objcet files or archives.

  • Property mode set to 100644
File size: 16.0 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-rap.h>
42#include <rld-outputter.h>
43#include <rld-process.h>
44#include <rld-resolver.h>
45
46#ifndef HAVE_KILL
47#define kill(p,s) raise(s)
48#endif
49
50/**
51 * RTEMS Linker options. This needs to be rewritten to be like cc where only a
52 * single '-' and long options is present.
53 */
54static struct option rld_opts[] = {
55  { "help",        no_argument,            NULL,           'h' },
56  { "version",     no_argument,            NULL,           'V' },
57  { "verbose",     no_argument,            NULL,           'v' },
58  { "warn",        no_argument,            NULL,           'w' },
59  { "map",         no_argument,            NULL,           'M' },
60  { "output",      required_argument,      NULL,           'o' },
61  { "out-format",  required_argument,      NULL,           'O' },
62  { "lib-path",    required_argument,      NULL,           'L' },
63  { "lib",         required_argument,      NULL,           'l' },
64  { "no-stdlibs",  no_argument,            NULL,           'n' },
65  { "entry",       required_argument,      NULL,           'e' },
66  { "define",      required_argument,      NULL,           'd' },
67  { "undefined",   required_argument,      NULL,           'u' },
68  { "base",        required_argument,      NULL,           'b' },
69  { "cc",          required_argument,      NULL,           'C' },
70  { "exec-prefix", required_argument,      NULL,           'E' },
71  { "cflags",      required_argument,      NULL,           'c' },
72  { "rap-strip",   no_argument,            NULL,           'S' },
73  { "rpath",       required_argument,      NULL,           'R' },
74  { "runtime-lib", required_argument,      NULL,           'P' },
75  { "one-file",    no_argument,            NULL,           's' },
76  { NULL,          0,                      NULL,            0 }
77};
78
79#if TO_BE_USED_FOR_THE_UNDEFINES
80void
81split_on_equals (const std::string& opt, std::string& left, std::string& right)
82{
83  std::string::size_type eq = opt.find_first_of('=');
84}
85#endif
86
87void
88usage (int exit_code)
89{
90  std::cout << "rtems-ld [options] objects" << std::endl
91            << "Options and arguments:" << std::endl
92            << " -h        : help (also --help)" << std::endl
93            << " -V        : print linker version number and exit (also --version)" << std::endl
94            << " -v        : verbose (trace import parts), can supply multiple times" << std::endl
95            << "             to increase verbosity (also --verbose)" << std::endl
96            << " -w        : generate warnings (also --warn)" << std::endl
97            << " -M        : generate map output (also --map)" << std::endl
98            << " -o file   : linker output is written to file (also --output)" << std::endl
99            << " -O format : linker output format, default is 'rap' (also --out-format)" << std::endl
100            << " -L path   : path to a library, add multiple for more than" << std::endl
101            << "             one path (also --lib-path)" << std::endl
102            << " -l lib    : add lib to the libraries searched, add multiple" << std::endl
103            << "             for more than one library (also --lib)" << std::endl
104            << " -n        : do not search standard libraries (also --no-stdlibs)" << std::endl
105            << " -e entry  : entry point symbol (also --entry)" << std::endl
106            << " -d sym    : add the symbol definition, add multiple with" << std::endl
107            << "             more than one define (also --define)" << std::endl
108            << " -u sym    : add the undefined symbol definition, add multiple" << std::endl
109            << "             for more than one undefined symbol (also --undefined)" << std::endl
110            << " -b elf    : read the ELF file symbols as the base RTEMS kernel" << std::endl
111            << "             image (also --base)" << std::endl
112            << " -C file   : execute file as the target C compiler (also --cc)" << std::endl
113            << " -E prefix : the RTEMS tool prefix (also --exec-prefix)" << std::endl
114            << " -c cflags : C compiler flags (also --cflags)" << std::endl
115            << " -S        : do not include file details (also --rap-strip)" << std::endl
116            << " -R        : include file paths (also --rpath)" << std::endl
117            << " -P        : place objects from archives (also --runtime-lib)" << std::endl
118            << " -s        : Include archive elf object files (also --one-file)" << std::endl
119            << " -Wl,opts  : link compatible flags, ignored" << std::endl
120            << "Output Formats:" << std::endl
121            << " rap     - RTEMS application (LZ77, single image)" << std::endl
122            << " elf     - ELF application (script, ELF files)" << std::endl
123            << " script  - Script format (list of object files)" << std::endl
124            << " archive - Archive format (collection of ELF files)" << std::endl;
125  ::exit (exit_code);
126}
127
128static void
129fatal_signal (int signum)
130{
131  signal (signum, SIG_DFL);
132
133  rld::process::temporaries_clean_up ();
134
135  /*
136   * Get the same signal again, this time not handled, so its normal effect
137   * occurs.
138   */
139  kill (getpid (), signum);
140}
141
142static void
143setup_signals (void)
144{
145  if (signal (SIGINT, SIG_IGN) != SIG_IGN)
146    signal (SIGINT, fatal_signal);
147#ifdef SIGHUP
148  if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
149    signal (SIGHUP, fatal_signal);
150#endif
151  if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
152    signal (SIGTERM, fatal_signal);
153#ifdef SIGPIPE
154  if (signal (SIGPIPE, SIG_IGN) != SIG_IGN)
155    signal (SIGPIPE, fatal_signal);
156#endif
157#ifdef SIGCHLD
158  signal (SIGCHLD, SIG_DFL);
159#endif
160}
161
162int
163main (int argc, char* argv[])
164{
165  int ec = 0;
166
167  setup_signals ();
168
169  try
170  {
171    rld::files::cache    cache;
172    rld::files::cache    base;
173    rld::files::cache    cachera;
174    rld::path::paths     libpaths;
175    rld::path::paths     libs;
176    rld::path::paths     objects;
177    rld::path::paths     libraries;
178    rld::symbols::bucket defines;
179    rld::symbols::bucket undefines;
180    rld::symbols::table  base_symbols;
181    rld::symbols::table  symbols;
182    rld::symbols::symtab undefined;
183    std::string          entry = "rtems";
184    std::string          exit;
185    std::string          output = "a.out";
186    std::string          outra;
187    std::string          base_name;
188    std::string          cc_name;
189    std::string          output_type = "rap";
190    bool                 standard_libs = true;
191    bool                 exec_prefix_set = false;
192    bool                 map = false;
193    bool                 warnings = false;
194    bool                 one_file = false;
195
196    libpaths.push_back (".");
197
198    while (true)
199    {
200      int opt = ::getopt_long (argc, argv, "hvwVMnsSb:E:o:O:L:l:c:e:d:u:C:W:R:P:", rld_opts, NULL);
201      if (opt < 0)
202        break;
203
204      switch (opt)
205      {
206        case 'V':
207          std::cout << "rtems-ld (RTEMS Linker) " << rld::version ()
208                    << std::endl;
209          ::exit (0);
210          break;
211
212        case 'v':
213          rld::verbose_inc ();
214          break;
215
216        case 'M':
217          map = true;
218          break;
219
220        case 'w':
221          warnings = true;
222          break;
223
224        case 'o':
225          if (output != "a.out")
226            std::cerr << "warning: output already set" << std::endl;
227          output = optarg;
228          break;
229
230        case 'O':
231          output_type = optarg;
232          break;
233
234        case 'l':
235          /*
236           * The order is important. It is the search order.
237           */
238          libs.push_back (optarg);
239          break;
240
241        case 'P':
242          if (!outra.empty ())
243            std::cerr << "warning: output ra alreay set" << std::endl;
244          outra = "lib";
245          outra += optarg;
246          outra += ".ra";
247          break;
248
249        case 's':
250          one_file = true;
251          break;
252
253        case 'L':
254          if ((optarg[::strlen (optarg) - 1] == '/') ||
255              (optarg[::strlen (optarg) - 1] == '\\'))
256            optarg[::strlen (optarg) - 1] = '\0';
257          libpaths.push_back (optarg);
258          break;
259
260        case 'n':
261          standard_libs = false;
262          break;
263
264        case 'C':
265          if (exec_prefix_set == true)
266            std::cerr << "warning: exec-prefix ignored when CC provided" << std::endl;
267          rld::cc::cc = optarg;
268          break;
269
270        case 'E':
271          exec_prefix_set = true;
272          rld::cc::exec_prefix = optarg;
273          break;
274
275        case 'c':
276          rld::cc::cflags = optarg;
277          break;
278
279        case 'e':
280          entry = optarg;
281          break;
282
283        case 'd':
284          defines.push_back (rld::symbols::symbol (optarg));
285          break;
286
287        case 'u':
288          undefines.push_back (rld::symbols::symbol (optarg));
289          break;
290
291        case 'b':
292          base_name = optarg;
293          break;
294
295        case 'S':
296          rld::rap::add_obj_details = false;
297          break;
298
299        case 'R':
300          rld::rap::rpath += optarg;
301          rld::rap::rpath += '\0';
302          break;
303
304        case 'W':
305          /* ignore linker compatiable flags */
306          break;
307
308        case '?':
309          usage (3);
310          break;
311
312        case 'h':
313          usage (0);
314          break;
315      }
316    }
317
318    argc -= optind;
319    argv += optind;
320
321    if (rld::verbose () || map)
322      std::cout << "RTEMS Linker " << rld::version () << std::endl;
323
324    /*
325     * If there are no object files there is nothing to link.
326     */
327    if ((argc == 0) && !map)
328      throw rld::error ("no object files", "options");
329
330    /*
331     * Check the output format is valid.
332     */
333    if ((output_type != "rap") &&
334        (output_type != "elf") &&
335        (output_type != "script") &&
336        (output_type != "archive"))
337      throw rld::error ("invalid output format", "options");
338
339    /*
340     * Load the remaining command line arguments into the cache as object
341     * files.
342     */
343    while (argc--)
344      objects.push_back (*argv++);
345
346    /*
347     * The 'entry' point symbol needs to be added to the undefines so it is
348     * resolved.
349     */
350    undefines.push_back (rld::symbols::symbol (entry));
351
352    /*
353     * Load the symbol table with the defined symbols from the defines bucket.
354     */
355    rld::symbols::load (defines, symbols);
356
357    /*
358     * Load the undefined table with the undefined symbols from the undefines
359     * bucket.
360     */
361    rld::symbols::load (undefines, undefined);
362
363    /*
364     * Add the object files to the cache.
365     */
366    cache.add (objects);
367
368    /*
369     * Open the cache.
370     */
371    cache.open ();
372
373    /*
374     * If the full path to CC is not provided and the exec-prefix is not set by
375     * the command line see if it can be detected from the object file
376     * types. This must be after we have added the object files because they
377     * are used when detecting.
378     */
379    if (rld::cc::cc.empty () && !exec_prefix_set)
380      rld::cc::exec_prefix = rld::elf::machine_type ();
381
382    /*
383     * If we have a base image add it.
384     */
385    if (base_name.length ())
386    {
387      if (rld::verbose ())
388        std::cout << "base-image: " << base_name << std::endl;
389      base.open ();
390      base.add (base_name);
391      base.load_symbols (base_symbols, true);
392    }
393
394    /*
395     * Get the standard library paths
396     */
397    if (standard_libs)
398      rld::cc::get_standard_libpaths (libpaths);
399
400    /*
401     * Get the command line libraries.
402     */
403    rld::files::find_libraries (libraries, libpaths, libs);
404
405    /*
406     * Are we to load standard libraries ?
407     */
408    if (standard_libs)
409      rld::cc::get_standard_libs (libraries, libpaths);
410
411    /*
412     * Load the library to the cache.
413     */
414    cache.add_libraries (libraries);
415
416    /*
417     * Begin the archive session. This opens the archives and leaves them open
418     * while we the symbol table is being used. The symbols reference object
419     * files and the object files may reference archives and it is assumed they
420     * are open and available. It is also assumed the number of library
421     * archives being managed is less than the maximum file handles this
422     * process can have open at any one time. If this is not the case this
423     * approach would need to be reconsidered and the overhead of opening and
424     * closing archives added.
425     */
426    try
427    {
428      cache.archives_begin ();
429
430      /*
431       * Load the symbol table.
432       */
433      cache.load_symbols (symbols);
434
435      /*
436       * Map ?
437       */
438      if (map)
439      {
440        if (base_name.length ())
441          rld::map (base, base_symbols);
442        rld::map (cache, symbols);
443      }
444
445      if (cache.path_count ())
446      {
447        /*
448         * This structure allows us to add different operations with the same
449         * structure.
450         */
451        rld::files::object_list dependents;
452        rld::resolver::resolve (dependents, cache,
453                                base_symbols, symbols, undefined);
454
455        /**
456         * Output the file.
457         */
458        if (output_type == "script")
459          rld::outputter::script (output, entry, exit, dependents, cache);
460        else if (output_type == "archive")
461          rld::outputter::archive (output, entry, exit, dependents, cache);
462        else if (output_type == "elf")
463          rld::outputter::elf_application (output, entry, exit,
464                                           dependents, cache);
465        else if (output_type == "rap")
466        {
467          rld::outputter::application (output, entry, exit,
468                                       dependents, cache, symbols,
469                                       one_file);
470          if (!outra.empty ())
471          {
472            rld::path::paths ra_libs;
473            bool ra_exist = false;
474
475            /**
476             * If exist, search it, else create a new one.
477             */
478            if ((ra_exist = ::access (outra.c_str (), 0)) == 0)
479            {
480              ra_libs.push_back (outra);
481              cachera.open ();
482              cachera.add_libraries (ra_libs);
483              cachera.archives_begin ();
484            }
485
486            rld::outputter::archivera (outra, dependents, cachera,
487                                       !ra_exist, false);
488          }
489        }
490        else
491          throw rld::error ("invalid output type", "output");
492
493        /**
494         * Check for warnings.
495         */
496        if (warnings)
497        {
498          rld::warn_unused_externals (dependents);
499        }
500      }
501    }
502    catch (...)
503    {
504      cache.archives_end ();
505      throw;
506    }
507
508    cache.archives_end ();
509  }
510  catch (rld::error re)
511  {
512    std::cerr << "error: "
513              << re.where << ": " << re.what
514              << std::endl;
515    ec = 10;
516  }
517  catch (std::exception e)
518  {
519    int   status;
520    char* realname;
521    realname = abi::__cxa_demangle (e.what(), 0, 0, &status);
522    std::cerr << "error: exception: " << realname << " [";
523    ::free (realname);
524    const std::type_info &ti = typeid (e);
525    realname = abi::__cxa_demangle (ti.name(), 0, 0, &status);
526    std::cerr << realname << "] " << e.what () << std::endl << std::flush;
527    ::free (realname);
528    ec = 11;
529  }
530  catch (...)
531  {
532    /*
533     * Helps to know if this happens.
534     */
535    std::cerr << "error: unhandled exception" << std::endl;
536    ec = 12;
537  }
538
539  return ec;
540}
Note: See TracBrowser for help on using the repository browser.