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

5
Last change on this file since 74883be5 was 74883be5, checked in by Chris Johns <chrisj@…>, on 05/13/19 at 00:46:45

libdl: Fix loading symbol that reference unknown sections.

  • Make the symbol parsing and loading stage match.
  • Check for possible overflow of the tables when loading.

Closes #3746

  • Property mode set to 100644
File size: 52.9 KB
Line 
1/*
2 *  COPYRIGHT (c) 2012-2019 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 <inttypes.h>
25#include <stdlib.h>
26#include <string.h>
27#include <stdio.h>
28#include <unistd.h>
29
30#include <rtems/rtl/rtl.h>
31#include "rtl-elf.h"
32#include "rtl-error.h"
33#include <rtems/rtl/rtl-trace.h>
34#include "rtl-trampoline.h"
35#include "rtl-unwind.h"
36#include <rtems/rtl/rtl-unresolved.h>
37
38/**
39 * The offsets in the reloc words.
40 */
41#define REL_R_OFFSET (0)
42#define REL_R_INFO   (1)
43#define REL_R_ADDEND (2)
44
45/**
46 * The ELF format signature.
47 */
48static rtems_rtl_loader_format elf_sig =
49{
50  .label = "ELF",
51  .flags = RTEMS_RTL_FMT_ELF
52};
53
54static const char*
55rtems_rtl_elf_sym_type_label (Elf_Byte st_info)
56{
57  const char* label;
58  switch (ELF_ST_TYPE (st_info))
59  {
60    case STT_NOTYPE:
61      label = "STT_NOTYPE";
62      break;
63    case STT_OBJECT:
64      label = "STT_OBJECT";
65      break;
66    case STT_FUNC:
67      label = "STT_FUNC";
68      break;
69    case STT_SECTION:
70      label = "STT_SECTION";
71      break;
72    case STT_FILE:
73      label = "STT_FILE";
74      break;
75    case STT_COMMON:
76      label = "STT_COMMON";
77      break;
78    case STT_TLS:
79      label = "STT_TLS";
80      break;
81    default:
82      label = "unknown";
83      break;
84  }
85  return label;
86}
87
88static const char*
89rtems_rtl_elf_sym_bind_label (Elf_Byte st_info)
90{
91  const char* label;
92  switch (ELF_ST_BIND (st_info))
93  {
94    case STB_LOCAL:
95      label = "STB_LOCAL";
96      break;
97    case STB_GLOBAL:
98      label = "STB_GLOBAL";
99      break;
100    case STB_WEAK:
101      label = "STB_WEAK";
102      break;
103    default:
104      label = "unknown";
105      break;
106  }
107  return label;
108}
109
110static bool
111rtems_rtl_elf_machine_check (Elf_Ehdr* ehdr)
112{
113  /*
114   * This code is determined by the NetBSD machine headers.
115   */
116  switch (ehdr->e_machine)
117  {
118    ELFDEFNNAME (MACHDEP_ID_CASES)
119    default:
120      return false;
121  }
122  return true;
123}
124
125static const char*
126rtems_rtl_elf_separated_section (const char* name)
127{
128  struct {
129    const char* label;
130    size_t      len;
131  } prefix[] = {
132    #define SEPARATED_PREFIX(_p) { _p, sizeof (_p) - 1 }
133    SEPARATED_PREFIX (".text."),
134    SEPARATED_PREFIX (".rel.text."),
135    SEPARATED_PREFIX (".data."),
136    SEPARATED_PREFIX (".rel.data."),
137    SEPARATED_PREFIX (".rodata."),
138    SEPARATED_PREFIX (".rel.rodata.")
139  };
140  const size_t prefixes = sizeof (prefix) / sizeof (prefix[0]);
141  size_t       p;
142  for (p = 0; p < prefixes; ++p)
143  {
144    if (strncmp (name, prefix[p].label, prefix[p].len) == 0)
145      return name + prefix[p].len;
146  }
147  return NULL;
148}
149
150static bool
151rtems_rtl_elf_find_symbol (rtems_rtl_obj*      obj,
152                           const Elf_Sym*      sym,
153                           const char*         symname,
154                           rtems_rtl_obj_sym** symbol,
155                           Elf_Word*           value)
156{
157  rtems_rtl_obj_sect* sect;
158
159  /*
160   * If the symbol type is STT_NOTYPE the symbol references a global
161   * symbol. The gobal symbol table is searched to find it and that value
162   * returned. If the symbol is local to the object module the section for the
163   * symbol is located and it's base added to the symbol's value giving an
164   * absolute location.
165   */
166  if (ELF_ST_TYPE(sym->st_info) == STT_NOTYPE || sym->st_shndx == SHN_COMMON)
167  {
168    /*
169     * Search the object file then the global table for the symbol.
170     */
171    *symbol = rtems_rtl_symbol_obj_find (obj, symname);
172    if (!*symbol)
173      return false;
174
175    *value = (Elf_Addr) (*symbol)->value;
176    return true;
177  }
178
179  *symbol = NULL;
180
181  sect = rtems_rtl_obj_find_section_by_index (obj, sym->st_shndx);
182  if (!sect)
183    return false;
184
185  *value = sym->st_value + (Elf_Addr) sect->base;
186
187  return true;
188}
189
190/**
191 * Relocation worker routine.
192 */
193typedef bool (*rtems_rtl_elf_reloc_handler)(rtems_rtl_obj*      obj,
194                                            bool                is_rela,
195                                            void*               relbuf,
196                                            rtems_rtl_obj_sect* targetsect,
197                                            rtems_rtl_obj_sym*  symbol,
198                                            Elf_Sym*            sym,
199                                            const char*         symname,
200                                            Elf_Word            symvalue,
201                                            bool                resolved,
202                                            void*               data);
203
204/**
205 * Relocation parser data.
206 */
207typedef struct
208{
209  size_t dependents; /**< The number of dependent object files. */
210  size_t unresolved; /**< The number of unresolved symbols. */
211} rtems_rtl_elf_reloc_data;
212
213static bool
214rtems_rtl_elf_reloc_parser (rtems_rtl_obj*      obj,
215                            bool                is_rela,
216                            void*               relbuf,
217                            rtems_rtl_obj_sect* targetsect,
218                            rtems_rtl_obj_sym*  symbol,
219                            Elf_Sym*            sym,
220                            const char*         symname,
221                            Elf_Word            symvalue,
222                            bool                resolved,
223                            void*               data)
224{
225  rtems_rtl_elf_reloc_data* rd = (rtems_rtl_elf_reloc_data*) data;
226  rtems_rtl_word            rel_words[3];
227  rtems_rtl_elf_rel_status  rs;
228
229  /*
230   * Check the reloc record to see if a trampoline is needed.
231   */
232  if (is_rela)
233  {
234    const Elf_Rela* rela = (const Elf_Rela*) relbuf;
235    if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
236      printf ("rtl: rela tramp: sym: %c:%s(%d)=%08jx type:%d off:%08jx addend:%d\n",
237              ELF_ST_BIND (sym->st_info) == STB_GLOBAL ||
238              ELF_ST_BIND (sym->st_info) == STB_WEAK ? 'G' : 'L',
239              symname, (int) ELF_R_SYM (rela->r_info),
240              (uintmax_t) symvalue, (int) ELF_R_TYPE (rela->r_info),
241              (uintmax_t) rela->r_offset, (int) rela->r_addend);
242    rs = rtems_rtl_elf_relocate_rela_tramp (obj, rela, targetsect,
243                                            symname, sym->st_info, symvalue);
244    rel_words[REL_R_OFFSET] = rela->r_offset;
245    rel_words[REL_R_INFO] = rela->r_info;
246    rel_words[REL_R_ADDEND] = rela->r_addend;
247  }
248  else
249  {
250    const Elf_Rel* rel = (const Elf_Rel*) relbuf;
251    if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
252      printf ("rtl: rel tramp: sym: %c:%s(%d)=%08jx type:%d off:%08jx\n",
253              ELF_ST_BIND (sym->st_info) == STB_GLOBAL ||
254              ELF_ST_BIND (sym->st_info) == STB_WEAK ? 'G' : 'L',
255              symname, (int) ELF_R_SYM (rel->r_info),
256              (uintmax_t) symvalue, (int) ELF_R_TYPE (rel->r_info),
257              (uintmax_t) rel->r_offset);
258    rs = rtems_rtl_elf_relocate_rel_tramp (obj, rel, targetsect,
259                                           symname, sym->st_info, symvalue);
260    rel_words[REL_R_OFFSET] = rel->r_offset;
261    rel_words[REL_R_INFO] = rel->r_info;
262    rel_words[REL_R_ADDEND] = 0;
263  }
264
265  if (rs == rtems_rtl_elf_rel_failure)
266    return false;
267
268  if (rs == rtems_rtl_elf_rel_tramp_cache || rs == rtems_rtl_elf_rel_tramp_add)
269  {
270    uint32_t flags = (is_rela ? 1 : 0) | (resolved ? 0 : 1 << 1) | (sym->st_info << 8);
271    if (!rtems_rtl_trampoline_add (obj, flags,
272                                   targetsect->section, symvalue, rel_words))
273      return false;
274  }
275
276  /*
277   * Handle any dependencies if there is a valid symbol.
278   */
279  if (symname != NULL)
280  {
281    /*
282     * Find the symbol's object file. It cannot be NULL so ignore that result
283     * if returned, it means something is corrupted. We are in an iterator.
284     */
285    rtems_rtl_obj*  sobj = rtems_rtl_find_obj_with_symbol (symbol);
286    if (sobj != NULL)
287    {
288      /*
289       * A dependency is not the base kernel image or itself. Tag the object as
290       * having been visited so we count it only once.
291       */
292      if (sobj != rtems_rtl_baseimage () && obj != sobj &&
293          (sobj->flags & RTEMS_RTL_OBJ_RELOC_TAG) == 0)
294      {
295        sobj->flags |= RTEMS_RTL_OBJ_RELOC_TAG;
296        ++rd->dependents;
297      }
298    }
299  }
300
301  return true;
302}
303
304static bool
305rtems_rtl_elf_reloc_relocator (rtems_rtl_obj*      obj,
306                               bool                is_rela,
307                               void*               relbuf,
308                               rtems_rtl_obj_sect* targetsect,
309                               rtems_rtl_obj_sym*  symbol,
310                               Elf_Sym*            sym,
311                               const char*         symname,
312                               Elf_Word            symvalue,
313                               bool                resolved,
314                               void*               data)
315{
316  const Elf_Rela* rela = (const Elf_Rela*) relbuf;
317  const Elf_Rel*  rel = (const Elf_Rel*) relbuf;
318
319  if (!resolved)
320  {
321    uint16_t       flags = 0;
322    rtems_rtl_word rel_words[3];
323
324    if (is_rela)
325    {
326      flags = 1;
327      rel_words[REL_R_OFFSET] = rela->r_offset;
328      rel_words[REL_R_INFO] = rela->r_info;
329      rel_words[REL_R_ADDEND] = rela->r_addend;
330    }
331    else
332    {
333      rel_words[REL_R_OFFSET] = rel->r_offset;
334      rel_words[REL_R_INFO] = rel->r_info;
335      rel_words[REL_R_ADDEND] = 0;
336    }
337
338    if (!rtems_rtl_unresolved_add (obj,
339                                   flags,
340                                   symname,
341                                   targetsect->section,
342                                   rel_words))
343      return false;
344
345    ++obj->unresolved;
346  }
347  else
348  {
349    rtems_rtl_obj*           sobj;
350    rtems_rtl_elf_rel_status rs;
351
352    if (is_rela)
353    {
354      if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
355        printf ("rtl: rela: sym:%s(%d)=%08jx type:%d off:%08jx addend:%d\n",
356                symname, (int) ELF_R_SYM (rela->r_info),
357                (uintmax_t) symvalue, (int) ELF_R_TYPE (rela->r_info),
358                (uintmax_t) rela->r_offset, (int) rela->r_addend);
359      rs = rtems_rtl_elf_relocate_rela (obj, rela, targetsect,
360                                        symname, sym->st_info, symvalue);
361      if (rs != rtems_rtl_elf_rel_no_error)
362        return false;
363    }
364    else
365    {
366      if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
367        printf ("rtl: rel: sym:%s(%d)=%08jx type:%d off:%08jx\n",
368                symname, (int) ELF_R_SYM (rel->r_info),
369                (uintmax_t) symvalue, (int) ELF_R_TYPE (rel->r_info),
370                (uintmax_t) rel->r_offset);
371      rs = rtems_rtl_elf_relocate_rel (obj, rel, targetsect,
372                                       symname, sym->st_info, symvalue);
373      if (rs != rtems_rtl_elf_rel_no_error)
374        return false;
375    }
376
377    sobj = rtems_rtl_find_obj_with_symbol (symbol);
378
379    if (rtems_rtl_trace (RTEMS_RTL_TRACE_DEPENDENCY))
380      printf ("rtl: depend: %s -> %s:%s\n",
381              obj->oname,
382              sobj == NULL ? "not-found" : sobj->oname,
383              symname);
384
385    if (sobj != NULL)
386    {
387      if (rtems_rtl_obj_add_dependent (obj, sobj))
388        rtems_rtl_obj_inc_reference (sobj);
389    }
390  }
391
392  return true;
393}
394
395static bool
396rtems_rtl_elf_relocate_worker (rtems_rtl_obj*              obj,
397                               int                         fd,
398                               rtems_rtl_obj_sect*         sect,
399                               rtems_rtl_elf_reloc_handler handler,
400                               void*                       data)
401{
402  rtems_rtl_obj_cache* symbols;
403  rtems_rtl_obj_cache* strings;
404  rtems_rtl_obj_cache* relocs;
405  rtems_rtl_obj_sect*  targetsect;
406  rtems_rtl_obj_sect*  symsect;
407  rtems_rtl_obj_sect*  strtab;
408  bool                 is_rela;
409  size_t               reloc_size;
410  int                  reloc;
411
412  /*
413   * First check if the section the relocations are for exists. If it does not
414   * exist ignore these relocations. They are most probably debug sections.
415   */
416  targetsect = rtems_rtl_obj_find_section_by_index (obj, sect->info);
417  if (!targetsect)
418    return true;
419
420  /*
421   * The section muct has been loaded. It could be a separate section in an
422   * archive and not loaded.
423   */
424  if ((targetsect->flags & RTEMS_RTL_OBJ_SECT_LOAD) == 0)
425    return true;
426
427
428  rtems_rtl_obj_caches (&symbols, &strings, &relocs);
429
430  if (!symbols || !strings || !relocs)
431    return false;
432
433  symsect = rtems_rtl_obj_find_section (obj, ".symtab");
434  if (!symsect)
435  {
436    rtems_rtl_set_error (EINVAL, "no .symtab section");
437    return false;
438  }
439
440  strtab = rtems_rtl_obj_find_section (obj, ".strtab");
441  if (!strtab)
442  {
443    rtems_rtl_set_error (EINVAL, "no .strtab section");
444    return false;
445  }
446
447  if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
448    printf ("rtl: relocation: %s, syms:%s\n", sect->name, symsect->name);
449
450  /*
451   * Handle the different relocation record types.
452   */
453  is_rela = ((sect->flags & RTEMS_RTL_OBJ_SECT_RELA) ==
454             RTEMS_RTL_OBJ_SECT_RELA) ? true : false;
455  reloc_size = is_rela ? sizeof (Elf_Rela) : sizeof (Elf_Rel);
456
457  for (reloc = 0; reloc < (sect->size / reloc_size); ++reloc)
458  {
459    uint8_t            relbuf[reloc_size];
460    const Elf_Rela*    rela = (const Elf_Rela*) relbuf;
461    const Elf_Rel*     rel = (const Elf_Rel*) relbuf;
462    rtems_rtl_obj_sym* symbol = NULL;
463    Elf_Sym            sym;
464    const char*        symname = NULL;
465    off_t              off;
466    Elf_Word           rel_type;
467    Elf_Word           symvalue = 0;
468    bool               resolved;
469
470    off = obj->ooffset + sect->offset + (reloc * reloc_size);
471
472    if (!rtems_rtl_obj_cache_read_byval (relocs, fd, off,
473                                         &relbuf[0], reloc_size))
474      return false;
475
476    /*
477     * Read the symbol details.
478     */
479    if (is_rela)
480      off = (obj->ooffset + symsect->offset +
481             (ELF_R_SYM (rela->r_info) * sizeof (sym)));
482    else
483      off = (obj->ooffset + symsect->offset +
484             (ELF_R_SYM (rel->r_info) * sizeof (sym)));
485
486    if (!rtems_rtl_obj_cache_read_byval (symbols, fd, off,
487                                         &sym, sizeof (sym)))
488      return false;
489
490    /*
491     * Only need the name of the symbol if global or a common symbol.
492     */
493    if (ELF_ST_TYPE (sym.st_info) == STT_OBJECT ||
494        ELF_ST_TYPE (sym.st_info) == STT_COMMON ||
495        ELF_ST_TYPE (sym.st_info) == STT_FUNC ||
496        ELF_ST_TYPE (sym.st_info) == STT_NOTYPE ||
497        ELF_ST_TYPE (sym.st_info) == STT_TLS ||
498        sym.st_shndx == SHN_COMMON)
499    {
500      size_t len;
501      off = obj->ooffset + strtab->offset + sym.st_name;
502      len = RTEMS_RTL_ELF_STRING_MAX;
503
504      if (!rtems_rtl_obj_cache_read (strings, fd, off,
505                                     (void**) &symname, &len))
506        return false;
507    }
508
509    /*
510     * See if the record references an external symbol. If it does find the
511     * symbol value. If the symbol cannot be found flag the object file as
512     * having unresolved externals and store the external. The load of an
513     * object after this one may provide the unresolved externals.
514     */
515    if (is_rela)
516      rel_type = ELF_R_TYPE(rela->r_info);
517    else
518      rel_type = ELF_R_TYPE(rel->r_info);
519
520    resolved = true;
521
522    if (rtems_rtl_elf_rel_resolve_sym (rel_type))
523      resolved = rtems_rtl_elf_find_symbol (obj,
524                                            &sym, symname,
525                                            &symbol, &symvalue);
526
527    if (!handler (obj,
528                  is_rela, relbuf, targetsect,
529                  symbol, &sym, symname, symvalue, resolved,
530                  data))
531      return false;
532  }
533
534  /*
535   * Set the unresolved externals status if there are unresolved externals.
536   */
537  if (obj->unresolved)
538    obj->flags |= RTEMS_RTL_OBJ_UNRESOLVED;
539
540  return true;
541}
542
543static bool
544rtems_rtl_elf_relocs_parser (rtems_rtl_obj*      obj,
545                             int                 fd,
546                             rtems_rtl_obj_sect* sect,
547                             void*               data)
548{
549  bool r = rtems_rtl_elf_relocate_worker (obj, fd, sect,
550                                          rtems_rtl_elf_reloc_parser, data);
551  return r;
552}
553
554static bool
555rtems_rtl_elf_relocs_locator (rtems_rtl_obj*      obj,
556                              int                 fd,
557                              rtems_rtl_obj_sect* sect,
558                              void*               data)
559{
560  return rtems_rtl_elf_relocate_worker (obj, fd, sect,
561                                        rtems_rtl_elf_reloc_relocator, data);
562}
563
564bool
565rtems_rtl_obj_relocate_unresolved (rtems_rtl_unresolv_reloc* reloc,
566                                   rtems_rtl_obj_sym*        sym)
567{
568  rtems_rtl_obj_sect*      sect;
569  bool                     is_rela;
570  Elf_Word                 symvalue;
571  rtems_rtl_obj*           sobj;
572  rtems_rtl_elf_rel_status rs;
573
574  is_rela = reloc->flags & 1;
575
576  sect = rtems_rtl_obj_find_section_by_index (reloc->obj, reloc->sect);
577  if (!sect)
578  {
579    rtems_rtl_set_error (ENOEXEC, "unresolved sect not found");
580    return false;
581  }
582
583  symvalue = (Elf_Word) (intptr_t) sym->value;
584  if (is_rela)
585  {
586    Elf_Rela rela;
587    rela.r_offset = reloc->rel[REL_R_OFFSET];
588    rela.r_info = reloc->rel[REL_R_INFO];
589    rela.r_addend = reloc->rel[REL_R_ADDEND];
590    if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
591          printf ("rtl: rela: sym:%d type:%d off:%08jx addend:%d\n",
592                  (int) ELF_R_SYM (rela.r_info), (int) ELF_R_TYPE (rela.r_info),
593                  (uintmax_t) rela.r_offset, (int) rela.r_addend);
594    rs = rtems_rtl_elf_relocate_rela (reloc->obj, &rela, sect,
595                                      sym->name, sym->data, symvalue);
596    if (rs != rtems_rtl_elf_rel_no_error)
597      return false;
598  }
599  else
600  {
601    Elf_Rel rel;
602    rel.r_offset = reloc->rel[REL_R_OFFSET];
603    rel.r_info = reloc->rel[REL_R_INFO];
604    if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
605      printf ("rtl: rel: sym:%d type:%d off:%08jx\n",
606              (int) ELF_R_SYM (rel.r_info), (int) ELF_R_TYPE (rel.r_info),
607              (uintmax_t) rel.r_offset);
608    rs = rtems_rtl_elf_relocate_rel (reloc->obj, &rel, sect,
609                                     sym->name, sym->data, symvalue);
610    if (rs != rtems_rtl_elf_rel_no_error)
611      return false;
612  }
613
614  if (reloc->obj->unresolved > 0)
615  {
616    --reloc->obj->unresolved;
617    if (reloc->obj->unresolved == 0)
618      reloc->obj->flags &= ~RTEMS_RTL_OBJ_UNRESOLVED;
619  }
620
621  sobj = rtems_rtl_find_obj_with_symbol (sym);
622
623  if (rtems_rtl_trace (RTEMS_RTL_TRACE_DEPENDENCY))
624    printf ("rtl: depend: %s -> %s:%s\n",
625            reloc->obj->oname,
626            sobj == NULL ? "not-found" : sobj->oname,
627            sym->name);
628
629  if (sobj != NULL)
630  {
631    if (rtems_rtl_obj_add_dependent (reloc->obj, sobj))
632      rtems_rtl_obj_inc_reference (sobj);
633  }
634
635  return true;
636}
637
638/**
639 * Common symbol iterator data.
640 */
641typedef struct
642{
643  size_t   size;      /**< The size of the common section */
644  uint32_t alignment; /**< The alignment of the common section. */
645} rtems_rtl_elf_common_data;
646
647static bool
648rtems_rtl_elf_common (rtems_rtl_obj*      obj,
649                      int                 fd,
650                      rtems_rtl_obj_sect* sect,
651                      void*               data)
652{
653  rtems_rtl_elf_common_data* common = (rtems_rtl_elf_common_data*) data;
654  rtems_rtl_obj_cache*       symbols;
655  int                        sym;
656
657  rtems_rtl_obj_caches (&symbols, NULL, NULL);
658
659  if (!symbols)
660    return false;
661
662  /*
663   * Find the number size of the common section by finding all symbols that
664   * reference the SHN_COMMON section.
665   */
666  for (sym = 0; sym < (sect->size / sizeof (Elf_Sym)); ++sym)
667  {
668    Elf_Sym symbol;
669    off_t   off;
670
671    off = obj->ooffset + sect->offset + (sym * sizeof (symbol));
672
673    if (!rtems_rtl_obj_cache_read_byval (symbols, fd, off,
674                                         &symbol, sizeof (symbol)))
675      return false;
676
677    if ((symbol.st_shndx == SHN_COMMON) &&
678        ((ELF_ST_TYPE (symbol.st_info) == STT_OBJECT) ||
679         (ELF_ST_TYPE (symbol.st_info) == STT_COMMON)))
680    {
681      if (rtems_rtl_trace (RTEMS_RTL_TRACE_SYMBOL))
682        printf ("rtl: com:elf:%-2d bind:%-2d type:%-2d size:%d value:%d name:%d\n",
683                sym, (int) ELF_ST_BIND (symbol.st_info),
684                (int) ELF_ST_TYPE (symbol.st_info),
685                (int) symbol.st_size, (int) symbol.st_value,
686                (int) symbol.st_name);
687      /*
688       * If the size is zero this is the first entry, it defines the common
689       * section's aligment. The symbol's value is the alignment.
690       */
691      if (common->size == 0)
692        common->alignment = symbol.st_value;
693      common->size +=
694        rtems_rtl_obj_align (common->size, symbol.st_value) + symbol.st_size;
695    }
696  }
697
698  return true;
699}
700
701/**
702 * Struct to handle trampoline reloc recs in the unresolved table.
703 */
704typedef struct rtems_rtl_tramp_data
705{
706  bool           failure;
707  rtems_rtl_obj* obj;
708  size_t         count;
709  size_t         total;
710} rtems_rtl_tramp_data;
711
712static bool
713rtems_rtl_elf_tramp_resolve_reloc (rtems_rtl_unresolv_rec* rec,
714                                   void*                   data)
715{
716  rtems_rtl_tramp_data* td = (rtems_rtl_tramp_data*) data;
717  if (rec->type == rtems_rtl_trampoline_reloc)
718  {
719    const rtems_rtl_tramp_reloc* tramp = &rec->rec.tramp;
720
721    ++td->total;
722
723    if (tramp->obj == td->obj)
724    {
725      const rtems_rtl_obj_sect* targetsect;
726      Elf_Byte                  st_info;
727      Elf_Word                  symvalue;
728      rtems_rtl_elf_rel_status  rs;
729      bool*                     failure = (bool*) data;
730      const bool                is_rela = (tramp->flags & 1) == 1;
731      const bool                unresolved = (tramp->flags & (1 << 1)) != 0;
732
733      ++td->count;
734
735      targetsect = rtems_rtl_obj_find_section_by_index (tramp->obj, tramp->sect);
736      st_info = tramp->flags >> 8;
737      symvalue = tramp->symvalue;
738
739      if (is_rela)
740      {
741        Elf_Rela rela = {
742          .r_offset = tramp->rel[REL_R_OFFSET],
743          .r_info   = tramp->rel[REL_R_INFO],
744          .r_addend = tramp->rel[REL_R_ADDEND]
745        };
746        if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
747          printf ("rtl: rela tramp: check: %c(%d)=%08jx type:%d off:%08jx addend:%d\n",
748                  ELF_ST_BIND (st_info) == STB_GLOBAL ||
749                  ELF_ST_BIND (st_info) == STB_WEAK ? 'G' : 'L',
750                  (int) ELF_R_SYM (rela.r_info),
751                  (uintmax_t) symvalue, (int) ELF_R_TYPE (rela.r_info),
752                  (uintmax_t) rela.r_offset, (int) rela.r_addend);
753        rs = rtems_rtl_elf_relocate_rela_tramp (tramp->obj, &rela, targetsect,
754                                                NULL, st_info, symvalue);
755      }
756      else
757      {
758        Elf_Rel rel = {
759          .r_offset = tramp->rel[REL_R_OFFSET],
760          .r_info   = tramp->rel[REL_R_INFO],
761        };
762        if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
763          printf ("rtl: rel tramp: check: %c(%d)=%08jx type:%d off:%08jx\n",
764                  ELF_ST_BIND (st_info) == STB_GLOBAL ||
765                  ELF_ST_BIND (st_info) == STB_WEAK ? 'G' : 'L',
766                  (int) ELF_R_SYM (rel.r_info),
767                  (uintmax_t) symvalue, (int) ELF_R_TYPE (rel.r_info),
768                  (uintmax_t) rel.r_offset);
769        rs = rtems_rtl_elf_relocate_rel_tramp (tramp->obj, &rel, targetsect,
770                                               NULL, st_info, symvalue);
771      }
772
773      if (unresolved || rs == rtems_rtl_elf_rel_tramp_add)
774        tramp->obj->tramps_size += tramp->obj->tramp_size;
775      if (rs == rtems_rtl_elf_rel_failure)
776      {
777        *failure = true;
778        return true;
779      }
780    }
781  }
782
783  return false;
784}
785
786static bool
787rtems_rtl_elf_alloc_trampoline (rtems_rtl_obj* obj, size_t unresolved)
788{
789  rtems_rtl_tramp_data td =  { 0 };
790  td.obj = obj;
791  /*
792   * See which relocs are out of range and need a trampoline.
793   */
794  rtems_rtl_unresolved_iterate (rtems_rtl_elf_tramp_resolve_reloc, &td);
795  if (td.failure)
796    return false;
797  rtems_rtl_trampoline_remove (obj);
798  obj->tramp_relocs = obj->tramp_size == 0 ? 0 : obj->tramps_size / obj->tramp_size;
799  if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
800    printf ("rtl: tramp:elf: tramps: %zu count:%zu total:%zu\n",
801            obj->tramp_relocs, td.count, td.total);
802  /*
803   * Add on enough space to handle the unresolved externals that need to be
804   * resolved at some point in time. They could all require fixups and
805   * trampolines.
806   */
807  obj->tramps_size += obj->tramp_size * unresolved;
808  if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
809    printf ("rtl: tramp:elf: slots: %zu (%zu)\n",
810            obj->tramp_size == 0 ? 0 : obj->tramps_size / obj->tramp_size,
811            obj->tramps_size);
812  return rtems_rtl_obj_alloc_trampoline (obj);
813}
814
815static bool
816rtems_rtl_elf_dependents (rtems_rtl_obj* obj, rtems_rtl_elf_reloc_data* reloc)
817{
818  /*
819   * If there are dependencies and no unresolved externals allocate and size
820   * the dependency table to the number of dependent object files. If there are
821   * unresolved externals the number of dependencies is unknown at this point
822   * in time so use dynamic allocation to allocate the block size number of
823   * entries when the entries are added.
824   */
825  if (reloc->dependents > 0 && reloc->unresolved == 0)
826  {
827    if (!rtems_rtl_obj_alloc_dependents (obj, reloc->dependents))
828      return false;
829  }
830  return true;
831}
832
833static bool
834rtems_rtl_elf_symbols_load (rtems_rtl_obj*      obj,
835                            int                 fd,
836                            rtems_rtl_obj_sect* sect,
837                            void*               data)
838{
839  rtems_rtl_obj_cache* symbols;
840  rtems_rtl_obj_cache* strings;
841  rtems_rtl_obj_sect*  strtab;
842  int                  locals;
843  int                  local_string_space;
844  rtems_rtl_obj_sym*   lsym;
845  char*                lstring;
846  int                  globals;
847  int                  global_string_space;
848  rtems_rtl_obj_sym*   gsym;
849  char*                gstring;
850  size_t               common_offset;
851  int                  sym;
852
853  strtab = rtems_rtl_obj_find_section (obj, ".strtab");
854  if (!strtab)
855  {
856    rtems_rtl_set_error (EINVAL, "no .strtab section");
857    return false;
858  }
859
860  rtems_rtl_obj_caches (&symbols, &strings, NULL);
861
862  if (!symbols || !strings)
863    return false;
864
865  /*
866   * Find the number of globals and the amount of string space
867   * needed. Also check for duplicate symbols.
868   */
869
870  globals             = 0;
871  global_string_space = 0;
872  locals              = 0;
873  local_string_space  = 0;
874
875  for (sym = 0; sym < (sect->size / sizeof (Elf_Sym)); ++sym)
876  {
877    Elf_Sym     symbol;
878    off_t       off;
879    const char* name;
880    size_t      len;
881
882    off = obj->ooffset + sect->offset + (sym * sizeof (symbol));
883
884    if (!rtems_rtl_obj_cache_read_byval (symbols, fd, off,
885                                         &symbol, sizeof (symbol)))
886      return false;
887
888    off = obj->ooffset + strtab->offset + symbol.st_name;
889    len = RTEMS_RTL_ELF_STRING_MAX;
890
891    if (!rtems_rtl_obj_cache_read (strings, fd, off, (void**) &name, &len))
892      return false;
893
894    /*
895     * Only keep the functions and global or weak symbols so place them in a
896     * separate table to local symbols. Local symbols are not needed after the
897     * object file has been loaded. Undefined symbols are NOTYPE so for locals
898     * we need to make sure there is a valid seciton.
899     */
900    if (rtems_rtl_trace (RTEMS_RTL_TRACE_SYMBOL))
901      printf ("rtl: sym:elf:%-4d name:%-4d: %-20s: bind:%-2d:%-12s " \
902              "type:%-2d:%-10s sect:%-5d size:%-5d value:%d\n",
903              sym, (int) symbol.st_name, name,
904              (int) ELF_ST_BIND (symbol.st_info),
905              rtems_rtl_elf_sym_bind_label (symbol.st_info),
906              (int) ELF_ST_TYPE (symbol.st_info),
907              rtems_rtl_elf_sym_type_label (symbol.st_info),
908              symbol.st_shndx,
909              (int) symbol.st_size,
910              (int) symbol.st_value);
911
912    /*
913     * If a duplicate forget it.
914     */
915    if (rtems_rtl_symbol_global_find (name))
916      continue;
917
918    if ((symbol.st_shndx != 0) &&
919        ((ELF_ST_TYPE (symbol.st_info) == STT_OBJECT) ||
920         (ELF_ST_TYPE (symbol.st_info) == STT_COMMON) ||
921         (ELF_ST_TYPE (symbol.st_info) == STT_FUNC) ||
922         (ELF_ST_TYPE (symbol.st_info) == STT_NOTYPE)))
923    {
924      /*
925       * There needs to be a valid section for the symbol.
926       */
927      rtems_rtl_obj_sect* symsect;
928
929      symsect = rtems_rtl_obj_find_section_by_index (obj, symbol.st_shndx);
930      if (symsect != NULL)
931      {
932        if ((ELF_ST_BIND (symbol.st_info) == STB_GLOBAL) ||
933            (ELF_ST_BIND (symbol.st_info) == STB_WEAK))
934        {
935          /*
936           * If there is a globally exported symbol already present and this
937           * symbol is not weak raise check if the object file being loaded is
938           * from an archive. If the base image is built with text sections a
939           * symbol with it's section will be linked into the base image and not
940           * another symbol. If not an archive rause an error.
941           *
942           * If the symbol is weak and present globally ignore this symbol and
943           * use the global one and if it is not present take this symbol global
944           * or weak. We accept the first weak symbol we find and make it
945           * globally exported.
946           */
947          if (rtems_rtl_symbol_global_find (name) &&
948              (ELF_ST_BIND (symbol.st_info) != STB_WEAK))
949          {
950            if (!rtems_rtl_obj_aname_valid (obj))
951            {
952              rtems_rtl_set_error (ENOMEM, "duplicate global symbol: %s", name);
953              return false;
954            }
955          }
956          else
957          {
958            if (rtems_rtl_trace (RTEMS_RTL_TRACE_SYMBOL))
959              printf ("rtl: sym:elf:%-4d name:%-4d: %-20s: global\n",
960                      sym, (int) symbol.st_name, name);
961            ++globals;
962            global_string_space += strlen (name) + 1;
963          }
964        }
965        else if (ELF_ST_BIND (symbol.st_info) == STB_LOCAL)
966        {
967          if (rtems_rtl_trace (RTEMS_RTL_TRACE_SYMBOL))
968            printf ("rtl: sym:elf:%-4d name:%-4d: %-20s: local\n",
969                    sym, (int) symbol.st_name, name);
970          ++locals;
971          local_string_space += strlen (name) + 1;
972        }
973      }
974    }
975  }
976
977  if (locals)
978  {
979    obj->local_size = locals * sizeof (rtems_rtl_obj_sym) + local_string_space;
980    obj->local_table = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_SYMBOL,
981                                            obj->local_size, true);
982    if (!obj->local_table)
983    {
984      obj->local_size = 0;
985      rtems_rtl_set_error (ENOMEM, "no memory for obj local syms");
986      return false;
987    }
988
989    obj->local_syms = locals;
990  }
991
992  if (globals)
993  {
994    obj->global_size = globals * sizeof (rtems_rtl_obj_sym) + global_string_space;
995    obj->global_table = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_SYMBOL,
996                                             obj->global_size, true);
997    if (!obj->global_table)
998    {
999      if (locals)
1000      {
1001        rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, obj->local_table);
1002        obj->local_size = 0;
1003        obj->local_syms = 0;
1004      }
1005      obj->global_size = 0;
1006      rtems_rtl_set_error (ENOMEM, "no memory for obj global syms");
1007      return false;
1008    }
1009
1010    obj->global_syms = globals;
1011  }
1012
1013  lsym = obj->local_table;
1014  lstring =
1015    (((char*) obj->local_table) + (locals * sizeof (rtems_rtl_obj_sym)));
1016  gsym = obj->global_table;
1017  gstring =
1018    (((char*) obj->global_table) + (globals * sizeof (rtems_rtl_obj_sym)));
1019
1020  common_offset = 0;
1021
1022  for (sym = 0; sym < (sect->size / sizeof (Elf_Sym)); ++sym)
1023  {
1024    Elf_Sym symbol;
1025    off_t   off;
1026    size_t  len;
1027
1028    off = obj->ooffset + sect->offset + (sym * sizeof (symbol));
1029
1030    if (!rtems_rtl_obj_cache_read_byval (symbols, fd, off,
1031                                         &symbol, sizeof (symbol)))
1032    {
1033      if (obj->local_syms)
1034      {
1035        rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, obj->local_table);
1036        obj->local_table = NULL;
1037        obj->local_size = 0;
1038        obj->local_syms = 0;
1039      }
1040      if (obj->global_syms)
1041      {
1042        rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, obj->global_table);
1043        obj->global_table = NULL;
1044        obj->global_syms = 0;
1045        obj->global_size = 0;
1046      }
1047      return false;
1048    }
1049
1050    if ((symbol.st_shndx != 0) &&
1051        ((ELF_ST_TYPE (symbol.st_info) == STT_OBJECT) ||
1052         (ELF_ST_TYPE (symbol.st_info) == STT_COMMON) ||
1053         (ELF_ST_TYPE (symbol.st_info) == STT_FUNC) ||
1054         (ELF_ST_TYPE (symbol.st_info) == STT_NOTYPE)) &&
1055         ((ELF_ST_BIND (symbol.st_info) == STB_GLOBAL) ||
1056          (ELF_ST_BIND (symbol.st_info) == STB_WEAK) ||
1057          (ELF_ST_BIND (symbol.st_info) == STB_LOCAL)))
1058    {
1059      rtems_rtl_obj_sect* symsect;
1060
1061      /*
1062       * There needs to be a valid section for the symbol.
1063       */
1064      symsect = rtems_rtl_obj_find_section_by_index (obj, symbol.st_shndx);
1065
1066      if (symsect != NULL)
1067      {
1068        rtems_rtl_obj_sym*  osym;
1069        char*               string;
1070        Elf_Word            value;
1071        const char*         name;
1072
1073        off = obj->ooffset + strtab->offset + symbol.st_name;
1074        len = RTEMS_RTL_ELF_STRING_MAX;
1075
1076        if (!rtems_rtl_obj_cache_read (strings, fd, off, (void**) &name, &len))
1077          return false;
1078
1079        /*
1080         * If a duplicate forget it.
1081         */
1082        if (rtems_rtl_symbol_global_find (name))
1083          continue;
1084
1085        if ((ELF_ST_BIND (symbol.st_info) == STB_GLOBAL) ||
1086            (ELF_ST_BIND (symbol.st_info) == STB_WEAK))
1087        {
1088          size_t slen = strlen (name) + 1;
1089          if ((gstring + slen) > (char*) obj->global_table + obj->global_size)
1090            string = NULL;
1091          else
1092          {
1093            osym = gsym;
1094            string = gstring;
1095            gstring += slen + 1;
1096            ++gsym;
1097          }
1098        }
1099        else
1100        {
1101          size_t slen = strlen (name) + 1;
1102          if ((lstring + slen) > (char*) obj->local_table + obj->local_size)
1103            string = NULL;
1104          else
1105          {
1106            osym = lsym;
1107            string = lstring;
1108            lstring += slen + 1;
1109            ++lsym;
1110          }
1111        }
1112
1113        /*
1114         * See if the loading has overflowed the allocated tables.
1115         */
1116        if (string == NULL)
1117        {
1118          if (obj->local_syms)
1119          {
1120            rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, obj->local_table);
1121            obj->local_table = NULL;
1122            obj->local_size = 0;
1123            obj->local_syms = 0;
1124          }
1125          if (obj->global_syms)
1126          {
1127            rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, obj->global_table);
1128            obj->global_table = NULL;
1129            obj->global_syms = 0;
1130            obj->global_size = 0;
1131          }
1132          rtems_rtl_set_error (ENOMEM, "syms overlow, parsing/loading size mismatch");
1133          return false;
1134        }
1135
1136        /*
1137         * Allocate any common symbols in the common section.
1138         */
1139        if (symbol.st_shndx == SHN_COMMON)
1140        {
1141          size_t value_off = rtems_rtl_obj_align (common_offset,
1142                                                  symbol.st_value);
1143          common_offset = value_off + symbol.st_size;
1144          value = value_off;
1145        }
1146        else
1147        {
1148          value = symbol.st_value;
1149        }
1150
1151        rtems_chain_set_off_chain (&osym->node);
1152        memcpy (string, name, strlen (name) + 1);
1153        osym->name = string;
1154        osym->value = (uint8_t*) value;
1155        osym->data = symbol.st_shndx;
1156
1157        if (rtems_rtl_trace (RTEMS_RTL_TRACE_SYMBOL))
1158          printf ("rtl: sym:add:%-4d name:%-4d: %-20s: bind:%-2d " \
1159                  "type:%-2d val:%-8p sect:%-3d size:%d\n",
1160                  sym, (int) symbol.st_name, osym->name,
1161                  (int) ELF_ST_BIND (symbol.st_info),
1162                  (int) ELF_ST_TYPE (symbol.st_info),
1163                  osym->value, symbol.st_shndx,
1164                  (int) symbol.st_size);
1165      }
1166    }
1167  }
1168
1169  return true;
1170}
1171
1172static bool
1173rtems_rtl_elf_symbols_locate (rtems_rtl_obj*      obj,
1174                              int                 fd,
1175                              rtems_rtl_obj_sect* sect,
1176                              void*               data)
1177{
1178  int sym;
1179
1180  for (sym = 0; sym < obj->local_syms; ++sym)
1181  {
1182      rtems_rtl_obj_sym*  osym = &obj->local_table[sym];
1183      rtems_rtl_obj_sect* symsect;
1184      symsect = rtems_rtl_obj_find_section_by_index (obj, osym->data);
1185      if (symsect)
1186      {
1187        osym->value += (intptr_t) symsect->base;
1188        if (rtems_rtl_trace (RTEMS_RTL_TRACE_SYMBOL))
1189          printf ("rtl: sym:locate:local :%-4d name: %-20s val:%-8p sect:%-3d (%s, %p)\n",
1190                  sym, osym->name, osym->value, osym->data,
1191                  symsect->name, symsect->base);
1192      }
1193  }
1194
1195  for (sym = 0; sym < obj->global_syms; ++sym)
1196  {
1197      rtems_rtl_obj_sym*  osym = &obj->global_table[sym];
1198      rtems_rtl_obj_sect* symsect;
1199      symsect = rtems_rtl_obj_find_section_by_index (obj, osym->data);
1200      if (symsect)
1201      {
1202        osym->value += (intptr_t) symsect->base;
1203        if (rtems_rtl_trace (RTEMS_RTL_TRACE_SYMBOL))
1204          printf ("rtl: sym:locate:global:%-4d name: %-20s val:%-8p sect:%-3d (%s, %p)\n",
1205                  sym, osym->name, osym->value, osym->data,
1206                  symsect->name, symsect->base);
1207      }
1208  }
1209
1210  if (obj->global_size)
1211    rtems_rtl_symbol_obj_add (obj);
1212
1213  return true;
1214}
1215
1216static bool
1217rtems_rtl_elf_arch_alloc (rtems_rtl_obj*      obj,
1218                          int                 fd,
1219                          rtems_rtl_obj_sect* sect,
1220                          void*               data)
1221{
1222  if (rtems_rtl_obj_sect_is_arch_alloc (sect))
1223    return rtems_rtl_elf_arch_section_alloc (obj, sect);
1224  return true;
1225}
1226
1227static bool
1228rtems_rtl_elf_arch_free (rtems_rtl_obj* obj)
1229{
1230  int index = -1;
1231  while (true)
1232  {
1233    rtems_rtl_obj_sect* sect;
1234    sect = rtems_rtl_obj_find_section_by_mask (obj,
1235                                               index,
1236                                               RTEMS_RTL_OBJ_SECT_ARCH_ALLOC);
1237    if (sect == NULL)
1238      break;
1239    if (!rtems_rtl_elf_arch_section_free (obj, sect))
1240      return false;
1241    index = sect->section;
1242  }
1243  return true;
1244}
1245
1246static bool
1247rtems_rtl_elf_loader (rtems_rtl_obj*      obj,
1248                      int                 fd,
1249                      rtems_rtl_obj_sect* sect,
1250                      void*               data)
1251{
1252  uint8_t* base_offset;
1253  size_t   len;
1254
1255  if (lseek (fd, obj->ooffset + sect->offset, SEEK_SET) < 0)
1256  {
1257    rtems_rtl_set_error (errno, "section load seek failed");
1258    return false;
1259  }
1260
1261  base_offset = sect->base;
1262  len = sect->size;
1263
1264  while (len)
1265  {
1266    ssize_t r = read (fd, base_offset, len);
1267    if (r <= 0)
1268    {
1269      rtems_rtl_set_error (errno, "section load read failed");
1270      return false;
1271    }
1272    base_offset += r;
1273    len -= r;
1274  }
1275
1276  return true;
1277}
1278
1279static bool
1280rtems_rtl_elf_parse_sections (rtems_rtl_obj* obj, int fd, Elf_Ehdr* ehdr)
1281{
1282  rtems_rtl_obj_cache* sects;
1283  rtems_rtl_obj_cache* strings;
1284  int                  section;
1285  off_t                sectstroff;
1286  off_t                off;
1287  Elf_Shdr             shdr;
1288
1289  rtems_rtl_obj_caches (&sects, &strings, NULL);
1290
1291  if (!sects || !strings)
1292    return false;
1293
1294  /*
1295   * Get the offset to the section string table.
1296   */
1297  off = obj->ooffset + ehdr->e_shoff + (ehdr->e_shstrndx * ehdr->e_shentsize);
1298
1299  if (!rtems_rtl_obj_cache_read_byval (sects, fd, off, &shdr, sizeof (shdr)))
1300    return false;
1301
1302  if (shdr.sh_type != SHT_STRTAB)
1303  {
1304    rtems_rtl_set_error (EINVAL, "bad .sectstr section type");
1305    return false;
1306  }
1307
1308  sectstroff = obj->ooffset + shdr.sh_offset;
1309
1310  for (section = 0; section < ehdr->e_shnum; ++section)
1311  {
1312    char*    name;
1313    size_t   len;
1314    uint32_t flags;
1315
1316    /*
1317     * Make sure section is at least 32bits to avoid 16-bit overflow errors.
1318     */
1319    off = obj->ooffset + ehdr->e_shoff + (((uint32_t) section) * ehdr->e_shentsize);
1320
1321    if (rtems_rtl_trace (RTEMS_RTL_TRACE_DETAIL))
1322      printf ("rtl: section header: %2d: offset=%d\n", section, (int) off);
1323
1324    if (!rtems_rtl_obj_cache_read_byval (sects, fd, off, &shdr, sizeof (shdr)))
1325      return false;
1326
1327    len = RTEMS_RTL_ELF_STRING_MAX;
1328    if (!rtems_rtl_obj_cache_read (strings, fd,
1329                                   sectstroff + shdr.sh_name,
1330                                   (void**) &name, &len))
1331      return false;
1332
1333    if (rtems_rtl_trace (RTEMS_RTL_TRACE_DETAIL))
1334      printf ("rtl: section: %2d: name=%s type=%d flags=%08x link=%d info=%d\n",
1335              section, name, (int) shdr.sh_type, (unsigned int) shdr.sh_flags,
1336              (int) shdr.sh_link, (int) shdr.sh_info);
1337
1338    flags = 0;
1339
1340    switch (shdr.sh_type)
1341    {
1342      case SHT_NULL:
1343        /*
1344         * Ignore.
1345         */
1346        break;
1347
1348      case SHT_PROGBITS:
1349        /*
1350         * There are 2 program bits sections. One is the program text and the
1351         * other is the program data. The program text is flagged
1352         * alloc/executable and the program data is flagged alloc/writable.
1353         */
1354        if ((shdr.sh_flags & SHF_ALLOC) == SHF_ALLOC)
1355        {
1356          if ((shdr.sh_flags & SHF_EXECINSTR) == SHF_EXECINSTR)
1357            flags = RTEMS_RTL_OBJ_SECT_TEXT | RTEMS_RTL_OBJ_SECT_LOAD;
1358          else if ((shdr.sh_flags & SHF_WRITE) == SHF_WRITE)
1359            flags = RTEMS_RTL_OBJ_SECT_DATA | RTEMS_RTL_OBJ_SECT_LOAD;
1360          else
1361            flags = RTEMS_RTL_OBJ_SECT_CONST | RTEMS_RTL_OBJ_SECT_LOAD;
1362        }
1363        break;
1364
1365      case SHT_NOBITS:
1366        /*
1367         * There is 1 NOBIT section which is the .bss section. There is nothing
1368         * but a definition as the .bss is just a clear region of memory.
1369         */
1370        if ((shdr.sh_flags & (SHF_ALLOC | SHF_WRITE)) == (SHF_ALLOC | SHF_WRITE))
1371          flags = RTEMS_RTL_OBJ_SECT_BSS | RTEMS_RTL_OBJ_SECT_ZERO;
1372        break;
1373
1374      case SHT_RELA:
1375        flags = RTEMS_RTL_OBJ_SECT_RELA | RTEMS_RTL_OBJ_SECT_LOAD;
1376        break;
1377
1378      case SHT_REL:
1379        /*
1380         * The sh_link holds the section index for the symbol table. The sh_info
1381         * holds the section index the relocations apply to.
1382         */
1383        flags = RTEMS_RTL_OBJ_SECT_REL | RTEMS_RTL_OBJ_SECT_LOAD;
1384        break;
1385
1386      case SHT_SYMTAB:
1387        flags = RTEMS_RTL_OBJ_SECT_SYM;
1388        break;
1389
1390      case SHT_STRTAB:
1391        flags = RTEMS_RTL_OBJ_SECT_STR;
1392        break;
1393
1394      case SHT_INIT_ARRAY:
1395        /*
1396         * Constructors are text and need to be loaded.
1397         */
1398        flags = (RTEMS_RTL_OBJ_SECT_CTOR |
1399                 RTEMS_RTL_OBJ_SECT_TEXT |
1400                 RTEMS_RTL_OBJ_SECT_LOAD);
1401        break;
1402
1403      case SHT_FINI_ARRAY:
1404        /*
1405         * Destructors are text and need to be loaded.
1406         */
1407        flags = (RTEMS_RTL_OBJ_SECT_DTOR |
1408                 RTEMS_RTL_OBJ_SECT_TEXT |
1409                 RTEMS_RTL_OBJ_SECT_LOAD);
1410        break;
1411
1412      default:
1413        /*
1414         * See if there are architecture specific flags?
1415         */
1416        flags = rtems_rtl_elf_section_flags (obj, &shdr);
1417        if (flags == 0)
1418        {
1419          if (rtems_rtl_trace (RTEMS_RTL_TRACE_WARNING))
1420            printf ("rtl: unsupported section: %2d: type=%02d flags=%02x\n",
1421                    section, (int) shdr.sh_type, (int) shdr.sh_flags);
1422        }
1423        break;
1424    }
1425
1426    if (flags != 0)
1427    {
1428      /*
1429       * If the object file is part of a library check the section's name. If it
1430       * starts with '.text.*' see if the last part is a global symbol. If a
1431       * global symbol exists we have to assume the symbol in the archive is a
1432       * duplicate can can be ignored.
1433       */
1434      if (rtems_rtl_obj_aname_valid (obj))
1435      {
1436        const char* symname = rtems_rtl_elf_separated_section (name);
1437        if (symname != NULL && rtems_rtl_symbol_global_find (symname))
1438          flags &= ~RTEMS_RTL_OBJ_SECT_LOAD;
1439      }
1440
1441      /*
1442       * If link ordering this section must appear in the same order in memory
1443       * as the linked-to section relative to the sections it loads with.
1444       */
1445      if ((shdr.sh_flags & SHF_LINK_ORDER) != 0)
1446        flags |= RTEMS_RTL_OBJ_SECT_LINK;
1447
1448      /*
1449       * Some architexctures have a named PROGBIT section for INIT/FINI.
1450       */
1451      if (strcmp (".ctors", name) == 0)
1452        flags |= RTEMS_RTL_OBJ_SECT_CTOR;
1453      if (strcmp (".dtors", name) == 0)
1454        flags |= RTEMS_RTL_OBJ_SECT_DTOR;
1455
1456      if (rtems_rtl_elf_unwind_parse (obj, name, flags))
1457      {
1458        flags &= ~(RTEMS_RTL_OBJ_SECT_TEXT | RTEMS_RTL_OBJ_SECT_CONST);
1459        flags |= RTEMS_RTL_OBJ_SECT_EH;
1460      }
1461
1462      /*
1463       * Architecture specific parsing. Modified or extends the flags.
1464       */
1465      flags = rtems_rtl_elf_arch_parse_section (obj, section, name, &shdr, flags);
1466      if (flags == 0)
1467      {
1468        if (rtems_rtl_trace (RTEMS_RTL_TRACE_WARNING))
1469          printf ("rtl: unsupported section: %2d: type=%02d flags=%02x\n",
1470                  section, (int) shdr.sh_type, (int) shdr.sh_flags);
1471        rtems_rtl_set_error (ENOMEM, "invalid architecture section: %s", name);
1472        return false;
1473      }
1474
1475      /*
1476       * Add the section.
1477       */
1478      if (!rtems_rtl_obj_add_section (obj, section, name,
1479                                      shdr.sh_size, shdr.sh_offset,
1480                                      shdr.sh_addralign, shdr.sh_link,
1481                                      shdr.sh_info, flags))
1482        return false;
1483    }
1484  }
1485
1486  return true;
1487}
1488
1489static bool
1490rtems_rtl_elf_add_common (rtems_rtl_obj* obj, size_t size, uint32_t alignment)
1491{
1492  if (size > 0)
1493  {
1494    if (!rtems_rtl_obj_add_section (obj, SHN_COMMON, ".common.rtems.rtl",
1495                                    size, 0, alignment, 0, 0,
1496                                    RTEMS_RTL_OBJ_SECT_BSS | RTEMS_RTL_OBJ_SECT_ZERO))
1497      return false;
1498  }
1499  return true;
1500}
1501
1502bool
1503rtems_rtl_elf_file_check (rtems_rtl_obj* obj, int fd)
1504{
1505  rtems_rtl_obj_cache* header;
1506  Elf_Ehdr             ehdr;
1507
1508  rtems_rtl_obj_caches (&header, NULL, NULL);
1509
1510  if (!rtems_rtl_obj_cache_read_byval (header, fd, obj->ooffset,
1511                                       &ehdr, sizeof (ehdr)))
1512    return false;
1513
1514  /*
1515   * Check we have a valid ELF file.
1516   */
1517  if ((memcmp (ELFMAG, ehdr.e_ident, SELFMAG) != 0)
1518      || ehdr.e_ident[EI_CLASS] != ELFCLASS)
1519  {
1520    return false;
1521  }
1522
1523  if ((ehdr.e_ident[EI_VERSION] != EV_CURRENT)
1524      || (ehdr.e_version != EV_CURRENT)
1525      || (ehdr.e_ident[EI_DATA] != ELFDEFNNAME (MACHDEP_ENDIANNESS)))
1526  {
1527    return false;
1528  }
1529
1530  return true;
1531}
1532
1533static bool
1534rtems_rtl_elf_load_linkmap (rtems_rtl_obj* obj)
1535{
1536  rtems_chain_control* sections = NULL;
1537  rtems_chain_node*    node = NULL;
1538  int                  sec_num = 0;
1539  section_detail*      sd;
1540  int                  i = 0;
1541  size_t               m;
1542
1543  /*
1544   * The section masks to add to the linkmap.
1545   */
1546  const uint32_t       sect_mask[] = {
1547    RTEMS_RTL_OBJ_SECT_TEXT | RTEMS_RTL_OBJ_SECT_LOAD,
1548    RTEMS_RTL_OBJ_SECT_CONST | RTEMS_RTL_OBJ_SECT_LOAD,
1549    RTEMS_RTL_OBJ_SECT_DATA | RTEMS_RTL_OBJ_SECT_LOAD,
1550    RTEMS_RTL_OBJ_SECT_BSS
1551  };
1552  const size_t sect_masks = sizeof (sect_mask) / sizeof (sect_mask[0]);
1553
1554  /*
1555   * Caculate the size of sections' name.
1556   */
1557  for (m = 0; m < sect_masks; ++m)
1558  {
1559    sections = &obj->sections;
1560    node = rtems_chain_first (sections);
1561    while (!rtems_chain_is_tail (sections, node))
1562    {
1563      rtems_rtl_obj_sect* sect = (rtems_rtl_obj_sect*) node;
1564      const uint32_t      mask = sect_mask[m];
1565      if ((sect->size != 0) && ((sect->flags & mask) == mask))
1566      {
1567        ++sec_num;
1568      }
1569      node = rtems_chain_next (node);
1570    }
1571  }
1572
1573  obj->obj_num = 1;
1574  obj->linkmap = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT,
1575                                      sizeof(struct link_map) +
1576                                      sec_num * sizeof (section_detail), true);
1577  if (!obj->linkmap)
1578  {
1579    rtems_rtl_set_error (ENOMEM, "no memory for obj linkmap");
1580    return false;
1581  }
1582
1583  obj->linkmap->name = obj->oname;
1584  obj->linkmap->sec_num = sec_num;
1585  obj->linkmap->sec_detail = (section_detail*) (obj->linkmap + 1);
1586  obj->linkmap->rpathlen = 0;
1587  obj->linkmap->rpath = NULL;
1588  obj->linkmap->l_next = NULL;
1589  obj->linkmap->l_prev = NULL;
1590  obj->linkmap->sec_addr[rap_text] = obj->text_base;
1591  obj->linkmap->sec_addr[rap_const] = obj->const_base;
1592  obj->linkmap->sec_addr[rap_data] = obj->data_base;
1593  obj->linkmap->sec_addr[rap_bss] = obj->bss_base;
1594
1595  sd = obj->linkmap->sec_detail;
1596  sections = &obj->sections;
1597  node = rtems_chain_first (sections);
1598
1599  for (m = 0; m < sect_masks; ++m)
1600  {
1601    sections = &obj->sections;
1602    node = rtems_chain_first (sections);
1603    while (!rtems_chain_is_tail (sections, node))
1604    {
1605      rtems_rtl_obj_sect* sect = (rtems_rtl_obj_sect*) node;
1606      const uint32_t      mask = sect_mask[m];
1607
1608      if ((sect->size != 0) && ((sect->flags & mask) == mask))
1609      {
1610        sd[i].name = sect->name;
1611        sd[i].size = sect->size;
1612        if ((mask & RTEMS_RTL_OBJ_SECT_TEXT) != 0)
1613        {
1614          sd[i].rap_id = rap_text;
1615          sd[i].offset = sect->base - obj->text_base;
1616        }
1617        if ((mask & RTEMS_RTL_OBJ_SECT_CONST) != 0)
1618        {
1619          sd[i].rap_id = rap_const;
1620          sd[i].offset = sect->base - obj->const_base;
1621        }
1622        if ((mask & RTEMS_RTL_OBJ_SECT_DATA) != 0)
1623        {
1624          sd[i].rap_id = rap_data;
1625          sd[i].offset = sect->base - obj->data_base;
1626        }
1627        if ((mask & RTEMS_RTL_OBJ_SECT_BSS) != 0)
1628        {
1629          sd[i].rap_id = rap_bss;
1630          sd[i].offset = sect->base - obj->bss_base;
1631        }
1632
1633        ++i;
1634      }
1635      node = rtems_chain_next (node);
1636    }
1637  }
1638
1639  return true;
1640}
1641
1642bool
1643rtems_rtl_elf_file_load (rtems_rtl_obj* obj, int fd)
1644{
1645  rtems_rtl_obj_cache*      header;
1646  Elf_Ehdr                  ehdr;
1647  rtems_rtl_elf_reloc_data  relocs = { 0 };
1648  rtems_rtl_elf_common_data common = { 0 };
1649
1650  rtems_rtl_obj_caches (&header, NULL, NULL);
1651
1652  if (!rtems_rtl_obj_cache_read_byval (header, fd, obj->ooffset,
1653                                       &ehdr, sizeof (ehdr)))
1654    return false;
1655
1656  /*
1657   * Check we have a valid ELF file.
1658   */
1659  if ((memcmp (ELFMAG, ehdr.e_ident, SELFMAG) != 0)
1660      || ehdr.e_ident[EI_CLASS] != ELFCLASS)
1661  {
1662    rtems_rtl_set_error (EINVAL, "invalid ELF file format");
1663    return false;
1664  }
1665
1666  if ((ehdr.e_ident[EI_VERSION] != EV_CURRENT)
1667      || (ehdr.e_version != EV_CURRENT)
1668      || (ehdr.e_ident[EI_DATA] != ELFDEFNNAME (MACHDEP_ENDIANNESS)))
1669  {
1670    rtems_rtl_set_error (EINVAL, "unsupported ELF file version");
1671    return false;
1672  }
1673
1674  if (!rtems_rtl_elf_machine_check (&ehdr))
1675  {
1676    rtems_rtl_set_error (EINVAL, "unsupported machine type");
1677    return false;
1678  }
1679
1680  if (ehdr.e_type == ET_DYN)
1681  {
1682    rtems_rtl_set_error (EINVAL, "unsupported ELF file type");
1683    return false;
1684  }
1685
1686  if (ehdr.e_phentsize != 0)
1687  {
1688    rtems_rtl_set_error (EINVAL, "ELF file contains program headers");
1689    return false;
1690  }
1691
1692  if (ehdr.e_shentsize != sizeof (Elf_Shdr))
1693  {
1694    rtems_rtl_set_error (EINVAL, "invalid ELF section header size");
1695    return false;
1696  }
1697
1698  /*
1699   * Set the format's architecture's maximum tramp size.
1700   */
1701  obj->tramp_size = rtems_rtl_elf_relocate_tramp_max_size ();
1702
1703  /*
1704   * Parse the section information first so we have the memory map of the object
1705   * file and the memory allocated. Any further allocations we make to complete
1706   * the load will not fragment the memory.
1707   */
1708  if (!rtems_rtl_elf_parse_sections (obj, fd, &ehdr))
1709    return false;
1710
1711  /*
1712   * Set the entry point if there is one.
1713   */
1714  obj->entry = (void*)(uintptr_t) ehdr.e_entry;
1715
1716  /*
1717   * Load the symbol table.
1718   *
1719   * 1. See if there are any common variables and if there are add a
1720   *    common section.
1721   * 2. Add up the common.
1722   * 3.
1723   */
1724  if (!rtems_rtl_obj_load_symbols (obj, fd, rtems_rtl_elf_common, &common))
1725    return false;
1726  if (!rtems_rtl_elf_add_common (obj, common.size, common.alignment))
1727    return false;
1728  if (!rtems_rtl_obj_load_symbols (obj, fd, rtems_rtl_elf_symbols_load, &ehdr))
1729    return false;
1730
1731  /*
1732   * Parse the relocation records. It lets us know how many dependents
1733   * and fixup trampolines there are.
1734   */
1735  if (!rtems_rtl_obj_relocate (obj, fd, rtems_rtl_elf_relocs_parser, &relocs))
1736    return false;
1737
1738  /*
1739   * Lock the allocator so the section memory and the trampoline memory are as
1740   * clock as possible.
1741   */
1742  rtems_rtl_alloc_lock ();
1743
1744  /*
1745   * Allocate the sections.
1746   */
1747  if (!rtems_rtl_obj_alloc_sections (obj, fd, rtems_rtl_elf_arch_alloc, &ehdr))
1748    return false;
1749
1750  if (!rtems_rtl_obj_load_symbols (obj, fd, rtems_rtl_elf_symbols_locate, &ehdr))
1751    return false;
1752
1753  if (!rtems_rtl_elf_dependents (obj, &relocs))
1754    return false;
1755
1756  if (!rtems_rtl_elf_alloc_trampoline (obj, relocs.unresolved))
1757    return false;
1758
1759  /*
1760   * Unlock the allocator.
1761   */
1762  rtems_rtl_alloc_unlock ();
1763
1764  /*
1765   * Load the sections and symbols and then relocation to the base address.
1766   */
1767  if (!rtems_rtl_obj_load_sections (obj, fd, rtems_rtl_elf_loader, &ehdr))
1768    return false;
1769
1770  /*
1771   * Fix up the relocations.
1772   */
1773  if (!rtems_rtl_obj_relocate (obj, fd, rtems_rtl_elf_relocs_locator, &ehdr))
1774    return false;
1775
1776  rtems_rtl_symbol_obj_erase_local (obj);
1777
1778  if (!rtems_rtl_elf_load_linkmap (obj))
1779  {
1780    return false;
1781  }
1782
1783  if (!rtems_rtl_elf_unwind_register (obj))
1784  {
1785    return false;
1786  }
1787
1788  return true;
1789}
1790
1791bool
1792rtems_rtl_elf_file_unload (rtems_rtl_obj* obj)
1793{
1794  rtems_rtl_elf_arch_free (obj);
1795  rtems_rtl_elf_unwind_deregister (obj);
1796  return true;
1797}
1798
1799rtems_rtl_loader_format*
1800rtems_rtl_elf_file_sig (void)
1801{
1802  return &elf_sig;
1803}
Note: See TracBrowser for help on using the repository browser.