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

4.11
Last change on this file since fc523ac8 was fc523ac8, checked in by Chris Johns <chrisj@…>, on Nov 19, 2014 at 11:18:16 PM

libdl: Fix possible 16-bit overflow (Coverity 1255339) refs #2192.

On a 16-bit target the section value could result in a sign-extension
overflow.

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