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

4.115
Last change on this file since 580466c was 580466c, checked in by Chris Johns <chrisj@…>, on Nov 20, 2014 at 2:52:12 AM

libdl: Update comment with details about the error fix.

See refs #2192.

  • Property mode set to 100644
File size: 26.1 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    /*
643     * Make sure section is at least 32bits to avoid 16-bit overflow errors.
644     */
645    off = obj->ooffset + ehdr->e_shoff + (((uint32_t) section) * ehdr->e_shentsize);
646
647    if (!rtems_rtl_obj_cache_read_byval (sects, fd, off, &shdr, sizeof (shdr)))
648      return false;
649
650    flags = 0;
651
652    switch (shdr.sh_type)
653    {
654      case SHT_NULL:
655        /*
656         * Ignore.
657         */
658        break;
659
660      case SHT_PROGBITS:
661        /*
662         * There are 2 program bits sections. One is the program text and the
663         * other is the program data. The program text is flagged
664         * alloc/executable and the program data is flagged alloc/writable.
665         */
666        if ((shdr.sh_flags & SHF_ALLOC) == SHF_ALLOC)
667        {
668          if ((shdr.sh_flags & SHF_EXECINSTR) == SHF_EXECINSTR)
669            flags = RTEMS_RTL_OBJ_SECT_TEXT | RTEMS_RTL_OBJ_SECT_LOAD;
670          else if ((shdr.sh_flags & SHF_WRITE) == SHF_WRITE)
671            flags = RTEMS_RTL_OBJ_SECT_DATA | RTEMS_RTL_OBJ_SECT_LOAD;
672          else
673            flags = RTEMS_RTL_OBJ_SECT_CONST | RTEMS_RTL_OBJ_SECT_LOAD;
674        }
675        break;
676
677      case SHT_NOBITS:
678        /*
679         * There is 1 NOBIT section which is the .bss section. There is nothing
680         * but a definition as the .bss is just a clear region of memory.
681         */
682        if ((shdr.sh_flags & (SHF_ALLOC | SHF_WRITE)) == (SHF_ALLOC | SHF_WRITE))
683          flags = RTEMS_RTL_OBJ_SECT_BSS | RTEMS_RTL_OBJ_SECT_ZERO;
684        break;
685
686      case SHT_RELA:
687        flags = RTEMS_RTL_OBJ_SECT_RELA;
688        break;
689
690      case SHT_REL:
691        /*
692         * The sh_link holds the section index for the symbol table. The sh_info
693         * holds the section index the relocations apply to.
694         */
695        flags = RTEMS_RTL_OBJ_SECT_REL;
696        break;
697
698      case SHT_SYMTAB:
699        flags = RTEMS_RTL_OBJ_SECT_SYM;
700        break;
701
702      case SHT_STRTAB:
703        flags = RTEMS_RTL_OBJ_SECT_STR;
704        break;
705
706      default:
707        if (rtems_rtl_trace (RTEMS_RTL_TRACE_WARNING))
708          printf ("rtl: unsupported section: %2d: type=%02d flags=%02x\n",
709                  section, (int) shdr.sh_type, (int) shdr.sh_flags);
710        break;
711    }
712
713    if (flags != 0)
714    {
715      char*  name;
716      size_t len;
717
718      len = RTEMS_RTL_ELF_STRING_MAX;
719      if (!rtems_rtl_obj_cache_read (strings, fd,
720                                     sectstroff + shdr.sh_name,
721                                     (void**) &name, &len))
722        return false;
723
724      if (strcmp (".ctors", name) == 0)
725        flags |= RTEMS_RTL_OBJ_SECT_CTOR;
726      if (strcmp (".dtors", name) == 0)
727        flags |= RTEMS_RTL_OBJ_SECT_DTOR;
728
729      if (!rtems_rtl_obj_add_section (obj, section, name,
730                                      shdr.sh_size, shdr.sh_offset,
731                                      shdr.sh_addralign, shdr.sh_link,
732                                      shdr.sh_info, flags))
733        return false;
734    }
735  }
736
737  return true;
738}
739
740bool
741rtems_rtl_elf_file_check (rtems_rtl_obj_t* obj, int fd)
742{
743  rtems_rtl_obj_cache_t* header;
744  Elf_Ehdr               ehdr;
745
746  rtems_rtl_obj_caches (&header, NULL, NULL);
747
748  if (!rtems_rtl_obj_cache_read_byval (header, fd, obj->ooffset,
749                                       &ehdr, sizeof (ehdr)))
750    return false;
751
752  /*
753   * Check we have a valid ELF file.
754   */
755  if ((memcmp (ELFMAG, ehdr.e_ident, SELFMAG) != 0)
756      || ehdr.e_ident[EI_CLASS] != ELFCLASS)
757  {
758    return false;
759  }
760
761  if ((ehdr.e_ident[EI_VERSION] != EV_CURRENT)
762      || (ehdr.e_version != EV_CURRENT)
763      || (ehdr.e_ident[EI_DATA] != ELFDEFNNAME (MACHDEP_ENDIANNESS)))
764  {
765    return false;
766  }
767
768  return true;
769}
770
771bool rtems_rtl_elf_load_details (rtems_rtl_obj_t* obj)
772{
773  rtems_chain_control* sections = NULL;
774  rtems_chain_node*    node = NULL;
775  size_t               mask = 0;
776  struct link_map*     l = NULL;
777  int                  sec_num = 0;
778  int                  i = 0;
779
780  /* caculate the size of sections' name. */
781
782  for (mask = RTEMS_RTL_OBJ_SECT_TEXT;
783       mask <= RTEMS_RTL_OBJ_SECT_BSS;
784       mask <<= 1)
785  {
786    sections = &obj->sections;
787    node = rtems_chain_first (sections);
788    while (!rtems_chain_is_tail (sections, node))
789    {
790      rtems_rtl_obj_sect_t* sect = (rtems_rtl_obj_sect_t*) node;
791
792      if ((sect->size != 0) && ((sect->flags & mask) != 0))
793      {
794        ++sec_num;
795      }
796      node = rtems_chain_next (node);
797    }
798  }
799
800  obj->obj_num = 1;
801  obj->detail = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT,
802                                     sizeof(struct link_map) +
803                                     sec_num * sizeof (section_detail), true);
804  if (!obj->detail)
805  {
806    rtems_rtl_set_error (ENOMEM, "no memory for obj global syms");
807    return false;
808  }
809
810  l = (struct link_map*) obj->detail;
811  l->name = obj->oname;
812  l->sec_num = sec_num;
813  l->sec_detail = (section_detail*) (l + 1);
814  l->rpathlen = 0;
815  l->rpath = NULL;
816  l->l_next = NULL;
817  l->l_prev = NULL;
818  l->sec_addr[rap_text] = obj->text_base;
819  l->sec_addr[rap_const] = obj->const_base;
820  l->sec_addr[rap_data] = obj->data_base;
821  l->sec_addr[rap_bss] = obj->bss_base;
822
823
824  section_detail* sd = l->sec_detail;
825  sections = &obj->sections;
826  node = rtems_chain_first (sections);
827  for (mask = RTEMS_RTL_OBJ_SECT_TEXT;
828       mask <= RTEMS_RTL_OBJ_SECT_BSS;
829       mask <<= 1)
830  {
831    sections = &obj->sections;
832    node = rtems_chain_first (sections);
833    while (!rtems_chain_is_tail (sections, node))
834    {
835      rtems_rtl_obj_sect_t* sect = (rtems_rtl_obj_sect_t*) node;
836
837      if ((sect->size != 0) && ((sect->flags & mask) != 0))
838      {
839        sd[i].name = sect->name;
840        sd[i].size = sect->size;
841        if (mask == RTEMS_RTL_OBJ_SECT_TEXT)
842        {
843          sd[i].rap_id = rap_text;
844          sd[i].offset = sect->base - obj->text_base;
845        }
846        if (mask == RTEMS_RTL_OBJ_SECT_CONST)
847        {
848          sd[i].rap_id = rap_const;
849          sd[i].offset = sect->base - obj->const_base;
850        }
851        if (mask == RTEMS_RTL_OBJ_SECT_DATA)
852        {
853          sd[i].rap_id = rap_data;
854          sd[i].offset = sect->base - obj->data_base;
855        }
856        if (mask == RTEMS_RTL_OBJ_SECT_BSS)
857        {
858          sd[i].rap_id = rap_bss;
859          sd[i].offset = sect->base - obj->bss_base;
860        }
861
862        ++i;
863      }
864      node = rtems_chain_next (node);
865    }
866  }
867
868  return true;
869}
870
871bool
872rtems_rtl_elf_file_load (rtems_rtl_obj_t* obj, int fd)
873{
874  rtems_rtl_obj_cache_t* header;
875  Elf_Ehdr               ehdr;
876
877  rtems_rtl_obj_caches (&header, NULL, NULL);
878
879  if (!rtems_rtl_obj_cache_read_byval (header, fd, obj->ooffset,
880                                       &ehdr, sizeof (ehdr)))
881    return false;
882
883  /*
884   * Check we have a valid ELF file.
885   */
886  if ((memcmp (ELFMAG, ehdr.e_ident, SELFMAG) != 0)
887      || ehdr.e_ident[EI_CLASS] != ELFCLASS)
888  {
889    rtems_rtl_set_error (EINVAL, "invalid ELF file format");
890    return false;
891  }
892
893  if ((ehdr.e_ident[EI_VERSION] != EV_CURRENT)
894      || (ehdr.e_version != EV_CURRENT)
895      || (ehdr.e_ident[EI_DATA] != ELFDEFNNAME (MACHDEP_ENDIANNESS)))
896  {
897    rtems_rtl_set_error (EINVAL, "unsupported ELF file version");
898    return false;
899  }
900
901  if (!rtems_rtl_elf_machine_check (&ehdr))
902  {
903    rtems_rtl_set_error (EINVAL, "unsupported machine type");
904    return false;
905  }
906
907  if (ehdr.e_type == ET_DYN)
908  {
909    rtems_rtl_set_error (EINVAL, "unsupported ELF file type");
910    return false;
911  }
912
913  if (ehdr.e_phentsize != 0)
914  {
915    rtems_rtl_set_error (EINVAL, "ELF file contains program headers");
916    return false;
917  }
918
919  if (ehdr.e_shentsize != sizeof (Elf_Shdr))
920  {
921    rtems_rtl_set_error (EINVAL, "invalid ELF section header size");
922    return false;
923  }
924
925  /*
926   * Parse the section information first so we have the memory map of the object
927   * file and the memory allocated. Any further allocations we make to complete
928   * the load will not fragment the memory.
929   */
930  if (!rtems_rtl_elf_parse_sections (obj, fd, &ehdr))
931    return false;
932
933  obj->entry = (void*)(uintptr_t) ehdr.e_entry;
934
935  if (!rtems_rtl_obj_load_sections (obj, fd, rtems_rtl_elf_loader, &ehdr))
936    return false;
937
938  if (!rtems_rtl_obj_load_symbols (obj, fd, rtems_rtl_elf_symbols, &ehdr))
939    return false;
940
941  if (!rtems_rtl_obj_relocate (obj, fd, rtems_rtl_elf_relocator, &ehdr))
942    return false;
943
944  rtems_rtl_symbol_obj_erase_local (obj);
945
946  if (!rtems_rtl_elf_load_details (obj))
947  {
948    return false;
949  }
950
951  return true;
952}
953
954rtems_rtl_loader_format_t*
955rtems_rtl_elf_file_sig (void)
956{
957  return &elf_sig;
958}
Note: See TracBrowser for help on using the repository browser.