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

5
Last change on this file since c2df65b was efc4f09, checked in by Chris Johns <chrisj@…>, on 12/09/15 at 09:08:19

Add release versioning support.

Support a top level VERSION file that defines an RTEMS release.

Fix the install of the python modules including thertems-test.

Update the git python module to the RSB version. Fix the options to
not call clean and to call dirty.

Update the version python module.

Fix the rtld C++ support to the VERSION file and the top level waf
script.

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