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

4.115
Last change on this file since ae5fe7e6 was ae5fe7e6, checked in by Chris Johns <chrisj@…>, on 10/27/14 at 01:09:41

cpukit: Add libdl with the Runtime Loader (RTL) code.

This is a merge of the RTL project.

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