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

4.104.115
Last change on this file since e5165d2 was e5165d2, checked in by Peng Fan <Peng.Fan@…>, on 08/09/14 at 12:32:50

Fix getopt_long usage

When passing shorhand options, getopt_long sometimes does not handle
them correctly.

Signed-off-by: Peng Fan <Peng.Fan@…>

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