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

5
Last change on this file since 8bd4f61c was b36c5209, checked in by Chris Johns <chrisj@…>, on 05/03/19 at 00:15:20

libdl: Do not access the ELF file while the allocator is locked.

  • Load symbols before allocation.
  • Parse reloc records and place any reloc recs in a cache to use while the allocator is locked.
  • Relocate symbols after section allocation.
  • Split section loading into allocation/locating and loading.
  • Update all arch back-ends with a new reloc interface to control tramp handling.
  • Add -a and -t to the object list shell command.

Closes #3741

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