source: rtems-tools/linkers/rld-elf.cpp @ ec24a37

4.104.11
Last change on this file since ec24a37 was ec24a37, checked in by Chris Johns <chrisj@…>, on May 6, 2012 at 10:47:11 PM

Add to git.

  • Property mode set to 100644
File size: 10.0 KB
Line 
1/*
2 * Copyright (c) 2011, 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-ld
20 *
21 * @brief RTEMS Linker ELF module manages the ELF format images.
22 *
23 */
24
25#include <string.h>
26
27#include <rld.h>
28
29namespace rld
30{
31  namespace elf
32  {
33    void error (const std::string& where)
34    {
35      throw rld::error (::elf_errmsg (-1), "elf:" + where);
36    }
37
38    /**
39     * We record the first class, machine and .. type of object file we get the
40     * header of and all header must match. We cannot mix object module types.
41     */
42    static int elf_object_class = ELFCLASSNONE;
43    static int elf_object_data = ELFDATANONE;
44    static int elf_object_machinetype = EM_NONE;
45
46    /**
47     * A single place to initialise the libelf library. This must be called
48     * before any libelf API calls are made.
49     */
50    static void
51    libelf_initialise ()
52    {
53      static bool libelf_initialised = false;
54      if (!libelf_initialised)
55      {
56        if (::elf_version (EV_CURRENT) == EV_NONE)
57          error ("initialisation");
58        libelf_initialised = true;
59      }
60    }
61
62    /**
63     * Return the RTEMS target type given the ELF machine type.
64     */
65    const std::string
66    machine_type ()
67    {
68      struct types_and_labels
69      {
70        const char* name;        //< The RTEMS label.
71        int         machinetype; //< The machine type.
72      };
73      types_and_labels types_to_labels[] =
74      {
75        { "arm",     EM_ARM },
76        { "avr",     EM_AVR },
77        { "bfin",    EM_BLACKFIN },
78        { "h8300",   EM_H8_300 },
79        { "i386",    EM_386 },
80     /* { "m32c",    EM_M32C }, Not in libelf I imported */
81        { "m32r",    EM_M32R },
82        { "m68k",    EM_68K },
83        { "m68k",    EM_COLDFIRE },
84        { "mips",    EM_MIPS },
85        { "powerpc", EM_PPC },
86        { "sh",      EM_SH },
87        { "sparc",   EM_SPARC },
88        { "sparc64", EM_SPARC },
89        { 0,         EM_NONE }
90      };
91
92      int m = 0;
93      while (types_to_labels[m].machinetype != EM_NONE)
94      {
95        if (elf_object_machinetype == types_to_labels[m].machinetype)
96          return types_to_labels[m].name;
97        ++m;
98      }
99
100      std::ostringstream what;
101      what << "unknown machine type: " << elf_object_machinetype;
102      throw rld::error (what, "machine-type");
103    }
104
105    section::section (int          index,
106                      std::string& name,
107                      elf_scn*     scn, 
108                      elf_shdr&    shdr)
109      : index (index),
110        name (name),
111        scn (scn),
112        shdr (shdr)
113    {
114      data = ::elf_getdata (scn, NULL);
115      if (!data)
116        error ("elf_getdata");
117    }
118
119    section::section ()
120      : index (-1),
121        scn (0),
122        data (0)
123    {
124      memset (&shdr, 0, sizeof (shdr));
125    }
126
127    #define rld_archive_fhdr_size (60)
128
129    void
130    begin (rld::files::image& image)
131    {
132      libelf_initialise ();
133
134      /*
135       * Begin's are not nesting.
136       */
137      Elf* elf = image.elf ();
138      if (elf)
139          error ("begin: already done: " + image.name ().full ());
140
141      /*
142       * Is this image part of an archive ?
143       */
144      elf = image.elf (true);
145      if (elf)
146      {
147        ssize_t offset = image.name ().offset () - rld_archive_fhdr_size;
148
149        if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
150          std::cout << "elf::rand: " << elf << " offset:" << offset
151                    << ' ' << image.name ().full () << std::endl;
152
153        if (::elf_rand (elf, offset) != offset)
154          error ("begin:" + image.name ().full ());
155      }
156
157      /*
158       * Note, the elf passed is either the archive or NULL.
159       */
160      elf = ::elf_begin (image.fd (), ELF_C_READ, elf);
161      if (!elf)
162        error ("begin:" + image.name ().full ());
163
164      if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
165        std::cout << "elf::begin: " << elf
166                  << ' ' << image.name ().full () << std::endl;
167
168      image.set_elf (elf);
169
170      elf_kind ek = ::elf_kind (elf);
171      if (image.name ().is_archive ())
172      {
173        if (ek != ELF_K_AR)
174          throw rld::error ("File not an ar archive", "libelf:" + image.name ().full ());
175      }
176      else if (ek != ELF_K_ELF)
177        throw rld::error ("File format not ELF", "libelf:" + image.name ().full ());
178
179      /*
180       * If an ELF file make sure they all match. On the first file that begins
181       * an ELF session record its settings.
182       */
183      if (ek == ELF_K_ELF)
184      {
185        int cl = ::gelf_getclass (elf);
186
187        if (elf_object_class == ELFCLASSNONE)
188          elf_object_class = cl;
189        else if (cl != elf_object_class)
190          throw rld::error ("Mixed classes not allowed (32bit/64bit).",
191                            "begin:" + image.name ().full ());
192     
193        char* ident = elf_getident (elf, NULL);
194
195        if (elf_object_data == ELFDATANONE)
196          elf_object_data = ident[EI_DATA];
197        else if (elf_object_data != ident[EI_DATA])
198          throw rld::error ("Mixed data types not allowed (LSB/MSB).",
199                            "begin:" + image.name ().full ());
200      }
201    }
202
203    void
204    end (rld::files::image& image)
205    {
206      ::Elf* elf = image.elf ();
207      if (elf)
208      {
209        if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
210          std::cout << "elf::end: " << elf
211                    << ' ' << image.name ().full () << std::endl;
212        ::elf_end (elf);
213      }
214      image.set_elf (0);
215    }
216
217    void
218    get_header (rld::files::image& image, elf_ehdr& ehdr)
219    {
220      if (::gelf_getehdr (image.elf (), &ehdr) == NULL)
221        error ("get-header:" + image.name ().full ());
222     
223      if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_REL))
224        throw rld::error ("Invalid ELF type (only ET_EXEC/ET_REL supported).",
225                          "get-header:" + image.name ().full ());
226
227      if (elf_object_machinetype == EM_NONE)
228        elf_object_machinetype = ehdr.e_machine;
229      else if (elf_object_machinetype != ehdr.e_machine)
230      {
231        std::ostringstream oss;
232        oss << "get-header:" << image.name ().full () 
233            << ": " << elf_object_machinetype << '/' << ehdr.e_machine;
234        throw rld::error ("Mixed machine types not supported.", oss.str ());
235      }
236    }
237
238    void
239    get_section_headers (rld::files::object& object,
240                         sections&           secs,
241                         unsigned int        type)
242    {
243      for (int sn = 0; sn < object.sections (); ++sn)
244      {
245        ::Elf_Scn* scn = ::elf_getscn (object.elf (), sn);
246        if (!scn)
247          error ("elf_getscn:" + object.name ().full ());
248        ::GElf_Shdr shdr;
249        if (!::gelf_getshdr (scn, &shdr))
250          error ("gelf_getshdr:" + object.name ().full ());
251        if (shdr.sh_type == type)
252        {
253          std::string name = get_string (object, 
254                                         object.section_strings (),
255                                         shdr.sh_name);
256          secs.push_back (section (sn, name, scn, shdr));
257        }
258      }
259    }
260
261    void
262    load_symbol_table (rld::symbols::table& exported,
263                       rld::files::object&  object, 
264                       section&             sec,
265                       bool                 local,
266                       bool                 weak,
267                       bool                 global)
268    {
269      int count = sec.shdr.sh_size / sec.shdr.sh_entsize;
270      for (int s = 0; s < count; ++s)
271      {
272        GElf_Sym esym;
273        if (!::gelf_getsym (sec.data, s, &esym))
274          error ("gelf_getsym");
275        std::string name = get_string (object, sec.shdr.sh_link, esym.st_name);
276        if (!name.empty ())
277        {
278          int stype = GELF_ST_TYPE (esym.st_info);
279          int sbind = GELF_ST_BIND (esym.st_info);
280          if (rld::verbose () >= RLD_VERBOSE_TRACE)
281          {
282            rld::symbols::symbol sym (name, esym);
283            std::cout << "elf::symbol: ";
284            sym.output (std::cout);
285            std::cout << std::endl;
286          }
287          if ((stype == STT_NOTYPE) && (esym.st_shndx == SHN_UNDEF))
288            object.unresolved_symbols ()[name] = rld::symbols::symbol (name, esym);
289          else if (((stype == STT_NOTYPE) || 
290                    (stype == STT_OBJECT) || 
291                    (stype == STT_FUNC)) &&
292                   ((local && (sbind == STB_LOCAL)) ||
293                    (weak && (sbind == STB_WEAK)) ||
294                    (global && (sbind == STB_GLOBAL))))
295          {
296            exported[name] = rld::symbols::symbol (name, object, esym);;
297            object.external_symbols ().push_back (&exported[name]);
298          }
299        }
300      }
301    }
302
303    void
304    load_symbols (rld::symbols::table& symbols,
305                  rld::files::object&  object, 
306                  bool                 local,
307                  bool                 weak,
308                  bool                 global)
309    {
310      sections sections;
311      get_section_headers (object, sections, SHT_SYMTAB);
312      for (sections::iterator si = sections.begin ();
313           si != sections.end ();
314           ++si)
315        load_symbol_table (symbols, object, *si, local, weak, global);
316    }
317
318    std::string
319    get_string (rld::files::object& object, 
320                int                 section,
321                size_t              offset)
322    {
323      char* s = ::elf_strptr (object.elf (), section, offset);
324      if (!s)
325        error ("elf_strptr");
326      return s;
327    }
328
329  }
330}
Note: See TracBrowser for help on using the repository browser.