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

5
Last change on this file since bba48d9 was bba48d9, checked in by Chris Johns <chrisj@…>, on 03/30/17 at 00:06:24

libdl: Support link ordered loading of ELF sections.

The ARM C++ exception ABI uses an address ordered index table to
locate the correct frame data and this requires the EXIDX sections are
loaded in the order the order the matching text is loaded.

The EXIDX sections set the SHF_LINK_ORDER flag and link field. This patch
adds support to load those flagged sections in the linked-to section
order.

Updates #2955.
Closes #2959

  • Property mode set to 100644
File size: 27.5 KB
Line 
1/*
2 *  COPYRIGHT (c) 2012-2014 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 "rtl-trace.h"
33#include "rtl-unwind.h"
34#include "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_t 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
67bool
68rtems_rtl_elf_find_symbol (rtems_rtl_obj_t* obj,
69                           const Elf_Sym*   sym,
70                           const char*      symname,
71                           Elf_Word*        value)
72{
73  rtems_rtl_obj_sect_t* sect;
74
75  if (ELF_ST_TYPE(sym->st_info) == STT_NOTYPE)
76  {
77    /*
78     * Search the object file then the global table for the symbol.
79     */
80    rtems_rtl_obj_sym_t* symbol = rtems_rtl_symbol_obj_find (obj, symname);
81    if (!symbol)
82    {
83      rtems_rtl_set_error (EINVAL, "global symbol not found: %s", symname);
84      return false;
85    }
86
87    *value = (Elf_Word) symbol->value;
88    return true;
89  }
90
91  sect = rtems_rtl_obj_find_section_by_index (obj, sym->st_shndx);
92  if (!sect)
93  {
94    rtems_rtl_set_error (EINVAL, "reloc symbol's section not found");
95    return false;
96  }
97
98  *value = sym->st_value + (Elf_Word) sect->base;
99  return true;
100}
101
102static bool
103rtems_rtl_elf_relocator (rtems_rtl_obj_t*      obj,
104                         int                   fd,
105                         rtems_rtl_obj_sect_t* sect,
106                         void*                 data)
107{
108  rtems_rtl_obj_cache_t* symbols;
109  rtems_rtl_obj_cache_t* strings;
110  rtems_rtl_obj_cache_t* relocs;
111  rtems_rtl_obj_sect_t*  targetsect;
112  rtems_rtl_obj_sect_t*  symsect;
113  rtems_rtl_obj_sect_t*  strtab;
114  bool                   is_rela;
115  size_t                 reloc_size;
116  int                    reloc;
117
118  /*
119   * First check if the section the relocations are for exists. If it does not
120   * exist ignore these relocations. They are most probably debug sections.
121   */
122  targetsect = rtems_rtl_obj_find_section_by_index (obj, sect->info);
123  if (!targetsect)
124    return true;
125
126  rtems_rtl_obj_caches (&symbols, &strings, &relocs);
127
128  if (!symbols || !strings || !relocs)
129    return false;
130
131  symsect = rtems_rtl_obj_find_section (obj, ".symtab");
132  if (!symsect)
133  {
134    rtems_rtl_set_error (EINVAL, "no .symtab section");
135    return false;
136  }
137
138  strtab = rtems_rtl_obj_find_section (obj, ".strtab");
139  if (!strtab)
140  {
141    rtems_rtl_set_error (EINVAL, "no .strtab section");
142    return false;
143  }
144
145  if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
146    printf ("rtl: relocation: %s, syms:%s\n", sect->name, symsect->name);
147
148  /*
149   * Handle the different relocation record types.
150   */
151  is_rela = ((sect->flags & RTEMS_RTL_OBJ_SECT_RELA) ==
152             RTEMS_RTL_OBJ_SECT_RELA) ? true : false;
153  reloc_size = is_rela ? sizeof (Elf_Rela) : sizeof (Elf_Rel);
154
155  for (reloc = 0; reloc < (sect->size / reloc_size); ++reloc)
156  {
157    uint8_t         relbuf[reloc_size];
158    const Elf_Rela* rela = (const Elf_Rela*) relbuf;
159    const Elf_Rel*  rel = (const Elf_Rel*) relbuf;
160    Elf_Sym         sym;
161    const char*     symname = NULL;
162    off_t           off;
163    Elf_Word        type;
164    Elf_Word        symvalue = 0;
165    bool            relocate;
166
167    off = obj->ooffset + sect->offset + (reloc * reloc_size);
168
169    if (!rtems_rtl_obj_cache_read_byval (relocs, fd, off,
170                                         &relbuf[0], reloc_size))
171      return false;
172
173    /*
174     * Read the symbol details.
175     */
176    if (is_rela)
177      off = (obj->ooffset + symsect->offset +
178             (ELF_R_SYM (rela->r_info) * sizeof (sym)));
179    else
180      off = (obj->ooffset + symsect->offset +
181             (ELF_R_SYM (rel->r_info) * sizeof (sym)));
182
183    if (!rtems_rtl_obj_cache_read_byval (symbols, fd, off,
184                                         &sym, sizeof (sym)))
185      return false;
186
187    /*
188     * Only need the name of the symbol if global.
189     */
190    if (ELF_ST_TYPE (sym.st_info) == STT_NOTYPE)
191    {
192      size_t len;
193      off = obj->ooffset + strtab->offset + sym.st_name;
194      len = RTEMS_RTL_ELF_STRING_MAX;
195
196      if (!rtems_rtl_obj_cache_read (strings, fd, off,
197                                     (void**) &symname, &len))
198        return false;
199    }
200
201    /*
202     * See if the record references an external symbol. If it does find the
203     * symbol value. If the symbol cannot be found flag the object file as
204     * having unresolved externals and store the externals. The load of an
205     * object after this one may provide the unresolved externals.
206     */
207    if (is_rela)
208      type = ELF_R_TYPE(rela->r_info);
209    else
210      type = ELF_R_TYPE(rel->r_info);
211
212    relocate = true;
213
214    if (rtems_rtl_elf_rel_resolve_sym (type))
215    {
216      if (!rtems_rtl_elf_find_symbol (obj, &sym, symname, &symvalue))
217      {
218        uint16_t         flags = 0;
219        rtems_rtl_word_t rel_words[3];
220
221        relocate = false;
222
223        if (is_rela)
224        {
225          flags = 1;
226          rel_words[REL_R_OFFSET] = rela->r_offset;
227          rel_words[REL_R_INFO] = rela->r_info;
228          rel_words[REL_R_ADDEND] = rela->r_addend;
229        }
230        else
231        {
232          rel_words[REL_R_OFFSET] = rel->r_offset;
233          rel_words[REL_R_INFO] = rel->r_info;
234          rel_words[REL_R_ADDEND] = 0;
235        }
236
237        if (!rtems_rtl_unresolved_add (obj,
238                                       flags,
239                                       symname,
240                                       targetsect->section,
241                                       rel_words))
242          return false;
243
244        ++obj->unresolved;
245      }
246    }
247
248    if (relocate)
249    {
250      if (is_rela)
251      {
252        if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
253          printf ("rtl: rela: sym:%s(%d)=%08lx type:%d off:%08lx addend:%d\n",
254                  symname, (int) ELF_R_SYM (rela->r_info), symvalue,
255                  (int) ELF_R_TYPE (rela->r_info), rela->r_offset, (int) rela->r_addend);
256        if (!rtems_rtl_elf_relocate_rela (obj, rela, targetsect,
257                                          symname, sym.st_info, symvalue))
258          return false;
259      }
260      else
261      {
262        if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
263          printf ("rtl: rel: sym:%s(%d)=%08lx type:%d off:%08lx\n",
264                  symname, (int) ELF_R_SYM (rel->r_info), symvalue,
265                  (int) ELF_R_TYPE (rel->r_info), rel->r_offset);
266        if (!rtems_rtl_elf_relocate_rel (obj, rel, targetsect,
267                                         symname, sym.st_info, symvalue))
268          return false;
269      }
270    }
271  }
272
273  /*
274   * Set the unresolved externals status if there are unresolved externals.
275   */
276  if (obj->unresolved)
277    obj->flags |= RTEMS_RTL_OBJ_UNRESOLVED;
278
279  return true;
280}
281
282bool
283rtems_rtl_obj_relocate_unresolved (rtems_rtl_unresolv_reloc_t* reloc,
284                                   rtems_rtl_obj_sym_t*        sym)
285{
286  rtems_rtl_obj_sect_t* sect;
287  bool                  is_rela;
288  Elf_Word              symvalue;
289
290  is_rela =reloc->flags & 1;
291
292  sect = rtems_rtl_obj_find_section_by_index (reloc->obj, reloc->sect);
293  if (!sect)
294  {
295    rtems_rtl_set_error (ENOEXEC, "unresolved sect not found");
296    return false;
297  }
298
299  symvalue = (Elf_Word) (intptr_t) sym->value;
300  if (is_rela)
301  {
302    Elf_Rela rela;
303    rela.r_offset = reloc->rel[REL_R_OFFSET];
304    rela.r_info = reloc->rel[REL_R_INFO];
305    rela.r_addend = reloc->rel[REL_R_ADDEND];
306    if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
307          printf ("rtl: rela: sym:%d type:%d off:%08lx addend:%d\n",
308                  (int) ELF_R_SYM (rela.r_info), (int) ELF_R_TYPE (rela.r_info),
309                  rela.r_offset, (int) rela.r_addend);
310    if (!rtems_rtl_elf_relocate_rela (reloc->obj, &rela, sect,
311                                      sym->name, sym->data, symvalue))
312      return false;
313  }
314  else
315  {
316    Elf_Rel rel;
317    rel.r_offset = reloc->rel[REL_R_OFFSET];
318    rel.r_info = reloc->rel[REL_R_INFO];
319    if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
320      printf ("rtl: rel: sym:%d type:%d off:%08lx\n",
321              (int) ELF_R_SYM (rel.r_info), (int) ELF_R_TYPE (rel.r_info),
322              rel.r_offset);
323    if (!rtems_rtl_elf_relocate_rel (reloc->obj, &rel, sect,
324                                     sym->name, sym->data, symvalue))
325      return false;
326  }
327
328  if (reloc->obj->unresolved)
329  {
330    --reloc->obj->unresolved;
331    if (!reloc->obj->unresolved)
332      reloc->obj->flags &= ~RTEMS_RTL_OBJ_UNRESOLVED;
333  }
334
335  return true;
336}
337
338static bool
339rtems_rtl_elf_symbols (rtems_rtl_obj_t*      obj,
340                       int                   fd,
341                       rtems_rtl_obj_sect_t* sect,
342                       void*                 data)
343{
344  rtems_rtl_obj_cache_t* symbols;
345  rtems_rtl_obj_cache_t* strings;
346  rtems_rtl_obj_sect_t*  strtab;
347  int                    locals;
348  int                    local_string_space;
349  rtems_rtl_obj_sym_t*   lsym;
350  char*                  lstring;
351  int                    globals;
352  int                    global_string_space;
353  rtems_rtl_obj_sym_t*   gsym;
354  char*                  gstring;
355  int                    sym;
356
357  strtab = rtems_rtl_obj_find_section (obj, ".strtab");
358  if (!strtab)
359  {
360    rtems_rtl_set_error (EINVAL, "no .strtab section");
361    return false;
362  }
363
364  rtems_rtl_obj_caches (&symbols, &strings, NULL);
365
366  if (!symbols || !strings)
367    return false;
368
369  /*
370   * Find the number of globals and the amount of string space
371   * needed. Also check for duplicate symbols.
372   */
373
374  globals             = 0;
375  global_string_space = 0;
376  locals              = 0;
377  local_string_space  = 0;
378
379  for (sym = 0; sym < (sect->size / sizeof (Elf_Sym)); ++sym)
380  {
381    Elf_Sym     symbol;
382    off_t       off;
383    const char* name;
384    size_t      len;
385
386    off = obj->ooffset + sect->offset + (sym * sizeof (symbol));
387
388    if (!rtems_rtl_obj_cache_read_byval (symbols, fd, off,
389                                         &symbol, sizeof (symbol)))
390      return false;
391
392    off = obj->ooffset + strtab->offset + symbol.st_name;
393    len = RTEMS_RTL_ELF_STRING_MAX;
394
395    if (!rtems_rtl_obj_cache_read (strings, fd, off, (void**) &name, &len))
396      return false;
397
398    /*
399     * Only keep the functions and global or weak symbols so place them in a
400     * separate table to local symbols. Local symbols are not needed after the
401     * object file has been loaded. Undefined symbols are NOTYPE so for locals
402     * we need to make sure there is a valid seciton.
403     */
404    if ((symbol.st_shndx != 0) &&
405        ((ELF_ST_TYPE (symbol.st_info) == STT_OBJECT) ||
406         (ELF_ST_TYPE (symbol.st_info) == STT_FUNC) ||
407         (ELF_ST_TYPE (symbol.st_info) == STT_NOTYPE)))
408    {
409      rtems_rtl_obj_sect_t* symsect;
410
411      symsect = rtems_rtl_obj_find_section_by_index (obj, symbol.st_shndx);
412      if (symsect)
413      {
414        if ((ELF_ST_BIND (symbol.st_info) == STB_GLOBAL) ||
415            (ELF_ST_BIND (symbol.st_info) == STB_WEAK))
416        {
417          /*
418           * If there is a globally exported symbol already present and this
419           * symbol is not weak raise an error. If the symbol is weak and
420           * present globally ignore this symbol and use the global one and if
421           * it is not present take this symbol global or weak. We accept the
422           * first weak symbol we find and make it globally exported.
423           */
424          if (rtems_rtl_symbol_global_find (name) &&
425              (ELF_ST_BIND (symbol.st_info) != STB_WEAK))
426          {
427            rtems_rtl_set_error (ENOMEM, "duplicate global symbol: %s", name);
428            return false;
429          }
430          else
431          {
432            ++globals;
433            global_string_space += strlen (name) + 1;
434          }
435        }
436        else if (ELF_ST_BIND (symbol.st_info) == STB_LOCAL)
437        {
438          ++locals;
439          local_string_space += strlen (name) + 1;
440        }
441      }
442    }
443  }
444
445  if (locals)
446  {
447    obj->local_size = locals * sizeof (rtems_rtl_obj_sym_t) + local_string_space;
448    obj->local_table = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_SYMBOL,
449                                            obj->local_size, true);
450    if (!obj->local_table)
451    {
452      obj->local_size = 0;
453      rtems_rtl_set_error (ENOMEM, "no memory for obj local syms");
454      return false;
455    }
456
457    obj->local_syms = locals;
458  }
459
460  if (globals)
461  {
462    obj->global_size = globals * sizeof (rtems_rtl_obj_sym_t) + global_string_space;
463    obj->global_table = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_SYMBOL,
464                                             obj->global_size, true);
465    if (!obj->global_table)
466    {
467      if (locals)
468      {
469        rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, obj->local_table);
470        obj->local_size = 0;
471        obj->local_syms = 0;
472      }
473      obj->global_size = 0;
474      rtems_rtl_set_error (ENOMEM, "no memory for obj global syms");
475      return false;
476    }
477
478    obj->global_syms = globals;
479  }
480
481  lsym = obj->local_table;
482  lstring =
483    (((char*) obj->local_table) + (locals * sizeof (rtems_rtl_obj_sym_t)));
484  gsym = obj->global_table;
485  gstring =
486    (((char*) obj->global_table) + (globals * sizeof (rtems_rtl_obj_sym_t)));
487
488  for (sym = 0; sym < (sect->size / sizeof (Elf_Sym)); ++sym)
489  {
490    Elf_Sym     symbol;
491    off_t       off;
492    const char* name;
493    size_t      len;
494
495    off = obj->ooffset + sect->offset + (sym * sizeof (symbol));
496
497    if (!rtems_rtl_obj_cache_read_byval (symbols, fd, off,
498                                         &symbol, sizeof (symbol)))
499    {
500      if (locals)
501      {
502        rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, obj->local_table);
503        obj->local_table = NULL;
504        obj->local_size = 0;
505        obj->local_syms = 0;
506      }
507      if (globals)
508      {
509        rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, obj->global_table);
510        obj->global_table = NULL;
511        obj->global_syms = 0;
512        obj->global_size = 0;
513      }
514      return false;
515    }
516
517    off = obj->ooffset + strtab->offset + symbol.st_name;
518    len = RTEMS_RTL_ELF_STRING_MAX;
519
520    if (!rtems_rtl_obj_cache_read (strings, fd, off, (void**) &name, &len))
521      return false;
522
523    if ((symbol.st_shndx != 0) &&
524        ((ELF_ST_TYPE (symbol.st_info) == STT_OBJECT) ||
525         (ELF_ST_TYPE (symbol.st_info) == STT_FUNC) ||
526         (ELF_ST_TYPE (symbol.st_info) == STT_NOTYPE)) &&
527         ((ELF_ST_BIND (symbol.st_info) == STB_GLOBAL) ||
528          (ELF_ST_BIND (symbol.st_info) == STB_WEAK) ||
529          (ELF_ST_BIND (symbol.st_info) == STB_LOCAL)))
530      {
531        rtems_rtl_obj_sect_t* symsect;
532        rtems_rtl_obj_sym_t*  osym;
533        char*                 string;
534
535        symsect = rtems_rtl_obj_find_section_by_index (obj, symbol.st_shndx);
536        if (symsect)
537        {
538          if ((ELF_ST_BIND (symbol.st_info) == STB_GLOBAL) ||
539              (ELF_ST_BIND (symbol.st_info) == STB_WEAK))
540          {
541            osym = gsym;
542            string = gstring;
543            gstring += strlen (name) + 1;
544            ++gsym;
545          }
546          else
547          {
548            osym = lsym;
549            string = lstring;
550            lstring += strlen (name) + 1;
551            ++lsym;
552          }
553
554          rtems_chain_set_off_chain (&osym->node);
555          memcpy (string, name, strlen (name) + 1);
556          osym->name = string;
557          osym->value = symbol.st_value + (uint8_t*) symsect->base;
558          osym->data = symbol.st_info;
559
560          if (rtems_rtl_trace (RTEMS_RTL_TRACE_SYMBOL))
561            printf ("rtl: sym:add:%-2d name:%-2d:%-20s bind:%-2d " \
562                    "type:%-2d val:%8p sect:%d size:%d\n",
563                    sym, (int) symbol.st_name, osym->name,
564                    (int) ELF_ST_BIND (symbol.st_info),
565                    (int) ELF_ST_TYPE (symbol.st_info),
566                    osym->value, symbol.st_shndx,
567                    (int) symbol.st_size);
568        }
569      }
570  }
571
572  if (globals)
573    rtems_rtl_symbol_obj_add (obj);
574
575  return true;
576}
577
578static bool
579rtems_rtl_elf_loader (rtems_rtl_obj_t*      obj,
580                      int                   fd,
581                      rtems_rtl_obj_sect_t* sect,
582                      void*                 data)
583{
584  uint8_t* base_offset;
585  size_t   len;
586
587  if (lseek (fd, obj->ooffset + sect->offset, SEEK_SET) < 0)
588  {
589    rtems_rtl_set_error (errno, "section load seek failed");
590    return false;
591  }
592
593  base_offset = sect->base;
594  len = sect->size;
595
596  while (len)
597  {
598    ssize_t r = read (fd, base_offset, len);
599    if (r <= 0)
600    {
601      rtems_rtl_set_error (errno, "section load read failed");
602      return false;
603    }
604    base_offset += r;
605    len -= r;
606  }
607
608  return true;
609}
610
611static bool
612rtems_rtl_elf_parse_sections (rtems_rtl_obj_t* obj, int fd, Elf_Ehdr* ehdr)
613{
614  rtems_rtl_obj_cache_t* sects;
615  rtems_rtl_obj_cache_t* strings;
616  int                    section;
617  off_t                  sectstroff;
618  off_t                  off;
619  Elf_Shdr               shdr;
620
621  rtems_rtl_obj_caches (&sects, &strings, NULL);
622
623  if (!sects || !strings)
624    return false;
625
626  /*
627   * Get the offset to the section string table.
628   */
629  off = obj->ooffset + ehdr->e_shoff + (ehdr->e_shstrndx * ehdr->e_shentsize);
630
631  if (!rtems_rtl_obj_cache_read_byval (sects, fd, off, &shdr, sizeof (shdr)))
632    return false;
633
634  if (shdr.sh_type != SHT_STRTAB)
635  {
636    rtems_rtl_set_error (EINVAL, "bad .sectstr section type");
637    return false;
638  }
639
640  sectstroff = obj->ooffset + shdr.sh_offset;
641
642  for (section = 0; section < ehdr->e_shnum; ++section)
643  {
644    uint32_t flags;
645
646    /*
647     * Make sure section is at least 32bits to avoid 16-bit overflow errors.
648     */
649    off = obj->ooffset + ehdr->e_shoff + (((uint32_t) section) * ehdr->e_shentsize);
650
651    if (rtems_rtl_trace (RTEMS_RTL_TRACE_DETAIL))
652      printf ("rtl: section header: %2d: offset=%d\n", section, (int) off);
653
654    if (!rtems_rtl_obj_cache_read_byval (sects, fd, off, &shdr, sizeof (shdr)))
655      return false;
656
657    flags = 0;
658
659    if (rtems_rtl_trace (RTEMS_RTL_TRACE_DETAIL))
660      printf ("rtl: section: %2d: type=%d flags=%08x link=%d info=%d\n",
661              section, (int) shdr.sh_type, (unsigned int) shdr.sh_flags,
662              (int) shdr.sh_link, (int) shdr.sh_info);
663
664    switch (shdr.sh_type)
665    {
666      case SHT_NULL:
667        /*
668         * Ignore.
669         */
670        break;
671
672      case SHT_PROGBITS:
673        /*
674         * There are 2 program bits sections. One is the program text and the
675         * other is the program data. The program text is flagged
676         * alloc/executable and the program data is flagged alloc/writable.
677         */
678        if ((shdr.sh_flags & SHF_ALLOC) == SHF_ALLOC)
679        {
680          if ((shdr.sh_flags & SHF_EXECINSTR) == SHF_EXECINSTR)
681            flags = RTEMS_RTL_OBJ_SECT_TEXT | RTEMS_RTL_OBJ_SECT_LOAD;
682          else if ((shdr.sh_flags & SHF_WRITE) == SHF_WRITE)
683            flags = RTEMS_RTL_OBJ_SECT_DATA | RTEMS_RTL_OBJ_SECT_LOAD;
684          else
685            flags = RTEMS_RTL_OBJ_SECT_CONST | RTEMS_RTL_OBJ_SECT_LOAD;
686        }
687        break;
688
689      case SHT_NOBITS:
690        /*
691         * There is 1 NOBIT section which is the .bss section. There is nothing
692         * but a definition as the .bss is just a clear region of memory.
693         */
694        if ((shdr.sh_flags & (SHF_ALLOC | SHF_WRITE)) == (SHF_ALLOC | SHF_WRITE))
695          flags = RTEMS_RTL_OBJ_SECT_BSS | RTEMS_RTL_OBJ_SECT_ZERO;
696        break;
697
698      case SHT_RELA:
699        flags = RTEMS_RTL_OBJ_SECT_RELA;
700        break;
701
702      case SHT_REL:
703        /*
704         * The sh_link holds the section index for the symbol table. The sh_info
705         * holds the section index the relocations apply to.
706         */
707        flags = RTEMS_RTL_OBJ_SECT_REL;
708        break;
709
710      case SHT_SYMTAB:
711        flags = RTEMS_RTL_OBJ_SECT_SYM;
712        break;
713
714      case SHT_STRTAB:
715        flags = RTEMS_RTL_OBJ_SECT_STR;
716        break;
717
718      default:
719        /*
720         * See if there are architecture specific flags?
721         */
722        flags = rtems_rtl_elf_section_flags (obj, &shdr);
723        if (flags == 0)
724        {
725          if (rtems_rtl_trace (RTEMS_RTL_TRACE_WARNING))
726            printf ("rtl: unsupported section: %2d: type=%02d flags=%02x\n",
727                    section, (int) shdr.sh_type, (int) shdr.sh_flags);
728        }
729        break;
730    }
731
732    if (flags != 0)
733    {
734      char*  name;
735      size_t len;
736
737      /*
738       * If link ordering this section must appear in the same order in memory
739       * as the linked-to section relative to the sections it loads with.
740       */
741      if ((shdr.sh_flags & SHF_LINK_ORDER) != 0)
742        flags |= RTEMS_RTL_OBJ_SECT_LINK;
743
744      len = RTEMS_RTL_ELF_STRING_MAX;
745      if (!rtems_rtl_obj_cache_read (strings, fd,
746                                     sectstroff + shdr.sh_name,
747                                     (void**) &name, &len))
748        return false;
749
750      if (strcmp (".ctors", name) == 0)
751        flags |= RTEMS_RTL_OBJ_SECT_CTOR;
752      if (strcmp (".dtors", name) == 0)
753        flags |= RTEMS_RTL_OBJ_SECT_DTOR;
754
755      if (rtems_rtl_elf_unwind_parse (obj, name, flags))
756      {
757        flags &= ~(RTEMS_RTL_OBJ_SECT_TEXT | RTEMS_RTL_OBJ_SECT_CONST);
758        flags |= RTEMS_RTL_OBJ_SECT_EH;
759      }
760
761      if (!rtems_rtl_obj_add_section (obj, section, name,
762                                      shdr.sh_size, shdr.sh_offset,
763                                      shdr.sh_addralign, shdr.sh_link,
764                                      shdr.sh_info, flags))
765        return false;
766    }
767  }
768
769  return true;
770}
771
772bool
773rtems_rtl_elf_file_check (rtems_rtl_obj_t* obj, int fd)
774{
775  rtems_rtl_obj_cache_t* header;
776  Elf_Ehdr               ehdr;
777
778  rtems_rtl_obj_caches (&header, NULL, NULL);
779
780  if (!rtems_rtl_obj_cache_read_byval (header, fd, obj->ooffset,
781                                       &ehdr, sizeof (ehdr)))
782    return false;
783
784  /*
785   * Check we have a valid ELF file.
786   */
787  if ((memcmp (ELFMAG, ehdr.e_ident, SELFMAG) != 0)
788      || ehdr.e_ident[EI_CLASS] != ELFCLASS)
789  {
790    return false;
791  }
792
793  if ((ehdr.e_ident[EI_VERSION] != EV_CURRENT)
794      || (ehdr.e_version != EV_CURRENT)
795      || (ehdr.e_ident[EI_DATA] != ELFDEFNNAME (MACHDEP_ENDIANNESS)))
796  {
797    return false;
798  }
799
800  return true;
801}
802
803static bool
804rtems_rtl_elf_load_linkmap (rtems_rtl_obj_t* obj)
805{
806  rtems_chain_control* sections = NULL;
807  rtems_chain_node*    node = NULL;
808  size_t               mask = 0;
809  int                  sec_num = 0;
810  section_detail*      sd;
811  int                  i = 0;
812
813  /*
814   * Caculate the size of sections' name.
815   */
816
817  for (mask = RTEMS_RTL_OBJ_SECT_TEXT;
818       mask <= RTEMS_RTL_OBJ_SECT_BSS;
819       mask <<= 1)
820  {
821    sections = &obj->sections;
822    node = rtems_chain_first (sections);
823    while (!rtems_chain_is_tail (sections, node))
824    {
825      rtems_rtl_obj_sect_t* sect = (rtems_rtl_obj_sect_t*) node;
826      if ((sect->size != 0) && ((sect->flags & mask) != 0))
827      {
828        ++sec_num;
829      }
830      node = rtems_chain_next (node);
831    }
832  }
833
834  obj->obj_num = 1;
835  obj->linkmap = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT,
836                                      sizeof(struct link_map) +
837                                      sec_num * sizeof (section_detail), true);
838  if (!obj->linkmap)
839  {
840    rtems_rtl_set_error (ENOMEM, "no memory for obj linkmap");
841    return false;
842  }
843
844  obj->linkmap->name = obj->oname;
845  obj->linkmap->sec_num = sec_num;
846  obj->linkmap->sec_detail = (section_detail*) (obj->linkmap + 1);
847  obj->linkmap->rpathlen = 0;
848  obj->linkmap->rpath = NULL;
849  obj->linkmap->l_next = NULL;
850  obj->linkmap->l_prev = NULL;
851  obj->linkmap->sec_addr[rap_text] = obj->text_base;
852  obj->linkmap->sec_addr[rap_const] = obj->const_base;
853  obj->linkmap->sec_addr[rap_data] = obj->data_base;
854  obj->linkmap->sec_addr[rap_bss] = obj->bss_base;
855
856  sd = obj->linkmap->sec_detail;
857  sections = &obj->sections;
858  node = rtems_chain_first (sections);
859
860  for (mask = RTEMS_RTL_OBJ_SECT_TEXT;
861       mask <= RTEMS_RTL_OBJ_SECT_BSS;
862       mask <<= 1)
863  {
864    sections = &obj->sections;
865    node = rtems_chain_first (sections);
866    while (!rtems_chain_is_tail (sections, node))
867    {
868      rtems_rtl_obj_sect_t* sect = (rtems_rtl_obj_sect_t*) node;
869
870      if ((sect->size != 0) && ((sect->flags & mask) != 0))
871      {
872        sd[i].name = sect->name;
873        sd[i].size = sect->size;
874        if (mask == RTEMS_RTL_OBJ_SECT_TEXT)
875        {
876          sd[i].rap_id = rap_text;
877          sd[i].offset = sect->base - obj->text_base;
878        }
879        if (mask == RTEMS_RTL_OBJ_SECT_CONST)
880        {
881          sd[i].rap_id = rap_const;
882          sd[i].offset = sect->base - obj->const_base;
883        }
884        if (mask == RTEMS_RTL_OBJ_SECT_DATA)
885        {
886          sd[i].rap_id = rap_data;
887          sd[i].offset = sect->base - obj->data_base;
888        }
889        if (mask == RTEMS_RTL_OBJ_SECT_BSS)
890        {
891          sd[i].rap_id = rap_bss;
892          sd[i].offset = sect->base - obj->bss_base;
893        }
894
895        ++i;
896      }
897      node = rtems_chain_next (node);
898    }
899  }
900
901  return true;
902}
903
904bool
905rtems_rtl_elf_file_load (rtems_rtl_obj_t* obj, int fd)
906{
907  rtems_rtl_obj_cache_t* header;
908  Elf_Ehdr               ehdr;
909
910  rtems_rtl_obj_caches (&header, NULL, NULL);
911
912  if (!rtems_rtl_obj_cache_read_byval (header, fd, obj->ooffset,
913                                       &ehdr, sizeof (ehdr)))
914    return false;
915
916  /*
917   * Check we have a valid ELF file.
918   */
919  if ((memcmp (ELFMAG, ehdr.e_ident, SELFMAG) != 0)
920      || ehdr.e_ident[EI_CLASS] != ELFCLASS)
921  {
922    rtems_rtl_set_error (EINVAL, "invalid ELF file format");
923    return false;
924  }
925
926  if ((ehdr.e_ident[EI_VERSION] != EV_CURRENT)
927      || (ehdr.e_version != EV_CURRENT)
928      || (ehdr.e_ident[EI_DATA] != ELFDEFNNAME (MACHDEP_ENDIANNESS)))
929  {
930    rtems_rtl_set_error (EINVAL, "unsupported ELF file version");
931    return false;
932  }
933
934  if (!rtems_rtl_elf_machine_check (&ehdr))
935  {
936    rtems_rtl_set_error (EINVAL, "unsupported machine type");
937    return false;
938  }
939
940  if (ehdr.e_type == ET_DYN)
941  {
942    rtems_rtl_set_error (EINVAL, "unsupported ELF file type");
943    return false;
944  }
945
946  if (ehdr.e_phentsize != 0)
947  {
948    rtems_rtl_set_error (EINVAL, "ELF file contains program headers");
949    return false;
950  }
951
952  if (ehdr.e_shentsize != sizeof (Elf_Shdr))
953  {
954    rtems_rtl_set_error (EINVAL, "invalid ELF section header size");
955    return false;
956  }
957
958  /*
959   * Parse the section information first so we have the memory map of the object
960   * file and the memory allocated. Any further allocations we make to complete
961   * the load will not fragment the memory.
962   */
963  if (!rtems_rtl_elf_parse_sections (obj, fd, &ehdr))
964    return false;
965
966  obj->entry = (void*)(uintptr_t) ehdr.e_entry;
967
968  if (!rtems_rtl_obj_load_sections (obj, fd, rtems_rtl_elf_loader, &ehdr))
969    return false;
970
971  if (!rtems_rtl_obj_load_symbols (obj, fd, rtems_rtl_elf_symbols, &ehdr))
972    return false;
973
974  if (!rtems_rtl_obj_relocate (obj, fd, rtems_rtl_elf_relocator, &ehdr))
975    return false;
976
977  rtems_rtl_obj_synchronize_cache (obj);
978
979  rtems_rtl_symbol_obj_erase_local (obj);
980
981  if (!rtems_rtl_elf_load_linkmap (obj))
982  {
983    return false;
984  }
985
986  if (!rtems_rtl_elf_unwind_register (obj))
987  {
988    return false;
989  }
990
991  return true;
992}
993
994bool
995rtems_rtl_elf_file_unload (rtems_rtl_obj_t* obj)
996{
997  rtems_rtl_elf_unwind_deregister (obj);
998  return true;
999}
1000
1001rtems_rtl_loader_format_t*
1002rtems_rtl_elf_file_sig (void)
1003{
1004  return &elf_sig;
1005}
Note: See TracBrowser for help on using the repository browser.