source: rtems-tools/linkers/rtems-ld.cpp @ 6fae4de

4.104.115
Last change on this file since 6fae4de was 544de91, checked in by Chris Johns <chrisj@…>, on 12/28/12 at 23:20:22

Fix managing weak symbols.

Weak symbols where not being managed correctly. The symbols table
is now a class with externals and weaks as separate symtabs so
the externals can be searched first then the weaks and if not
found an unresolved error is raised. This was found creating
a libbsdport RAP file where the drivers in the all driver table
resolved to the weak symbols and so linking in nothing.

Fixing the weak symbols as found in the libbsdport library
triggered a new resolver bug. The object files now contain the
resolver state and this is used to determine if an object file
has been resolved or is currently being resolved avoiding
rescursive loops with dependent object files.

The resolver trace output is a little easier to read.

  • 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::symtab 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 << std::flush;
473    ::free (realname);
474    ec = 11;
475  }
476  catch (...)
477  {
478    /*
479     * Helps to know if this happens.
480     */
481    std::cerr << "error: unhandled exception" << std::endl;
482    ec = 12;
483  }
484
485  return ec;
486}
Note: See TracBrowser for help on using the repository browser.