source: rtems/cpukit/libdl/rtl-elf.c @ 21275b58

5
Last change on this file since 21275b58 was 03139d5b, checked in by Chris Johns <chrisj@…>, on 11/20/18 at 03:56:11

libdl: Add object file dependencies to track references

Tracking references lets us manage when an object file can be
unloaded. If an object file has references to it, it cannot be
unloaded.

Modules that depend on each other cannot be unloaded.

Updates #3605

  • Property mode set to 100644
File size: 37.6 KB
Line 
1/*
2 *  COPYRIGHT (c) 2012-2018 Chris Johns <chrisj@rtems.org>
3 *
4 *  The license and distribution terms for this file may be
5 *  found in the file LICENSE in this distribution or at
6 *  http://www.rtems.org/license/LICENSE.
7 */
8/**
9 * @file
10 *
11 * @ingroup rtems_rtld
12 *
13 * @brief RTEMS Run-Time Link Editor
14 *
15 * This is the RTL implementation.
16 */
17
18#if HAVE_CONFIG_H
19#include "config.h"
20#endif
21
22#include <errno.h>
23#include <fcntl.h>
24#include <stdlib.h>
25#include <string.h>
26#include <stdio.h>
27#include <unistd.h>
28
29#include <rtems/rtl/rtl.h>
30#include "rtl-elf.h"
31#include "rtl-error.h"
32#include <rtems/rtl/rtl-trace.h>
33#include "rtl-unwind.h"
34#include <rtems/rtl/rtl-unresolved.h>
35
36/**
37 * The offsets in the unresolved array.
38 */
39#define REL_R_OFFSET (0)
40#define REL_R_INFO   (1)
41#define REL_R_ADDEND (2)
42
43/**
44 * The ELF format signature.
45 */
46static rtems_rtl_loader_format elf_sig =
47{
48  .label = "ELF",
49  .flags = RTEMS_RTL_FMT_ELF
50};
51
52static bool
53rtems_rtl_elf_machine_check (Elf_Ehdr* ehdr)
54{
55  /*
56   * This code is determined by the NetBSD machine headers.
57   */
58  switch (ehdr->e_machine)
59  {
60    ELFDEFNNAME (MACHDEP_ID_CASES)
61    default:
62      return false;
63  }
64  return true;
65}
66
67static bool
68rtems_rtl_elf_find_symbol (rtems_rtl_obj*      obj,
69                           const Elf_Sym*      sym,
70                           const char*         symname,
71                           rtems_rtl_obj_sym** symbol,
72                           Elf_Word*           value)
73{
74  rtems_rtl_obj_sect* sect;
75
76  /*
77   * If the symbol type is STT_NOTYPE the symbol references a global
78   * symbol. The gobal symbol table is searched to find it and that value
79   * returned. If the symbol is local to the object module the section for the
80   * symbol is located and it's base added to the symbol's value giving an
81   * absolute location.
82   */
83  if (ELF_ST_TYPE(sym->st_info) == STT_NOTYPE || sym->st_shndx == SHN_COMMON)
84  {
85    /*
86     * Search the object file then the global table for the symbol.
87     */
88    *symbol = rtems_rtl_symbol_obj_find (obj, symname);
89    if (!*symbol)
90    {
91      rtems_rtl_set_error (EINVAL, "global symbol not found: %s", symname);
92      return false;
93    }
94
95    *value = (Elf_Addr) (*symbol)->value;
96    return true;
97  }
98
99  *symbol = NULL;
100
101  sect = rtems_rtl_obj_find_section_by_index (obj, sym->st_shndx);
102  if (!sect)
103  {
104    rtems_rtl_set_error (EINVAL, "reloc symbol's section not found");
105    return false;
106  }
107
108  *value = sym->st_value + (Elf_Addr) sect->base;
109  return true;
110}
111
112/**
113 * Relocation worker routine.
114 */
115typedef bool (*rtems_rtl_elf_reloc_handler)(rtems_rtl_obj*      obj,
116                                            bool                is_rela,
117                                            void*               relbuf,
118                                            rtems_rtl_obj_sect* targetsect,
119                                            rtems_rtl_obj_sym*  symbol,
120                                            Elf_Sym*            sym,
121                                            const char*         symname,
122                                            Elf_Word            symvalue,
123                                            bool                resolved,
124                                            void*               data);
125
126/**
127 * Relocation parser data.
128 */
129typedef struct
130{
131  size_t dependents; /**< The number of dependent object files. */
132  size_t unresolved; /**< The number of unresolved symbols. */
133} rtems_rtl_elf_reloc_data;
134
135static bool
136rtems_rtl_elf_reloc_parser (rtems_rtl_obj*      obj,
137                            bool                is_rela,
138                            void*               relbuf,
139                            rtems_rtl_obj_sect* targetsect,
140                            rtems_rtl_obj_sym*  symbol,
141                            Elf_Sym*            sym,
142                            const char*         symname,
143                            Elf_Word            symvalue,
144                            bool                resolved,
145                            void*               data)
146{
147  rtems_rtl_elf_reloc_data* rd = (rtems_rtl_elf_reloc_data*) data;
148  /*
149   * If the symbol has been resolved and there is a symbol name it is a global
150   * symbol and from another object file so add it as a dependency.
151   */
152  if (!resolved)
153  {
154    ++rd->unresolved;
155  }
156  else if (resolved && symname != NULL)
157  {
158    /*
159     * Find the symbol's object file. It cannot be NULL so ignore that result
160     * if returned, it means something is corrupted. We are in an iterator.
161     */
162    rtems_rtl_obj*  sobj = rtems_rtl_find_obj_with_symbol (symbol);
163    if (sobj != NULL)
164    {
165      /*
166       * A dependency is not the base kernel image or itself. Tag the object as
167       * having been visited so we count it only once.
168       */
169      if (sobj != rtems_rtl_baseimage () && obj != sobj &&
170          (sobj->flags & RTEMS_RTL_OBJ_RELOC_TAG) == 0)
171      {
172        sobj->flags |= RTEMS_RTL_OBJ_RELOC_TAG;
173        ++rd->dependents;
174      }
175    }
176  }
177  return true;
178}
179
180static bool
181rtems_rtl_elf_reloc_relocator (rtems_rtl_obj*      obj,
182                               bool                is_rela,
183                               void*               relbuf,
184                               rtems_rtl_obj_sect* targetsect,
185                               rtems_rtl_obj_sym*  symbol,
186                               Elf_Sym*            sym,
187                               const char*         symname,
188                               Elf_Word            symvalue,
189                               bool                resolved,
190                               void*               data)
191{
192  const Elf_Rela* rela = (const Elf_Rela*) relbuf;
193  const Elf_Rel*  rel = (const Elf_Rel*) relbuf;
194
195  if (!resolved)
196  {
197    uint16_t       flags = 0;
198    rtems_rtl_word rel_words[3];
199
200    if (is_rela)
201    {
202      flags = 1;
203      rel_words[REL_R_OFFSET] = rela->r_offset;
204      rel_words[REL_R_INFO] = rela->r_info;
205      rel_words[REL_R_ADDEND] = rela->r_addend;
206    }
207    else
208    {
209      rel_words[REL_R_OFFSET] = rel->r_offset;
210      rel_words[REL_R_INFO] = rel->r_info;
211      rel_words[REL_R_ADDEND] = 0;
212    }
213
214    if (!rtems_rtl_unresolved_add (obj,
215                                   flags,
216                                   symname,
217                                   targetsect->section,
218                                   rel_words))
219      return false;
220
221    ++obj->unresolved;
222  }
223  else
224  {
225    rtems_rtl_obj* sobj;
226
227    if (is_rela)
228    {
229      if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
230        printf ("rtl: rela: sym:%s(%d)=%08jx type:%d off:%08jx addend:%d\n",
231                symname, (int) ELF_R_SYM (rela->r_info),
232                (uintmax_t) symvalue, (int) ELF_R_TYPE (rela->r_info),
233                (uintmax_t) rela->r_offset, (int) rela->r_addend);
234      if (!rtems_rtl_elf_relocate_rela (obj, rela, targetsect,
235                                        symname, sym->st_info, symvalue))
236        return false;
237    }
238    else
239    {
240      if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
241        printf ("rtl: rel: sym:%s(%d)=%08jx type:%d off:%08jx\n",
242                symname, (int) ELF_R_SYM (rel->r_info),
243                (uintmax_t) symvalue, (int) ELF_R_TYPE (rel->r_info),
244                (uintmax_t) rel->r_offset);
245      if (!rtems_rtl_elf_relocate_rel (obj, rel, targetsect,
246                                       symname, sym->st_info, symvalue))
247        return false;
248    }
249
250    sobj = rtems_rtl_find_obj_with_symbol (symbol);
251    if (sobj != NULL)
252    {
253      if (rtems_rtl_obj_add_dependent (obj, sobj))
254        rtems_rtl_obj_inc_reference (sobj);
255    }
256  }
257
258  return true;
259}
260
261static bool
262rtems_rtl_elf_relocate_worker (rtems_rtl_obj*              obj,
263                               int                         fd,
264                               rtems_rtl_obj_sect*         sect,
265                               rtems_rtl_elf_reloc_handler handler,
266                               void*                       data)
267{
268  rtems_rtl_obj_cache* symbols;
269  rtems_rtl_obj_cache* strings;
270  rtems_rtl_obj_cache* relocs;
271  rtems_rtl_obj_sect*  targetsect;
272  rtems_rtl_obj_sect*  symsect;
273  rtems_rtl_obj_sect*  strtab;
274  bool                 is_rela;
275  size_t               reloc_size;
276  int                  reloc;
277
278  /*
279   * First check if the section the relocations are for exists. If it does not
280   * exist ignore these relocations. They are most probably debug sections.
281   */
282  targetsect = rtems_rtl_obj_find_section_by_index (obj, sect->info);
283  if (!targetsect)
284    return true;
285
286  rtems_rtl_obj_caches (&symbols, &strings, &relocs);
287
288  if (!symbols || !strings || !relocs)
289    return false;
290
291  symsect = rtems_rtl_obj_find_section (obj, ".symtab");
292  if (!symsect)
293  {
294    rtems_rtl_set_error (EINVAL, "no .symtab section");
295    return false;
296  }
297
298  strtab = rtems_rtl_obj_find_section (obj, ".strtab");
299  if (!strtab)
300  {
301    rtems_rtl_set_error (EINVAL, "no .strtab section");
302    return false;
303  }
304
305  if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
306    printf ("rtl: relocation: %s, syms:%s\n", sect->name, symsect->name);
307
308  /*
309   * Handle the different relocation record types.
310   */
311  is_rela = ((sect->flags & RTEMS_RTL_OBJ_SECT_RELA) ==
312             RTEMS_RTL_OBJ_SECT_RELA) ? true : false;
313  reloc_size = is_rela ? sizeof (Elf_Rela) : sizeof (Elf_Rel);
314
315  for (reloc = 0; reloc < (sect->size / reloc_size); ++reloc)
316  {
317    uint8_t            relbuf[reloc_size];
318    const Elf_Rela*    rela = (const Elf_Rela*) relbuf;
319    const Elf_Rel*     rel = (const Elf_Rel*) relbuf;
320    rtems_rtl_obj_sym* symbol = NULL;
321    Elf_Sym            sym;
322    const char*        symname = NULL;
323    off_t              off;
324    Elf_Word           rel_type;
325    Elf_Word           symvalue = 0;
326    bool               resolved;
327
328    off = obj->ooffset + sect->offset + (reloc * reloc_size);
329
330    if (!rtems_rtl_obj_cache_read_byval (relocs, fd, off,
331                                         &relbuf[0], reloc_size))
332      return false;
333
334    /*
335     * Read the symbol details.
336     */
337    if (is_rela)
338      off = (obj->ooffset + symsect->offset +
339             (ELF_R_SYM (rela->r_info) * sizeof (sym)));
340    else
341      off = (obj->ooffset + symsect->offset +
342             (ELF_R_SYM (rel->r_info) * sizeof (sym)));
343
344    if (!rtems_rtl_obj_cache_read_byval (symbols, fd, off,
345                                         &sym, sizeof (sym)))
346      return false;
347
348    /*
349     * Only need the name of the symbol if global or a common symbol.
350     */
351    if (ELF_ST_TYPE (sym.st_info) == STT_NOTYPE ||
352        sym.st_shndx == SHN_COMMON)
353    {
354      size_t len;
355      off = obj->ooffset + strtab->offset + sym.st_name;
356      len = RTEMS_RTL_ELF_STRING_MAX;
357
358      if (!rtems_rtl_obj_cache_read (strings, fd, off,
359                                     (void**) &symname, &len))
360        return false;
361    }
362
363    /*
364     * See if the record references an external symbol. If it does find the
365     * symbol value. If the symbol cannot be found flag the object file as
366     * having unresolved externals and store the external. The load of an
367     * object after this one may provide the unresolved externals.
368     */
369    if (is_rela)
370      rel_type = ELF_R_TYPE(rela->r_info);
371    else
372      rel_type = ELF_R_TYPE(rel->r_info);
373
374    resolved = true;
375
376    if (rtems_rtl_elf_rel_resolve_sym (rel_type))
377      resolved = rtems_rtl_elf_find_symbol (obj,
378                                            &sym, symname,
379                                            &symbol, &symvalue);
380
381    if (!handler (obj,
382                  is_rela, relbuf, targetsect,
383                  symbol, &sym, symname, symvalue, resolved,
384                  data))
385      return false;
386  }
387
388  /*
389   * Set the unresolved externals status if there are unresolved externals.
390   */
391  if (obj->unresolved)
392    obj->flags |= RTEMS_RTL_OBJ_UNRESOLVED;
393
394  return true;
395}
396
397static bool
398rtems_rtl_elf_relocs_parser (rtems_rtl_obj*      obj,
399                             int                 fd,
400                             rtems_rtl_obj_sect* sect,
401                             void*               data)
402{
403  bool r = rtems_rtl_elf_relocate_worker (obj, fd, sect,
404                                          rtems_rtl_elf_reloc_parser, data);
405  rtems_rtl_obj_update_flags (RTEMS_RTL_OBJ_RELOC_TAG, 0);
406  return r;
407}
408
409static bool
410rtems_rtl_elf_relocs_locator (rtems_rtl_obj*      obj,
411                              int                 fd,
412                              rtems_rtl_obj_sect* sect,
413                              void*               data)
414{
415  return rtems_rtl_elf_relocate_worker (obj, fd, sect,
416                                        rtems_rtl_elf_reloc_relocator, data);
417}
418
419bool
420rtems_rtl_obj_relocate_unresolved (rtems_rtl_unresolv_reloc* reloc,
421                                   rtems_rtl_obj_sym*        sym)
422{
423  rtems_rtl_obj_sect* sect;
424  bool                is_rela;
425  Elf_Word            symvalue;
426  rtems_rtl_obj*      sobj;
427
428  is_rela = reloc->flags & 1;
429
430  sect = rtems_rtl_obj_find_section_by_index (reloc->obj, reloc->sect);
431  if (!sect)
432  {
433    rtems_rtl_set_error (ENOEXEC, "unresolved sect not found");
434    return false;
435  }
436
437  symvalue = (Elf_Word) (intptr_t) sym->value;
438  if (is_rela)
439  {
440    Elf_Rela rela;
441    rela.r_offset = reloc->rel[REL_R_OFFSET];
442    rela.r_info = reloc->rel[REL_R_INFO];
443    rela.r_addend = reloc->rel[REL_R_ADDEND];
444    if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
445          printf ("rtl: rela: sym:%d type:%d off:%08jx addend:%d\n",
446                  (int) ELF_R_SYM (rela.r_info), (int) ELF_R_TYPE (rela.r_info),
447                  (uintmax_t) rela.r_offset, (int) rela.r_addend);
448    if (!rtems_rtl_elf_relocate_rela (reloc->obj, &rela, sect,
449                                      sym->name, sym->data, symvalue))
450      return false;
451  }
452  else
453  {
454    Elf_Rel rel;
455    rel.r_offset = reloc->rel[REL_R_OFFSET];
456    rel.r_info = reloc->rel[REL_R_INFO];
457    if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
458      printf ("rtl: rel: sym:%d type:%d off:%08jx\n",
459              (int) ELF_R_SYM (rel.r_info), (int) ELF_R_TYPE (rel.r_info),
460              (uintmax_t) rel.r_offset);
461    if (!rtems_rtl_elf_relocate_rel (reloc->obj, &rel, sect,
462                                     sym->name, sym->data, symvalue))
463      return false;
464  }
465
466  if (reloc->obj->unresolved > 0)
467  {
468    --reloc->obj->unresolved;
469    if (reloc->obj->unresolved == 0)
470      reloc->obj->flags &= ~RTEMS_RTL_OBJ_UNRESOLVED;
471  }
472
473  sobj = rtems_rtl_find_obj_with_symbol (sym);
474  if (sobj != NULL)
475  {
476    if (rtems_rtl_obj_add_dependent (reloc->obj, sobj))
477      rtems_rtl_obj_inc_reference (sobj);
478  }
479
480  return true;
481}
482
483/**
484 * Common symbol iterator data.
485 */
486typedef struct
487{
488  size_t   size;      /**< The size of the common section */
489  uint32_t alignment; /**< The alignment of the common section. */
490} rtems_rtl_elf_common_data;
491
492static bool
493rtems_rtl_elf_common (rtems_rtl_obj*      obj,
494                      int                 fd,
495                      rtems_rtl_obj_sect* sect,
496                      void*               data)
497{
498  rtems_rtl_elf_common_data* common = (rtems_rtl_elf_common_data*) data;
499  rtems_rtl_obj_cache*       symbols;
500  int                        sym;
501
502  rtems_rtl_obj_caches (&symbols, NULL, NULL);
503
504  if (!symbols)
505    return false;
506
507  /*
508   * Find the number size of the common section by finding all symbols that
509   * reference the SHN_COMMON section.
510   */
511  for (sym = 0; sym < (sect->size / sizeof (Elf_Sym)); ++sym)
512  {
513    Elf_Sym symbol;
514    off_t   off;
515
516    off = obj->ooffset + sect->offset + (sym * sizeof (symbol));
517
518    if (!rtems_rtl_obj_cache_read_byval (symbols, fd, off,
519                                         &symbol, sizeof (symbol)))
520      return false;
521
522    if ((symbol.st_shndx == SHN_COMMON) &&
523        ((ELF_ST_TYPE (symbol.st_info) == STT_OBJECT) ||
524         (ELF_ST_TYPE (symbol.st_info) == STT_COMMON)))
525    {
526      if (rtems_rtl_trace (RTEMS_RTL_TRACE_SYMBOL))
527        printf ("rtl: com:elf:%-2d bind:%-2d type:%-2d size:%d value:%d\n",
528                sym, (int) ELF_ST_BIND (symbol.st_info),
529                (int) ELF_ST_TYPE (symbol.st_info),
530                (int) symbol.st_size, (int) symbol.st_value);
531      /*
532       * If the size is zero this is the first entry, it defines the common
533       * section's aligment. The symbol's value is the alignment.
534       */
535      if (common->size == 0)
536        common->alignment = symbol.st_value;
537      common->size +=
538        rtems_rtl_obj_align (common->size, symbol.st_value) + symbol.st_size;
539    }
540  }
541
542  return true;
543}
544
545static bool
546rtems_rtl_elf_dependents (rtems_rtl_obj* obj, rtems_rtl_elf_reloc_data* reloc)
547{
548  /*
549   * If there are dependencies and no unresolved externals allocate and size
550   * the dependency table to the number of dependent object files. If there are
551   * unresolved externals the number of dependencies is unknown at this point
552   * in time so use dynamic allocation to allocate the block size number of
553   * entries when the entries are added.
554   */
555  if (reloc->dependents > 0 && reloc->unresolved == 0)
556  {
557    if (!rtems_rtl_obj_alloc_dependents (obj, reloc->dependents))
558      return false;
559  }
560  return true;
561}
562
563static bool
564rtems_rtl_elf_symbols (rtems_rtl_obj*      obj,
565                       int                 fd,
566                       rtems_rtl_obj_sect* sect,
567                       void*               data)
568{
569  rtems_rtl_obj_cache* symbols;
570  rtems_rtl_obj_cache* strings;
571  rtems_rtl_obj_sect*  strtab;
572  int                  locals;
573  int                  local_string_space;
574  rtems_rtl_obj_sym*   lsym;
575  char*                lstring;
576  int                  globals;
577  int                  global_string_space;
578  rtems_rtl_obj_sym*   gsym;
579  char*                gstring;
580  size_t               common_offset;
581  int                  sym;
582
583  strtab = rtems_rtl_obj_find_section (obj, ".strtab");
584  if (!strtab)
585  {
586    rtems_rtl_set_error (EINVAL, "no .strtab section");
587    return false;
588  }
589
590  rtems_rtl_obj_caches (&symbols, &strings, NULL);
591
592  if (!symbols || !strings)
593    return false;
594
595  /*
596   * Find the number of globals and the amount of string space
597   * needed. Also check for duplicate symbols.
598   */
599
600  globals             = 0;
601  global_string_space = 0;
602  locals              = 0;
603  local_string_space  = 0;
604
605  for (sym = 0; sym < (sect->size / sizeof (Elf_Sym)); ++sym)
606  {
607    Elf_Sym     symbol;
608    off_t       off;
609    const char* name;
610    size_t      len;
611
612    off = obj->ooffset + sect->offset + (sym * sizeof (symbol));
613
614    if (!rtems_rtl_obj_cache_read_byval (symbols, fd, off,
615                                         &symbol, sizeof (symbol)))
616      return false;
617
618    off = obj->ooffset + strtab->offset + symbol.st_name;
619    len = RTEMS_RTL_ELF_STRING_MAX;
620
621    if (!rtems_rtl_obj_cache_read (strings, fd, off, (void**) &name, &len))
622      return false;
623
624    /*
625     * Only keep the functions and global or weak symbols so place them in a
626     * separate table to local symbols. Local symbols are not needed after the
627     * object file has been loaded. Undefined symbols are NOTYPE so for locals
628     * we need to make sure there is a valid seciton.
629     */
630    if (rtems_rtl_trace (RTEMS_RTL_TRACE_SYMBOL))
631      printf ("rtl: sym:elf:%-2d name:%-2d:%-20s bind:%-2d " \
632              "type:%-2d sect:%d size:%d\n",
633              sym, (int) symbol.st_name, name,
634              (int) ELF_ST_BIND (symbol.st_info),
635              (int) ELF_ST_TYPE (symbol.st_info),
636              symbol.st_shndx,
637              (int) symbol.st_size);
638
639    if ((symbol.st_shndx != 0) &&
640        ((ELF_ST_TYPE (symbol.st_info) == STT_OBJECT) ||
641         (ELF_ST_TYPE (symbol.st_info) == STT_COMMON) ||
642         (ELF_ST_TYPE (symbol.st_info) == STT_FUNC) ||
643         (ELF_ST_TYPE (symbol.st_info) == STT_NOTYPE)))
644    {
645      /*
646       * There needs to be a valid section for the symbol.
647       */
648      rtems_rtl_obj_sect* symsect;
649
650      symsect = rtems_rtl_obj_find_section_by_index (obj, symbol.st_shndx);
651      if (symsect != NULL)
652      {
653        if ((ELF_ST_BIND (symbol.st_info) == STB_GLOBAL) ||
654            (ELF_ST_BIND (symbol.st_info) == STB_WEAK))
655        {
656          /*
657           * If there is a globally exported symbol already present and this
658           * symbol is not weak raise an error. If the symbol is weak and
659           * present globally ignore this symbol and use the global one and if
660           * it is not present take this symbol global or weak. We accept the
661           * first weak symbol we find and make it globally exported.
662           */
663          if (rtems_rtl_symbol_global_find (name) &&
664              (ELF_ST_BIND (symbol.st_info) != STB_WEAK))
665          {
666            rtems_rtl_set_error (ENOMEM, "duplicate global symbol: %s", name);
667            return false;
668          }
669          else
670          {
671            if (rtems_rtl_trace (RTEMS_RTL_TRACE_SYMBOL))
672              printf ("rtl: sym:elf:%-2d name:%-2d:%-20s: global\n",
673                      sym, (int) symbol.st_name, name);
674            ++globals;
675            global_string_space += strlen (name) + 1;
676          }
677        }
678        else if (ELF_ST_BIND (symbol.st_info) == STB_LOCAL)
679        {
680          if (rtems_rtl_trace (RTEMS_RTL_TRACE_SYMBOL))
681            printf ("rtl: sym:elf:%-2d name:%-2d:%-20s: local\n",
682                    sym, (int) symbol.st_name, name);
683          ++locals;
684          local_string_space += strlen (name) + 1;
685        }
686      }
687    }
688  }
689
690  if (locals)
691  {
692    obj->local_size = locals * sizeof (rtems_rtl_obj_sym) + local_string_space;
693    obj->local_table = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_SYMBOL,
694                                            obj->local_size, true);
695    if (!obj->local_table)
696    {
697      obj->local_size = 0;
698      rtems_rtl_set_error (ENOMEM, "no memory for obj local syms");
699      return false;
700    }
701
702    obj->local_syms = locals;
703  }
704
705  if (globals)
706  {
707    obj->global_size = globals * sizeof (rtems_rtl_obj_sym) + global_string_space;
708    obj->global_table = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_SYMBOL,
709                                             obj->global_size, true);
710    if (!obj->global_table)
711    {
712      if (locals)
713      {
714        rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, obj->local_table);
715        obj->local_size = 0;
716        obj->local_syms = 0;
717      }
718      obj->global_size = 0;
719      rtems_rtl_set_error (ENOMEM, "no memory for obj global syms");
720      return false;
721    }
722
723    obj->global_syms = globals;
724  }
725
726  lsym = obj->local_table;
727  lstring =
728    (((char*) obj->local_table) + (locals * sizeof (rtems_rtl_obj_sym)));
729  gsym = obj->global_table;
730  gstring =
731    (((char*) obj->global_table) + (globals * sizeof (rtems_rtl_obj_sym)));
732
733  common_offset = 0;
734
735  for (sym = 0; sym < (sect->size / sizeof (Elf_Sym)); ++sym)
736  {
737    Elf_Sym     symbol;
738    off_t       off;
739    const char* name;
740    size_t      len;
741
742    off = obj->ooffset + sect->offset + (sym * sizeof (symbol));
743
744    if (!rtems_rtl_obj_cache_read_byval (symbols, fd, off,
745                                         &symbol, sizeof (symbol)))
746    {
747      if (locals)
748      {
749        rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, obj->local_table);
750        obj->local_table = NULL;
751        obj->local_size = 0;
752        obj->local_syms = 0;
753      }
754      if (globals)
755      {
756        rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, obj->global_table);
757        obj->global_table = NULL;
758        obj->global_syms = 0;
759        obj->global_size = 0;
760      }
761      return false;
762    }
763
764    off = obj->ooffset + strtab->offset + symbol.st_name;
765    len = RTEMS_RTL_ELF_STRING_MAX;
766
767    if (!rtems_rtl_obj_cache_read (strings, fd, off, (void**) &name, &len))
768      return false;
769
770    if ((symbol.st_shndx != 0) &&
771        ((ELF_ST_TYPE (symbol.st_info) == STT_OBJECT) ||
772         (ELF_ST_TYPE (symbol.st_info) == STT_COMMON) ||
773         (ELF_ST_TYPE (symbol.st_info) == STT_FUNC) ||
774         (ELF_ST_TYPE (symbol.st_info) == STT_NOTYPE)) &&
775         ((ELF_ST_BIND (symbol.st_info) == STB_GLOBAL) ||
776          (ELF_ST_BIND (symbol.st_info) == STB_WEAK) ||
777          (ELF_ST_BIND (symbol.st_info) == STB_LOCAL)))
778      {
779        rtems_rtl_obj_sect* symsect;
780        rtems_rtl_obj_sym*  osym;
781        char*               string;
782        Elf_Word            value;
783
784        symsect = rtems_rtl_obj_find_section_by_index (obj, symbol.st_shndx);
785        if (symsect)
786        {
787          if ((ELF_ST_BIND (symbol.st_info) == STB_GLOBAL) ||
788              (ELF_ST_BIND (symbol.st_info) == STB_WEAK))
789          {
790            osym = gsym;
791            string = gstring;
792            gstring += strlen (name) + 1;
793            ++gsym;
794          }
795          else
796          {
797            osym = lsym;
798            string = lstring;
799            lstring += strlen (name) + 1;
800            ++lsym;
801          }
802
803          /*
804           * Allocate any common symbols in the common section.
805           */
806          if (symbol.st_shndx == SHN_COMMON)
807          {
808            size_t value_off = rtems_rtl_obj_align (common_offset,
809                                                    symbol.st_value);
810            common_offset = value_off + symbol.st_size;
811            value = value_off;
812          }
813          else
814          {
815            value = symbol.st_value;
816          }
817
818          rtems_chain_set_off_chain (&osym->node);
819          memcpy (string, name, strlen (name) + 1);
820          osym->name = string;
821          osym->value = value + (uint8_t*) symsect->base;
822          osym->data = symbol.st_info;
823
824          if (rtems_rtl_trace (RTEMS_RTL_TRACE_SYMBOL))
825            printf ("rtl: sym:add:%-2d name:%-2d:%-20s bind:%-2d " \
826                    "type:%-2d val:%8p sect:%d size:%d\n",
827                    sym, (int) symbol.st_name, osym->name,
828                    (int) ELF_ST_BIND (symbol.st_info),
829                    (int) ELF_ST_TYPE (symbol.st_info),
830                    osym->value, symbol.st_shndx,
831                    (int) symbol.st_size);
832        }
833      }
834  }
835
836  if (globals)
837    rtems_rtl_symbol_obj_add (obj);
838
839  return true;
840}
841
842static bool
843rtems_rtl_elf_loader (rtems_rtl_obj*      obj,
844                      int                 fd,
845                      rtems_rtl_obj_sect* sect,
846                      void*               data)
847{
848  uint8_t* base_offset;
849  size_t   len;
850
851  if (lseek (fd, obj->ooffset + sect->offset, SEEK_SET) < 0)
852  {
853    rtems_rtl_set_error (errno, "section load seek failed");
854    return false;
855  }
856
857  base_offset = sect->base;
858  len = sect->size;
859
860  while (len)
861  {
862    ssize_t r = read (fd, base_offset, len);
863    if (r <= 0)
864    {
865      rtems_rtl_set_error (errno, "section load read failed");
866      return false;
867    }
868    base_offset += r;
869    len -= r;
870  }
871
872  return true;
873}
874
875static bool
876rtems_rtl_elf_parse_sections (rtems_rtl_obj* obj, int fd, Elf_Ehdr* ehdr)
877{
878  rtems_rtl_obj_cache* sects;
879  rtems_rtl_obj_cache* strings;
880  int                  section;
881  off_t                sectstroff;
882  off_t                off;
883  Elf_Shdr             shdr;
884
885  rtems_rtl_obj_caches (&sects, &strings, NULL);
886
887  if (!sects || !strings)
888    return false;
889
890  /*
891   * Get the offset to the section string table.
892   */
893  off = obj->ooffset + ehdr->e_shoff + (ehdr->e_shstrndx * ehdr->e_shentsize);
894
895  if (!rtems_rtl_obj_cache_read_byval (sects, fd, off, &shdr, sizeof (shdr)))
896    return false;
897
898  if (shdr.sh_type != SHT_STRTAB)
899  {
900    rtems_rtl_set_error (EINVAL, "bad .sectstr section type");
901    return false;
902  }
903
904  sectstroff = obj->ooffset + shdr.sh_offset;
905
906  for (section = 0; section < ehdr->e_shnum; ++section)
907  {
908    uint32_t flags;
909
910    /*
911     * Make sure section is at least 32bits to avoid 16-bit overflow errors.
912     */
913    off = obj->ooffset + ehdr->e_shoff + (((uint32_t) section) * ehdr->e_shentsize);
914
915    if (rtems_rtl_trace (RTEMS_RTL_TRACE_DETAIL))
916      printf ("rtl: section header: %2d: offset=%d\n", section, (int) off);
917
918    if (!rtems_rtl_obj_cache_read_byval (sects, fd, off, &shdr, sizeof (shdr)))
919      return false;
920
921    if (rtems_rtl_trace (RTEMS_RTL_TRACE_DETAIL))
922      printf ("rtl: section: %2d: type=%d flags=%08x link=%d info=%d\n",
923              section, (int) shdr.sh_type, (unsigned int) shdr.sh_flags,
924              (int) shdr.sh_link, (int) shdr.sh_info);
925
926    flags = 0;
927
928    switch (shdr.sh_type)
929    {
930      case SHT_NULL:
931        /*
932         * Ignore.
933         */
934        break;
935
936      case SHT_PROGBITS:
937        /*
938         * There are 2 program bits sections. One is the program text and the
939         * other is the program data. The program text is flagged
940         * alloc/executable and the program data is flagged alloc/writable.
941         */
942        if ((shdr.sh_flags & SHF_ALLOC) == SHF_ALLOC)
943        {
944          if ((shdr.sh_flags & SHF_EXECINSTR) == SHF_EXECINSTR)
945            flags = RTEMS_RTL_OBJ_SECT_TEXT | RTEMS_RTL_OBJ_SECT_LOAD;
946          else if ((shdr.sh_flags & SHF_WRITE) == SHF_WRITE)
947            flags = RTEMS_RTL_OBJ_SECT_DATA | RTEMS_RTL_OBJ_SECT_LOAD;
948          else
949            flags = RTEMS_RTL_OBJ_SECT_CONST | RTEMS_RTL_OBJ_SECT_LOAD;
950        }
951        break;
952
953      case SHT_NOBITS:
954        /*
955         * There is 1 NOBIT section which is the .bss section. There is nothing
956         * but a definition as the .bss is just a clear region of memory.
957         */
958        if ((shdr.sh_flags & (SHF_ALLOC | SHF_WRITE)) == (SHF_ALLOC | SHF_WRITE))
959          flags = RTEMS_RTL_OBJ_SECT_BSS | RTEMS_RTL_OBJ_SECT_ZERO;
960        break;
961
962      case SHT_RELA:
963        flags = RTEMS_RTL_OBJ_SECT_RELA;
964        break;
965
966      case SHT_REL:
967        /*
968         * The sh_link holds the section index for the symbol table. The sh_info
969         * holds the section index the relocations apply to.
970         */
971        flags = RTEMS_RTL_OBJ_SECT_REL;
972        break;
973
974      case SHT_SYMTAB:
975        flags = RTEMS_RTL_OBJ_SECT_SYM;
976        break;
977
978      case SHT_STRTAB:
979        flags = RTEMS_RTL_OBJ_SECT_STR;
980        break;
981
982      default:
983        /*
984         * See if there are architecture specific flags?
985         */
986        flags = rtems_rtl_elf_section_flags (obj, &shdr);
987        if (flags == 0)
988        {
989          if (rtems_rtl_trace (RTEMS_RTL_TRACE_WARNING))
990            printf ("rtl: unsupported section: %2d: type=%02d flags=%02x\n",
991                    section, (int) shdr.sh_type, (int) shdr.sh_flags);
992        }
993        break;
994    }
995
996    if (flags != 0)
997    {
998      char*  name;
999      size_t len;
1000
1001      /*
1002       * If link ordering this section must appear in the same order in memory
1003       * as the linked-to section relative to the sections it loads with.
1004       */
1005      if ((shdr.sh_flags & SHF_LINK_ORDER) != 0)
1006        flags |= RTEMS_RTL_OBJ_SECT_LINK;
1007
1008      len = RTEMS_RTL_ELF_STRING_MAX;
1009      if (!rtems_rtl_obj_cache_read (strings, fd,
1010                                     sectstroff + shdr.sh_name,
1011                                     (void**) &name, &len))
1012        return false;
1013
1014      if (strcmp (".ctors", name) == 0)
1015        flags |= RTEMS_RTL_OBJ_SECT_CTOR;
1016      if (strcmp (".dtors", name) == 0)
1017        flags |= RTEMS_RTL_OBJ_SECT_DTOR;
1018
1019      if (rtems_rtl_elf_unwind_parse (obj, name, flags))
1020      {
1021        flags &= ~(RTEMS_RTL_OBJ_SECT_TEXT | RTEMS_RTL_OBJ_SECT_CONST);
1022        flags |= RTEMS_RTL_OBJ_SECT_EH;
1023      }
1024
1025      if (!rtems_rtl_obj_add_section (obj, section, name,
1026                                      shdr.sh_size, shdr.sh_offset,
1027                                      shdr.sh_addralign, shdr.sh_link,
1028                                      shdr.sh_info, flags))
1029        return false;
1030    }
1031  }
1032
1033  return true;
1034}
1035
1036static bool
1037rtems_rtl_elf_add_common (rtems_rtl_obj* obj, size_t size, uint32_t alignment)
1038{
1039  if (size > 0)
1040  {
1041    if (!rtems_rtl_obj_add_section (obj, SHN_COMMON, ".common.rtems.rtl",
1042                                    size, 0, alignment, 0, 0,
1043                                    RTEMS_RTL_OBJ_SECT_BSS | RTEMS_RTL_OBJ_SECT_ZERO))
1044      return false;
1045  }
1046  return true;
1047}
1048
1049bool
1050rtems_rtl_elf_file_check (rtems_rtl_obj* obj, int fd)
1051{
1052  rtems_rtl_obj_cache* header;
1053  Elf_Ehdr             ehdr;
1054
1055  rtems_rtl_obj_caches (&header, NULL, NULL);
1056
1057  if (!rtems_rtl_obj_cache_read_byval (header, fd, obj->ooffset,
1058                                       &ehdr, sizeof (ehdr)))
1059    return false;
1060
1061  /*
1062   * Check we have a valid ELF file.
1063   */
1064  if ((memcmp (ELFMAG, ehdr.e_ident, SELFMAG) != 0)
1065      || ehdr.e_ident[EI_CLASS] != ELFCLASS)
1066  {
1067    return false;
1068  }
1069
1070  if ((ehdr.e_ident[EI_VERSION] != EV_CURRENT)
1071      || (ehdr.e_version != EV_CURRENT)
1072      || (ehdr.e_ident[EI_DATA] != ELFDEFNNAME (MACHDEP_ENDIANNESS)))
1073  {
1074    return false;
1075  }
1076
1077  return true;
1078}
1079
1080static bool
1081rtems_rtl_elf_load_linkmap (rtems_rtl_obj* obj)
1082{
1083  rtems_chain_control* sections = NULL;
1084  rtems_chain_node*    node = NULL;
1085  size_t               mask = 0;
1086  int                  sec_num = 0;
1087  section_detail*      sd;
1088  int                  i = 0;
1089
1090  /*
1091   * Caculate the size of sections' name.
1092   */
1093
1094  for (mask = RTEMS_RTL_OBJ_SECT_TEXT;
1095       mask <= RTEMS_RTL_OBJ_SECT_BSS;
1096       mask <<= 1)
1097  {
1098    sections = &obj->sections;
1099    node = rtems_chain_first (sections);
1100    while (!rtems_chain_is_tail (sections, node))
1101    {
1102      rtems_rtl_obj_sect* sect = (rtems_rtl_obj_sect*) node;
1103      if ((sect->size != 0) && ((sect->flags & mask) != 0))
1104      {
1105        ++sec_num;
1106      }
1107      node = rtems_chain_next (node);
1108    }
1109  }
1110
1111  obj->obj_num = 1;
1112  obj->linkmap = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT,
1113                                      sizeof(struct link_map) +
1114                                      sec_num * sizeof (section_detail), true);
1115  if (!obj->linkmap)
1116  {
1117    rtems_rtl_set_error (ENOMEM, "no memory for obj linkmap");
1118    return false;
1119  }
1120
1121  obj->linkmap->name = obj->oname;
1122  obj->linkmap->sec_num = sec_num;
1123  obj->linkmap->sec_detail = (section_detail*) (obj->linkmap + 1);
1124  obj->linkmap->rpathlen = 0;
1125  obj->linkmap->rpath = NULL;
1126  obj->linkmap->l_next = NULL;
1127  obj->linkmap->l_prev = NULL;
1128  obj->linkmap->sec_addr[rap_text] = obj->text_base;
1129  obj->linkmap->sec_addr[rap_const] = obj->const_base;
1130  obj->linkmap->sec_addr[rap_data] = obj->data_base;
1131  obj->linkmap->sec_addr[rap_bss] = obj->bss_base;
1132
1133  sd = obj->linkmap->sec_detail;
1134  sections = &obj->sections;
1135  node = rtems_chain_first (sections);
1136
1137  for (mask = RTEMS_RTL_OBJ_SECT_TEXT;
1138       mask <= RTEMS_RTL_OBJ_SECT_BSS;
1139       mask <<= 1)
1140  {
1141    sections = &obj->sections;
1142    node = rtems_chain_first (sections);
1143    while (!rtems_chain_is_tail (sections, node))
1144    {
1145      rtems_rtl_obj_sect* sect = (rtems_rtl_obj_sect*) node;
1146
1147      if ((sect->size != 0) && ((sect->flags & mask) != 0))
1148      {
1149        sd[i].name = sect->name;
1150        sd[i].size = sect->size;
1151        if (mask == RTEMS_RTL_OBJ_SECT_TEXT)
1152        {
1153          sd[i].rap_id = rap_text;
1154          sd[i].offset = sect->base - obj->text_base;
1155        }
1156        if (mask == RTEMS_RTL_OBJ_SECT_CONST)
1157        {
1158          sd[i].rap_id = rap_const;
1159          sd[i].offset = sect->base - obj->const_base;
1160        }
1161        if (mask == RTEMS_RTL_OBJ_SECT_DATA)
1162        {
1163          sd[i].rap_id = rap_data;
1164          sd[i].offset = sect->base - obj->data_base;
1165        }
1166        if (mask == RTEMS_RTL_OBJ_SECT_BSS)
1167        {
1168          sd[i].rap_id = rap_bss;
1169          sd[i].offset = sect->base - obj->bss_base;
1170        }
1171
1172        ++i;
1173      }
1174      node = rtems_chain_next (node);
1175    }
1176  }
1177
1178  return true;
1179}
1180
1181bool
1182rtems_rtl_elf_file_load (rtems_rtl_obj* obj, int fd)
1183{
1184  rtems_rtl_obj_cache*      header;
1185  Elf_Ehdr                  ehdr;
1186  rtems_rtl_elf_reloc_data  relocs = { 0 };
1187  rtems_rtl_elf_common_data common = { 0 };
1188
1189  rtems_rtl_obj_caches (&header, NULL, NULL);
1190
1191  if (!rtems_rtl_obj_cache_read_byval (header, fd, obj->ooffset,
1192                                       &ehdr, sizeof (ehdr)))
1193    return false;
1194
1195  /*
1196   * Check we have a valid ELF file.
1197   */
1198  if ((memcmp (ELFMAG, ehdr.e_ident, SELFMAG) != 0)
1199      || ehdr.e_ident[EI_CLASS] != ELFCLASS)
1200  {
1201    rtems_rtl_set_error (EINVAL, "invalid ELF file format");
1202    return false;
1203  }
1204
1205  if ((ehdr.e_ident[EI_VERSION] != EV_CURRENT)
1206      || (ehdr.e_version != EV_CURRENT)
1207      || (ehdr.e_ident[EI_DATA] != ELFDEFNNAME (MACHDEP_ENDIANNESS)))
1208  {
1209    rtems_rtl_set_error (EINVAL, "unsupported ELF file version");
1210    return false;
1211  }
1212
1213  if (!rtems_rtl_elf_machine_check (&ehdr))
1214  {
1215    rtems_rtl_set_error (EINVAL, "unsupported machine type");
1216    return false;
1217  }
1218
1219  if (ehdr.e_type == ET_DYN)
1220  {
1221    rtems_rtl_set_error (EINVAL, "unsupported ELF file type");
1222    return false;
1223  }
1224
1225  if (ehdr.e_phentsize != 0)
1226  {
1227    rtems_rtl_set_error (EINVAL, "ELF file contains program headers");
1228    return false;
1229  }
1230
1231  if (ehdr.e_shentsize != sizeof (Elf_Shdr))
1232  {
1233    rtems_rtl_set_error (EINVAL, "invalid ELF section header size");
1234    return false;
1235  }
1236
1237  /*
1238   * Parse the section information first so we have the memory map of the object
1239   * file and the memory allocated. Any further allocations we make to complete
1240   * the load will not fragment the memory.
1241   */
1242  if (!rtems_rtl_elf_parse_sections (obj, fd, &ehdr))
1243    return false;
1244
1245  /*
1246   * See if there are any common variables and if there are add a common
1247   * section.
1248   */
1249  if (!rtems_rtl_obj_load_symbols (obj, fd, rtems_rtl_elf_common, &common))
1250    return false;
1251  if (!rtems_rtl_elf_add_common (obj, common.size, common.alignment))
1252    return false;
1253
1254  /*
1255   * Set the entry point if there is one.
1256   */
1257  obj->entry = (void*)(uintptr_t) ehdr.e_entry;
1258
1259  /*
1260   * Load the sections and symbols and then relocation to the base address.
1261   */
1262  if (!rtems_rtl_obj_load_sections (obj, fd, rtems_rtl_elf_loader, &ehdr))
1263    return false;
1264
1265  if (!rtems_rtl_obj_relocate (obj, fd, rtems_rtl_elf_relocs_parser, &relocs))
1266    return false;
1267
1268  if (!rtems_rtl_elf_dependents (obj, &relocs))
1269    return false;
1270
1271  if (!rtems_rtl_obj_load_symbols (obj, fd, rtems_rtl_elf_symbols, &ehdr))
1272    return false;
1273
1274  if (!rtems_rtl_obj_relocate (obj, fd, rtems_rtl_elf_relocs_locator, &ehdr))
1275    return false;
1276
1277  rtems_rtl_obj_synchronize_cache (obj);
1278
1279  rtems_rtl_symbol_obj_erase_local (obj);
1280
1281  if (!rtems_rtl_elf_load_linkmap (obj))
1282  {
1283    return false;
1284  }
1285
1286  if (!rtems_rtl_elf_unwind_register (obj))
1287  {
1288    return false;
1289  }
1290
1291  return true;
1292}
1293
1294bool
1295rtems_rtl_elf_file_unload (rtems_rtl_obj* obj)
1296{
1297  rtems_rtl_elf_unwind_deregister (obj);
1298  return true;
1299}
1300
1301rtems_rtl_loader_format*
1302rtems_rtl_elf_file_sig (void)
1303{
1304  return &elf_sig;
1305}
Note: See TracBrowser for help on using the repository browser.