source: rtems-tools/linkers/rtems-ld.cpp @ 977c3de

4.104.11
Last change on this file since 977c3de was 977c3de, checked in by Chris Johns <chrisj@…>, on Nov 17, 2012 at 6:34:33 AM

Refactor the ELF support to allow ELF write suppport.

The refactoring allows better reuse of the ELF support and cleans up
some hacks from the generic file and archive handling improving the
separation of the file handling from the file format, ie ELF. The
handling of ELF object files and ELF object files inside archives
is cleaner.

The refactor cleaned up the symbol handling where the symbols now
reside in the ELF file object and references are take in symbol
pointer containers and symbol table containers.

The main purpose of the refactor is to allow support for creating
and writing ELF files.

Also added an rtems-syms command where special symbol support
can be added.

  • Property mode set to 100644
File size: 12.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-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    bool                 script = false;
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          script = true;
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    rld::cc::get_standard_libpaths (libpaths);
343
344    /*
345     * Get the command line libraries.
346     */
347    rld::files::find_libraries (libraries, libpaths, libs);
348
349    /*
350     * Are we to load standard libraries ?
351     */
352    if (standard_libs)
353      rld::cc::get_standard_libs (libraries, libpaths);
354
355    /*
356     * Load the library to the cache.
357     */
358    cache.add_libraries (libraries);
359
360    /*
361     * Load the symbol table.
362     */
363    cache.load_symbols (symbols);
364
365    /*
366     * Map ?
367     */
368    if (map)
369    {
370      if (base_name.length ())
371        rld::map (base, base_symbols);
372      rld::map (cache, symbols);
373    }
374
375    if (cache.path_count ())
376    {
377      /*
378       * This structure allows us to add different operations with the same
379       * structure.
380       */
381      rld::files::object_list dependents;
382      rld::resolver::resolve (dependents, cache, base_symbols, symbols, undefined);
383
384      /**
385       * Output the file.
386       */
387      if (script)
388        rld::outputter::script (output, dependents, cache);
389      else
390        rld::outputter::archive (output, dependents, cache);
391
392      /**
393       * Check for warnings.
394       */
395      if (warnings)
396      {
397        rld::warn_unused_externals (dependents);
398      }
399    }
400  }
401  catch (rld::error re)
402  {
403    std::cerr << "error: "
404              << re.where << ": " << re.what
405              << std::endl;
406    ec = 10;
407  }
408  catch (std::exception e)
409  {
410    int   status;
411    char* realname;
412    realname = abi::__cxa_demangle (e.what(), 0, 0, &status);
413    std::cerr << "error: exception: " << realname << " [";
414    ::free (realname);
415    const std::type_info &ti = typeid (e);
416    realname = abi::__cxa_demangle (ti.name(), 0, 0, &status);
417    std::cerr << realname << "] " << e.what () << std::endl;
418    ::free (realname);
419    ec = 11;
420  }
421  catch (...)
422  {
423    /*
424     * Helps to know if this happens.
425     */
426    std::cout << "error: unhandled exception" << std::endl;
427    ec = 12;
428  }
429
430  return ec;
431}
Note: See TracBrowser for help on using the repository browser.