source: rtems-tools/linkers/rtems-syms.cpp @ 885aebd

4.10
Last change on this file since 885aebd was 885aebd, checked in by Chris Johns <chrisj@…>, on Aug 25, 2016 at 5:54:23 AM

linkers/syms: Add weak symbols to the global symbol table.

Add any weak symbols that have been linked into the base image to the
global symbol table. A weak symbol is global when view viewed from
a dynamically loaded module.

Closes #2704.

  • Property mode set to 100644
File size: 14.2 KB
Line 
1/*
2 * Copyright (c) 2011-2014, 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 Symbols 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 <fstream>
30#include <iomanip>
31#include <iostream>
32
33#include <cxxabi.h>
34#include <signal.h>
35#include <stdlib.h>
36#include <string.h>
37#include <unistd.h>
38
39#include <getopt.h>
40
41#include <rld.h>
42#include <rld-cc.h>
43#include <rld-outputter.h>
44#include <rld-process.h>
45#include <rld-symbols.h>
46#include <rld-rtems.h>
47
48#ifndef HAVE_KILL
49#define kill(p,s) raise(s)
50#endif
51
52/**
53 * Header text.
54 */
55static const char* c_header[] =
56{
57  "/*",
58  " * RTEMS Global Symbol Table",
59  " *  Automatically generated. Do not edit..",
60  " */",
61  "",
62  "extern const unsigned char rtems__rtl_base_globals[];",
63  "extern const unsigned int rtems__rtl_base_globals_size[];",
64  "",
65  "void rtems_rtl_base_sym_global_add (const unsigned char* , unsigned int );",
66  "",
67  "asm(\".section \\\".rodata\\\"\");",
68  "",
69  "asm(\"  .align   4\");",
70  "asm(\"  .local   rtems__rtl_base_globals\");",
71  "asm(\"rtems__rtl_base_globals:\");",
72  "#if __mips__",
73  " asm(\"  .align 0\");",
74  "#else",
75  " asm(\"  .balign 1\");",
76  "#endif",
77  0
78};
79
80static const char* c_trailer[] =
81{
82  "asm(\"  .byte    0\");",
83  "asm(\"  .ascii   \\\"\\xde\\xad\\xbe\\xef\\\"\");",
84#if BROKEN_ON_SOME_ASSEMBLERS
85  "asm(\"  .type    rtems__rtl_base_globals, #object\");",
86  "asm(\"  .size    rtems__rtl_base_globals, . - rtems__rtl_base_globals\");",
87#endif
88  "",
89  "/*",
90  " * Symbol table size.",
91  " */",
92  "asm(\"  .align   4\");",
93  "asm(\"  .local   rtems__rtl_base_globals_size\");",
94#if BROKEN_ON_SOME_ASSEMBLERS
95  "asm(\"  .type    rtems__rtl_base_globals_size, #object\");",
96  "asm(\"  .size    rtems__rtl_base_globals_size, 4\");",
97#endif
98  "asm(\"rtems__rtl_base_globals_size:\");",
99  "asm(\"  .long rtems__rtl_base_globals_size - rtems__rtl_base_globals\");",
100  "",
101  0
102};
103
104static const char* c_rtl_call_body[] =
105{
106  "{",
107  "  rtems_rtl_base_sym_global_add (&rtems__rtl_base_globals[0],",
108  "                                 rtems__rtl_base_globals_size[0]);",
109  "}",
110  0
111};
112
113/**
114 * Paint the data to the temporary file.
115 */
116static void
117temporary_file_paint (rld::process::tempfile& t, const char* lines[])
118{
119  for (int l = 0; lines[l]; ++l)
120    t.write_line (lines[l]);
121}
122
123/**
124 * The constructor trailer.
125 */
126static void
127c_constructor_trailer (rld::process::tempfile& c)
128{
129  c.write_line ("static void init(void) __attribute__ ((constructor));");
130  c.write_line ("static void init(void)");
131  temporary_file_paint (c, c_rtl_call_body);
132}
133
134/**
135 * The embedded trailer.
136 */
137static void
138c_embedded_trailer (rld::process::tempfile& c)
139{
140  c.write_line ("void rtems_rtl_base_global_syms_init(void);");
141  c.write_line ("void rtems_rtl_base_global_syms_init(void)");
142  temporary_file_paint (c, c_rtl_call_body);
143}
144
145/**
146 * Generate the symbol map object file for loading or linking into
147 * a running RTEMS machine.
148 */
149
150struct output_sym
151{
152  rld::process::tempfile& c;
153  const bool              embed;
154  const bool              weak;
155
156  output_sym(rld::process::tempfile& c,
157             bool                    embed,
158             bool                    weak)
159    : c (c),
160      embed (embed),
161      weak (weak) {
162  }
163
164  void operator ()(const rld::symbols::symtab::value_type& value);
165};
166
167void
168output_sym::operator ()(const rld::symbols::symtab::value_type& value)
169{
170  const rld::symbols::symbol& sym = *(value.second);
171
172  /*
173   * Weak symbols without a value are probably unresolved externs. Ignore them.
174   */
175  if (weak && sym.value () == 0)
176    return;
177
178  c.write_line ("asm(\"  .asciz \\\"" + sym.name () + "\\\"\");");
179
180  if (embed)
181  {
182    c.write_line ("asm(\"  .long " + sym.name () + "\");");
183  }
184  else
185  {
186    std::stringstream oss;
187    oss << std::hex << std::setfill ('0') << std::setw (8) << sym.value ();
188    c.write_line ("asm(\"  .long 0x" + oss.str () + "\");");
189  }
190}
191
192
193static void
194generate_c (rld::process::tempfile& c,
195            rld::symbols::table&    symbols,
196            bool                    embed)
197{
198  temporary_file_paint (c, c_header);
199
200  /*
201   * Add the global symbols.
202   */
203  std::for_each (symbols.globals ().begin (),
204                 symbols.globals ().end (),
205                 output_sym (c, embed, false));
206
207  /*
208   * Add the weak symbols that have been linked into the base image. A weak
209   * symbols present in the base image is no longer weak and should be consider
210   * a global symbol. You cannot link a global symbol with the same in a
211   * dynamically loaded module.
212   */
213  std::for_each (symbols.weaks ().begin (),
214                 symbols.weaks ().end (),
215                 output_sym (c, embed, true));
216
217  temporary_file_paint (c, c_trailer);
218
219  if (embed)
220    c_embedded_trailer (c);
221  else
222    c_constructor_trailer (c);
223}
224
225static void
226generate_symmap (rld::process::tempfile& c,
227                 const std::string&      output,
228                 rld::symbols::table&    symbols,
229                 bool                    embed)
230{
231  c.open (true);
232
233  if (rld::verbose ())
234    std::cout << "symbol C file: " << c.name () << std::endl;
235
236  generate_c (c, symbols, embed);
237
238  if (rld::verbose ())
239    std::cout << "symbol O file: " << output << std::endl;
240
241  rld::process::arg_container args;
242
243  rld::cc::make_cc_command (args);
244  rld::cc::append_flags (rld::cc::ft_cflags, args);
245
246  args.push_back ("-O2");
247  args.push_back ("-c");
248  args.push_back ("-o");
249  args.push_back (output);
250  args.push_back (c.name ());
251
252  rld::process::tempfile out;
253  rld::process::tempfile err;
254  rld::process::status   status;
255
256  status = rld::process::execute (rld::cc::get_cc (),
257                                  args,
258                                  out.name (),
259                                  err.name ());
260
261
262  if ((status.type != rld::process::status::normal) ||
263      (status.code != 0))
264  {
265    err.output (rld::cc::get_cc (), std::cout);
266    throw rld::error ("Compiler error", "compiling wrapper");
267  }
268}
269
270/**
271 * RTEMS Symbols options.
272 */
273static struct option rld_opts[] = {
274  { "help",        no_argument,            NULL,           'h' },
275  { "version",     no_argument,            NULL,           'V' },
276  { "verbose",     no_argument,            NULL,           'v' },
277  { "warn",        no_argument,            NULL,           'w' },
278  { "keep",        no_argument,            NULL,           'k' },
279  { "embed",       no_argument,            NULL,           'e' },
280  { "symc",        required_argument,      NULL,           'S' },
281  { "output",      required_argument,      NULL,           'o' },
282  { "map",         required_argument,      NULL,           'm' },
283  { "cc",          required_argument,      NULL,           'C' },
284  { "exec-prefix", required_argument,      NULL,           'E' },
285  { "cflags",      required_argument,      NULL,           'c' },
286  { NULL,          0,                      NULL,            0 }
287};
288
289void
290usage (int exit_code)
291{
292  std::cout << "rtems-syms [options] kernel" << std::endl
293            << "Options and arguments:" << std::endl
294            << " -h        : help (also --help)" << std::endl
295            << " -V        : print linker version number and exit (also --version)" << std::endl
296            << " -v        : verbose (trace import parts), can supply multiple times" << std::endl
297            << "             to increase verbosity (also --verbose)" << std::endl
298            << " -w        : generate warnings (also --warn)" << std::endl
299            << " -k        : keep temporary files (also --keep)" << std::endl
300            << " -e        : embedded symbol table (also --embed)" << std::endl
301            << " -S        : symbol's C file (also --symc)" << std::endl
302            << " -o file   : output object file (also --output)" << std::endl
303            << " -m file   : output a map file (also --map)" << std::endl
304            << " -C file   : execute file as the target C compiler (also --cc)" << std::endl
305            << " -E prefix : the RTEMS tool prefix (also --exec-prefix)" << std::endl
306            << " -c cflags : C compiler flags (also --cflags)" << std::endl;
307  ::exit (exit_code);
308}
309
310static void
311fatal_signal (int signum)
312{
313  signal (signum, SIG_DFL);
314
315  rld::process::temporaries_clean_up ();
316
317  /*
318   * Get the same signal again, this time not handled, so its normal effect
319   * occurs.
320   */
321  kill (getpid (), signum);
322}
323
324static void
325setup_signals (void)
326{
327  if (signal (SIGINT, SIG_IGN) != SIG_IGN)
328    signal (SIGINT, fatal_signal);
329#ifdef SIGHUP
330  if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
331    signal (SIGHUP, fatal_signal);
332#endif
333  if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
334    signal (SIGTERM, fatal_signal);
335#ifdef SIGPIPE
336  if (signal (SIGPIPE, SIG_IGN) != SIG_IGN)
337    signal (SIGPIPE, fatal_signal);
338#endif
339#ifdef SIGCHLD
340  signal (SIGCHLD, SIG_DFL);
341#endif
342}
343
344int
345main (int argc, char* argv[])
346{
347  int ec = 0;
348
349  setup_signals ();
350
351  try
352  {
353    rld::files::cache   kernel;
354    rld::symbols::table symbols;
355    std::string         kernel_name;
356    std::string         output;
357    std::string         map;
358    std::string         cc;
359    std::string         symc;
360    bool                embed = false;
361
362    rld::set_cmdline (argc, argv);
363
364    while (true)
365    {
366      int opt = ::getopt_long (argc, argv, "hvVwkef:S:o:m:E:c:C:", rld_opts, NULL);
367      if (opt < 0)
368        break;
369
370      switch (opt)
371      {
372        case 'V':
373          std::cout << "rtems-syms (RTEMS Symbols) " << rld::version ()
374                    << ", RTEMS revision " << rld::rtems::version ()
375                    << std::endl;
376          ::exit (0);
377          break;
378
379        case 'v':
380          rld::verbose_inc ();
381          break;
382
383        case 'w':
384          break;
385
386        case 'k':
387          rld::process::set_keep_temporary_files ();
388          break;
389
390        case 'e':
391          embed = true;
392          break;
393
394        case 'o':
395          output = optarg;
396          break;
397
398        case 'm':
399          map = optarg;
400          break;
401
402        case 'C':
403          if (rld::cc::is_exec_prefix_set ())
404            std::cerr << "warning: exec-prefix ignored when CC provided" << std::endl;
405          rld::cc::set_cc (optarg);
406          break;
407
408        case 'E':
409          if (rld::cc::is_cc_set ())
410            std::cerr << "warning: exec-prefix ignored when CC provided" << std::endl;
411          rld::cc::set_exec_prefix (optarg);
412          break;
413
414        case 'c':
415          rld::cc::set_flags (optarg, rld::cc::ft_cflags);
416          break;
417
418        case 'S':
419          symc = optarg;
420          break;
421
422        case '?':
423          usage (3);
424          break;
425
426        case 'h':
427          usage (0);
428          break;
429      }
430    }
431
432    /*
433     * Set the program name.
434     */
435    rld::set_progname (argv[0]);
436
437    argc -= optind;
438    argv += optind;
439
440    if (rld::verbose ())
441      std::cout << "RTEMS Kernel Symbols " << rld::version () << std::endl;
442
443    /*
444     * If there are no object files there is nothing to link.
445     */
446    if (argc == 0)
447      throw rld::error ("no kernel file", "options");
448    if (argc != 1)
449      throw rld::error ("only one kernel file", "options");
450    if (output.empty () && map.empty ())
451      throw rld::error ("no output or map", "options");
452
453    kernel_name = *argv;
454
455    if (rld::verbose ())
456      std::cout << "kernel: " << kernel_name << std::endl;
457
458    /*
459     * Load the symbols from the kernel.
460     */
461    try
462    {
463      /*
464       * Load the kernel ELF file symbol table.
465       */
466      kernel.open ();
467      kernel.add (kernel_name);
468      kernel.load_symbols (symbols, true);
469
470      /*
471       * If the full path to CC is not provided and the exec-prefix is not set
472       * by the command line see if it can be detected from the object file
473       * types. This must be after we have added the object files because they
474       * are used when detecting.
475       */
476      if (!cc.empty ())
477        rld::cc::set_cc (cc);
478      if (!rld::cc::is_cc_set () && !rld::cc::is_exec_prefix_set ())
479        rld::cc::set_exec_prefix (rld::elf::machine_type ());
480
481      /*
482       * Create a map file if asked too.
483       */
484      if (!map.empty ())
485      {
486        std::ofstream mout;
487        mout.open (map.c_str());
488        if (!mout.is_open ())
489          throw rld::error ("map file open failed", "map");
490        mout << "RTEMS Kernel Symbols Map" << std::endl
491             << " kernel: " << kernel_name << std::endl
492             << std::endl;
493        rld::symbols::output (mout, symbols);
494        mout.close ();
495      }
496
497      /*
498       * Create an output file if asked too.
499       */
500      if (!output.empty ())
501      {
502        rld::process::tempfile c (".c");
503
504        if (!symc.empty ())
505        {
506          c.override (symc);
507          c.keep ();
508        }
509
510        /*
511         * Generate and compile the symbol map.
512         */
513        generate_symmap (c, output, symbols, embed);
514      }
515
516      kernel.close ();
517    }
518    catch (...)
519    {
520      kernel.close ();
521      throw;
522    }
523
524    kernel.close ();
525  }
526  catch (rld::error re)
527  {
528    std::cerr << "error: "
529              << re.where << ": " << re.what
530              << std::endl;
531    ec = 10;
532  }
533  catch (std::exception e)
534  {
535    int   status;
536    char* realname;
537    realname = abi::__cxa_demangle (e.what(), 0, 0, &status);
538    std::cerr << "error: exception: " << realname << " [";
539    ::free (realname);
540    const std::type_info &ti = typeid (e);
541    realname = abi::__cxa_demangle (ti.name(), 0, 0, &status);
542    std::cerr << realname << "] " << e.what () << std::endl;
543    ::free (realname);
544    ec = 11;
545  }
546  catch (...)
547  {
548    /*
549     * Helps to know if this happens.
550     */
551    std::cout << "error: unhandled exception" << std::endl;
552    ec = 12;
553  }
554
555  return ec;
556}
Note: See TracBrowser for help on using the repository browser.