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

Last change on this file since 89c59be was 89c59be, checked in by Chris Johns <chrisj@…>, on Dec 17, 2018 at 5:36:48 AM

libdl: Add symbol searching and loading from archives.

  • Load archive symbol tables to support searching of archives for symbols.
  • Search archive symbols and load the object file that contains the symbol.
  • Search the global and archives until all remaining unresolved symbols are not found. Group the loaded object files in the pending queue.
  • Run the object file and loaded dependents as a group before adding to the main object list.
  • Remove orphaned object files after references are removed.

Updates #3686

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