source: rtems/cpukit/libdl/rtl-obj.c @ 2b885d6

5
Last change on this file since 2b885d6 was 2b885d6, checked in by Pavel Pisa <pisa@…>, on Jul 3, 2016 at 4:24:27 PM

libdl/rtl-obj.c: ensure that loaded code is synchronized through caches.

Synchronize each cluster of sections of the same type separately
to support even cases where text and data are allocated from different
areas (for example due allocation from different MPU protection regions).

rtems_cache_instruction_sync_after_code_change is called even to data
sections. Propagation of data only changes should not require cache
maintenance operation on sane SMP mutithread capable systems if barrier
instruction is added but be on safe side even for case where self
modifying code uses data sections initial values etc.

  • Property mode set to 100644
File size: 28.0 KB
Line 
1/*
2 *  COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org>
3 *
4 *  The license and distribution terms for this file may be
5 *  found in the file LICENSE in this distribution or at
6 *  http://www.rtems.org/license/LICENSE.
7 */
8/**
9 * @file
10 *
11 * @ingroup rtl
12 *
13 * @brief RTEMS Run-Time Linker Error
14 */
15
16#if HAVE_CONFIG_H
17#include "config.h"
18#endif
19
20#include <errno.h>
21#include <inttypes.h>
22#include <stdlib.h>
23#include <stdio.h>
24
25#include <rtems/libio_.h>
26
27#include <rtems/rtl/rtl.h>
28#include "rtl-chain-iterator.h"
29#include "rtl-obj.h"
30#include "rtl-error.h"
31#include "rtl-find-file.h"
32#include "rtl-string.h"
33#include "rtl-trace.h"
34
35#if RTEMS_RTL_RAP_LOADER
36#include "rtl-rap.h"
37#define RTEMS_RTL_RAP_LOADER_COUNT 1
38#else
39#define RTEMS_RTL_RAP_LOADER_COUNT 0
40#endif
41
42#if RTEMS_RTL_ELF_LOADER
43#include "rtl-elf.h"
44#define RTEMS_RTL_ELF_LOADER_COUNT 1
45#else
46#define RTEMS_RTL_ELF_LOADER_COUNT 0
47#endif
48
49/**
50 * The table of supported loader formats.
51 */
52static rtems_rtl_loader_table_t loaders[RTEMS_RTL_ELF_LOADER_COUNT +
53                                        RTEMS_RTL_RAP_LOADER_COUNT] =
54{
55#if RTEMS_RTL_RAP_LOADER
56  { rtems_rtl_rap_file_check, rtems_rtl_rap_file_load, rtems_rtl_rap_file_sig },
57#endif
58#if RTEMS_RTL_ELF_LOADER
59  { rtems_rtl_elf_file_check, rtems_rtl_elf_file_load, rtems_rtl_elf_file_sig },
60#endif
61};
62
63rtems_rtl_obj_t*
64rtems_rtl_obj_alloc (void)
65{
66  rtems_rtl_obj_t* obj = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT,
67                                              sizeof (rtems_rtl_obj_t),
68                                              true);
69  if (obj)
70  {
71    /*
72     * Initialise the chains.
73     */
74    rtems_chain_initialize_empty (&obj->sections);
75  }
76  return obj;
77}
78
79static void
80rtems_rtl_obj_free_names (rtems_rtl_obj_t* obj)
81{
82  if (rtems_rtl_obj_oname_valid (obj))
83    rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, (void*) obj->oname);
84  if (rtems_rtl_obj_aname_valid (obj))
85    rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, (void*) obj->aname);
86  if (rtems_rtl_obj_fname_valid (obj))
87    rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, (void*) obj->fname);
88}
89
90bool
91rtems_rtl_obj_free (rtems_rtl_obj_t* obj)
92{
93  if (obj->users || ((obj->flags & RTEMS_RTL_OBJ_LOCKED) != 0))
94  {
95    rtems_rtl_set_error (EINVAL, "cannot free obj still in use");
96    return false;
97  }
98  if (!rtems_chain_is_node_off_chain (&obj->link))
99    rtems_chain_extract (&obj->link);
100  rtems_rtl_alloc_module_del (&obj->text_base, &obj->const_base,
101                              &obj->data_base, &obj->bss_base);
102  rtems_rtl_symbol_obj_erase (obj);
103  rtems_rtl_obj_free_names (obj);
104  if (obj->sec_num)
105    free (obj->sec_num);
106  if (obj->detail)
107    rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, (void*)obj->detail);
108  rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, obj);
109  return true;
110}
111
112bool
113rtems_rtl_obj_unresolved (rtems_rtl_obj_t* obj)
114{
115  return (obj->flags & RTEMS_RTL_OBJ_UNRESOLVED) != 0 ? true : false;
116}
117
118bool
119rtems_rtl_parse_name (const char*  name,
120                      const char** aname,
121                      const char** oname,
122                      off_t*       ooffset)
123{
124  const char* laname = NULL;
125  const char* loname = NULL;
126  const char* colon;
127  const char* end;
128
129  /*
130   * Parse the name to determine if the object file is part of an archive or it
131   * is an object file. If an archive check the name for a '@' to see if the
132   * archive contains an offset.
133   */
134  end = name + strlen (name);
135  colon = strrchr (name, ':');
136  if (colon == NULL || colon < strrchr(name, '/'))
137    colon = end;
138
139  loname = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, colon - name + 1, true);
140  if (!oname)
141  {
142    rtems_rtl_set_error (ENOMEM, "no memory for object file name");
143    return false;
144  }
145
146  memcpy ((void*) loname, name, colon - name);
147
148  /*
149   * If the pointers match there is no ':' delimiter.
150   */
151  if (colon != end)
152  {
153    const char* at;
154
155    /*
156     * The file name is an archive and the object file name is next after the
157     * delimiter. Move the pointer to the archive name.
158     */
159    laname = loname;
160    ++colon;
161
162    /*
163     * See if there is a '@' to delimit an archive offset for the object in the
164     * archive.
165     */
166    at = strchr (colon, '@');
167
168    if (at == NULL)
169      at = end;
170
171
172    loname = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, at - colon + 1, true);
173    if (!loname)
174    {
175      rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, (void*) laname);
176      rtems_rtl_set_error (ENOMEM, "no memory for object file name");
177      return false;
178    }
179
180    memcpy ((void*) loname, colon, at - colon);
181
182    if (at != end)
183    {
184      /*
185       * The object name has an archive offset. If the number
186       * does not parse 0 will be returned and the archive will be
187       * searched.
188       */
189      *ooffset = strtoul (at + 1, 0, 0);
190    }
191  }
192
193  *oname = loname;
194  *aname = laname;
195  return true;
196}
197
198static bool
199rtems_rtl_obj_parse_name (rtems_rtl_obj_t* obj, const char* name)
200{
201  return rtems_rtl_parse_name (name, &(obj->aname), &(obj->oname), &(obj->ooffset));
202}
203
204static bool
205rtems_rtl_seek_read (int fd, off_t off, size_t len, uint8_t* buffer)
206{
207  if (lseek (fd, off, SEEK_SET) < 0)
208    return false;
209  if (read (fd, buffer, len) != len)
210    return false;
211  return true;
212}
213
214/**
215 * Scan the decimal number returning the value found.
216 */
217static uint64_t
218rtems_rtl_scan_decimal (const uint8_t* string, size_t len)
219{
220  uint64_t value = 0;
221
222  while (len && (*string != ' '))
223  {
224    value *= 10;
225    value += *string - '0';
226    ++string;
227    --len;
228  }
229
230  return value;
231}
232
233/**
234 * Align the size to the next alignment point. Assume the alignment is a
235 * positive integral power of 2 if not 0 or 1. If 0 or 1 then there is no
236 * alignment.
237 */
238static size_t
239rtems_rtl_sect_align (size_t offset, uint32_t alignment)
240{
241  if ((alignment > 1) && ((offset & ~alignment) != 0))
242    offset = (offset + alignment) & ~(alignment - 1);
243  return offset;
244}
245
246/**
247 * Section size summer iterator data.
248 */
249typedef struct
250{
251  uint32_t mask; /**< The selection mask to sum. */
252  size_t   size; /**< The size of all section fragments. */
253} rtems_rtl_obj_sect_summer_t;
254
255static bool
256rtems_rtl_obj_sect_summer (rtems_chain_node* node, void* data)
257{
258  rtems_rtl_obj_sect_t*        sect = (rtems_rtl_obj_sect_t*) node;
259  rtems_rtl_obj_sect_summer_t* summer = data;
260  if ((sect->flags & summer->mask) == summer->mask)
261    summer->size =
262      rtems_rtl_sect_align (summer->size, sect->alignment) + sect->size;
263  return true;
264}
265
266static size_t
267rtems_rtl_obj_section_size (rtems_rtl_obj_t* obj, uint32_t mask)
268{
269  rtems_rtl_obj_sect_summer_t summer;
270  summer.mask = mask;
271  summer.size = 0;
272  rtems_rtl_chain_iterate (&obj->sections,
273                           rtems_rtl_obj_sect_summer,
274                           &summer);
275  return summer.size;
276}
277
278/**
279 * Section alignment iterator data. The first section's alignment sets the
280 * alignment for that type of section.
281 */
282typedef struct
283{
284  uint32_t mask;      /**< The selection mask to look for alignment. */
285  uint32_t alignment; /**< The alignment of the section type. */
286} rtems_rtl_obj_sect_aligner_t;
287
288/**
289 * The section aligner iterator.
290 */
291static bool
292rtems_rtl_obj_sect_aligner (rtems_chain_node* node, void* data)
293{
294  rtems_rtl_obj_sect_t*         sect = (rtems_rtl_obj_sect_t*) node;
295  rtems_rtl_obj_sect_aligner_t* aligner = data;
296  if ((sect->flags & aligner->mask) == aligner->mask)
297  {
298    aligner->alignment = sect->alignment;
299    return false;
300  }
301  return true;
302}
303
304static size_t
305rtems_rtl_obj_section_alignment (rtems_rtl_obj_t* obj, uint32_t mask)
306{
307  rtems_rtl_obj_sect_aligner_t aligner;
308  aligner.mask = mask;
309  aligner.alignment = 0;
310  rtems_rtl_chain_iterate (&obj->sections,
311                           rtems_rtl_obj_sect_aligner,
312                           &aligner);
313  return aligner.alignment;
314}
315
316static bool
317rtems_rtl_obj_section_handler (uint32_t                     mask,
318                               rtems_rtl_obj_t*             obj,
319                               int                          fd,
320                               rtems_rtl_obj_sect_handler_t handler,
321                               void*                        data)
322{
323  rtems_chain_node* node = rtems_chain_first (&obj->sections);
324  while (!rtems_chain_is_tail (&obj->sections, node))
325  {
326    rtems_rtl_obj_sect_t* sect = (rtems_rtl_obj_sect_t*) node;
327    if ((sect->flags & mask) != 0)
328    {
329      if (!handler (obj, fd, sect, data))
330        return false;
331    }
332    node = rtems_chain_next (node);
333  }
334  return true;
335}
336
337bool
338rtems_rtl_match_name (rtems_rtl_obj_t* obj, const char* name)
339{
340  const char* n1 = obj->oname;
341  while ((*n1 != '\0') && (*n1 != '\n') && (*n1 != '/') &&
342         (*name != '\0') && (*name != '/') && (*n1 == *name))
343  {
344    ++n1;
345    ++name;
346  }
347  if (((*n1 == '\0') || (*n1 == '\n') || (*n1 == '/')) &&
348      ((*name == '\0') || (*name == '/')))
349    return true;
350  return false;
351}
352
353bool
354rtems_rtl_obj_find_file (rtems_rtl_obj_t* obj, const char* name)
355{
356  const char*       pname;
357  rtems_rtl_data_t* rtl;
358
359  /*
360   * Parse the name. The object descriptor will have the archive name and/or
361   * object name fields filled in. A find of the file will result in the file
362   * name (fname) field pointing to the actual file if present on the file
363   * system.
364   */
365  if (!rtems_rtl_obj_parse_name (obj, name))
366    return false;
367
368  /*
369   * If the archive field (aname) is set we use that name else we use the
370   * object field (oname). If selected name is absolute we just point the aname
371   * field to the fname field to that name. If the field is relative we search
372   * the paths set in the RTL for the file.
373   */
374  if (rtems_rtl_obj_aname_valid (obj))
375    pname = rtems_rtl_obj_aname (obj);
376  else
377    pname = rtems_rtl_obj_oname (obj);
378
379  rtl = rtems_rtl_lock ();
380
381  if (!rtems_rtl_find_file (pname, rtl->paths, &obj->fname, &obj->fsize))
382  {
383    rtems_rtl_set_error (ENOENT, "file not found");
384    rtems_rtl_unlock ();
385    return false;
386  }
387
388  rtems_rtl_unlock ();
389
390  return true;
391}
392
393bool
394rtems_rtl_obj_add_section (rtems_rtl_obj_t* obj,
395                           int              section,
396                           const char*      name,
397                           size_t           size,
398                           off_t            offset,
399                           uint32_t         alignment,
400                           int              link,
401                           int              info,
402                           uint32_t         flags)
403{
404  rtems_rtl_obj_sect_t* sect = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT,
405                                                    sizeof (rtems_rtl_obj_sect_t), true);
406  if (!sect)
407  {
408    rtems_rtl_set_error (ENOMEM, "adding allocated section");
409    return false;
410  }
411  sect->section = section;
412  sect->name = rtems_rtl_strdup (name);
413  sect->size = size;
414  sect->offset = offset;
415  sect->alignment = alignment;
416  sect->link = link;
417  sect->info = info;
418  sect->flags = flags;
419  sect->base = NULL;
420  rtems_chain_append (&obj->sections, &sect->node);
421
422  if (rtems_rtl_trace (RTEMS_RTL_TRACE_SECTION))
423    printf ("rtl: sect: %-2d: %s\n", section, name);
424
425  return true;
426}
427
428void
429rtems_rtl_obj_erase_sections (rtems_rtl_obj_t* obj)
430{
431  rtems_chain_node* node = rtems_chain_first (&obj->sections);
432  while (!rtems_chain_is_tail (&obj->sections, node))
433  {
434    rtems_rtl_obj_sect_t* sect = (rtems_rtl_obj_sect_t*) node;
435    rtems_chain_node*     next_node = rtems_chain_next (node);
436    rtems_chain_extract (node);
437    rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, (void*) sect->name);
438    rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, sect);
439    node = next_node;
440  }
441}
442
443/**
444 * Section finder iterator data.
445 */
446typedef struct
447{
448  rtems_rtl_obj_sect_t*  sect;  /**< The matching section. */
449  const char*            name;  /**< The name to match. */
450  int                    index; /**< The index to match. */
451} rtems_rtl_obj_sect_finder_t;
452
453static bool
454rtems_rtl_obj_sect_match_name (rtems_chain_node* node, void* data)
455{
456  rtems_rtl_obj_sect_t*        sect = (rtems_rtl_obj_sect_t*) node;
457  rtems_rtl_obj_sect_finder_t* match = data;
458  if (strcmp (sect->name, match->name) == 0)
459  {
460    match->sect = sect;
461    return false;
462  }
463  return true;
464}
465
466rtems_rtl_obj_sect_t*
467rtems_rtl_obj_find_section (rtems_rtl_obj_t* obj, const char* name)
468{
469  rtems_rtl_obj_sect_finder_t match;
470  match.sect = NULL;
471  match.name = name;
472  rtems_rtl_chain_iterate (&obj->sections,
473                           rtems_rtl_obj_sect_match_name,
474                           &match);
475  return match.sect;
476}
477
478static bool
479rtems_rtl_obj_sect_match_index (rtems_chain_node* node, void* data)
480{
481  rtems_rtl_obj_sect_t*        sect = (rtems_rtl_obj_sect_t*) node;
482  rtems_rtl_obj_sect_finder_t* match = data;
483  if (sect->section == match->index)
484  {
485    match->sect = sect;
486    return false;
487  }
488  return true;
489}
490
491rtems_rtl_obj_sect_t*
492rtems_rtl_obj_find_section_by_index (rtems_rtl_obj_t* obj, int index)
493{
494  rtems_rtl_obj_sect_finder_t match;
495  match.sect = NULL;
496  match.index = index;
497  rtems_rtl_chain_iterate (&obj->sections,
498                           rtems_rtl_obj_sect_match_index,
499                           &match);
500  return match.sect;
501}
502
503size_t
504rtems_rtl_obj_text_size (rtems_rtl_obj_t* obj)
505{
506  return rtems_rtl_obj_section_size (obj, RTEMS_RTL_OBJ_SECT_TEXT);
507}
508
509uint32_t
510rtems_rtl_obj_text_alignment (rtems_rtl_obj_t* obj)
511{
512  return rtems_rtl_obj_section_alignment (obj, RTEMS_RTL_OBJ_SECT_TEXT);
513}
514
515size_t
516rtems_rtl_obj_const_size (rtems_rtl_obj_t* obj)
517{
518  return rtems_rtl_obj_section_size (obj, RTEMS_RTL_OBJ_SECT_CONST);
519}
520
521uint32_t
522rtems_rtl_obj_const_alignment (rtems_rtl_obj_t* obj)
523{
524  return rtems_rtl_obj_section_alignment (obj, RTEMS_RTL_OBJ_SECT_CONST);
525}
526
527size_t
528rtems_rtl_obj_data_size (rtems_rtl_obj_t* obj)
529{
530  return rtems_rtl_obj_section_size (obj, RTEMS_RTL_OBJ_SECT_DATA);
531}
532
533uint32_t
534rtems_rtl_obj_data_alignment (rtems_rtl_obj_t* obj)
535{
536  return rtems_rtl_obj_section_alignment (obj, RTEMS_RTL_OBJ_SECT_DATA);
537}
538
539size_t
540rtems_rtl_obj_bss_size (rtems_rtl_obj_t* obj)
541{
542  return rtems_rtl_obj_section_size (obj, RTEMS_RTL_OBJ_SECT_BSS);
543}
544
545uint32_t
546rtems_rtl_obj_bss_alignment (rtems_rtl_obj_t* obj)
547{
548  return rtems_rtl_obj_section_alignment (obj, RTEMS_RTL_OBJ_SECT_BSS);
549}
550
551bool
552rtems_rtl_obj_relocate (rtems_rtl_obj_t*             obj,
553                        int                          fd,
554                        rtems_rtl_obj_sect_handler_t handler,
555                        void*                        data)
556{
557  uint32_t mask = RTEMS_RTL_OBJ_SECT_REL | RTEMS_RTL_OBJ_SECT_RELA;
558  return rtems_rtl_obj_section_handler (mask, obj, fd, handler, data);
559}
560
561bool
562rtems_rtl_obj_load_symbols (rtems_rtl_obj_t*             obj,
563                            int                          fd,
564                            rtems_rtl_obj_sect_handler_t handler,
565                            void*                        data)
566{
567  uint32_t mask = RTEMS_RTL_OBJ_SECT_SYM;
568  return rtems_rtl_obj_section_handler (mask, obj, fd, handler, data);
569}
570
571static size_t
572rtems_rtl_obj_sections_loader (uint32_t                     mask,
573                               rtems_rtl_obj_t*             obj,
574                               int                          fd,
575                               uint8_t*                     base,
576                               rtems_rtl_obj_sect_handler_t handler,
577                               void*                        data)
578{
579  rtems_chain_control* sections = &obj->sections;
580  rtems_chain_node*    node = rtems_chain_first (sections);
581  size_t               base_offset = 0;
582  bool                 first = true;
583  while (!rtems_chain_is_tail (sections, node))
584  {
585    rtems_rtl_obj_sect_t* sect = (rtems_rtl_obj_sect_t*) node;
586
587    if ((sect->size != 0) && ((sect->flags & mask) != 0))
588    {
589      if (!first)
590        base_offset = rtems_rtl_sect_align (base_offset, sect->alignment);
591
592      sect->base = base + base_offset;
593
594      if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD_SECT))
595        printf ("rtl: loading: %s -> %8p (%zi)\n",
596                sect->name, sect->base, sect->size);
597
598      if ((sect->flags & RTEMS_RTL_OBJ_SECT_LOAD) == RTEMS_RTL_OBJ_SECT_LOAD)
599      {
600        if (!handler (obj, fd, sect, data))
601        {
602          sect->base = 0;
603          return false;
604        }
605      }
606      else if ((sect->flags & RTEMS_RTL_OBJ_SECT_ZERO) == RTEMS_RTL_OBJ_SECT_ZERO)
607      {
608        memset (base + base_offset, 0, sect->size);
609      }
610      else
611      {
612        sect->base = 0;
613        rtems_rtl_set_error (errno, "section has no load op");
614        return false;
615      }
616
617      base_offset += sect->size;
618      first = false;
619    }
620
621    rtems_cache_instruction_sync_after_code_change(base, base_offset);
622
623    node = rtems_chain_next (node);
624  }
625
626  return true;
627}
628
629bool
630rtems_rtl_obj_load_sections (rtems_rtl_obj_t*             obj,
631                             int                          fd,
632                             rtems_rtl_obj_sect_handler_t handler,
633                             void*                        data)
634{
635  size_t text_size;
636  size_t const_size;
637  size_t data_size;
638  size_t bss_size;
639
640  text_size  = rtems_rtl_obj_text_size (obj) + rtems_rtl_obj_const_alignment (obj);
641  const_size = rtems_rtl_obj_const_size (obj) + rtems_rtl_obj_data_alignment (obj);
642  data_size  = rtems_rtl_obj_data_size (obj) + rtems_rtl_obj_bss_alignment (obj);
643  bss_size   = rtems_rtl_obj_bss_size (obj);
644
645  /*
646   * Let the allocator manage the actual allocation. The user can use the
647   * standard heap or provide a specific allocator with memory protection.
648   */
649  if (!rtems_rtl_alloc_module_new (&obj->text_base, text_size,
650                                   &obj->const_base, const_size,
651                                   &obj->data_base, data_size,
652                                   &obj->bss_base, bss_size))
653  {
654    obj->exec_size = 0;
655    rtems_rtl_set_error (ENOMEM, "no memory to load obj");
656    return false;
657  }
658
659  obj->exec_size = text_size + const_size + data_size + bss_size;
660
661  if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD_SECT))
662  {
663    printf ("rtl: load sect: text  - b:%p s:%zi a:%" PRIu32 "\n",
664            obj->text_base, text_size, rtems_rtl_obj_text_alignment (obj));
665    printf ("rtl: load sect: const - b:%p s:%zi a:%" PRIu32 "\n",
666            obj->const_base, const_size, rtems_rtl_obj_const_alignment (obj));
667    printf ("rtl: load sect: data  - b:%p s:%zi a:%" PRIu32 "\n",
668            obj->data_base, data_size, rtems_rtl_obj_data_alignment (obj));
669    printf ("rtl: load sect: bss   - b:%p s:%zi a:%" PRIu32 "\n",
670            obj->bss_base, bss_size, rtems_rtl_obj_bss_alignment (obj));
671  }
672
673  /*
674   * Load all text then data then bss sections in seperate operations so each
675   * type of section is grouped together.
676   */
677  if (!rtems_rtl_obj_sections_loader (RTEMS_RTL_OBJ_SECT_TEXT,
678                                      obj, fd, obj->text_base, handler, data) ||
679      !rtems_rtl_obj_sections_loader (RTEMS_RTL_OBJ_SECT_CONST,
680                                      obj, fd, obj->const_base, handler, data) ||
681      !rtems_rtl_obj_sections_loader (RTEMS_RTL_OBJ_SECT_DATA,
682                                      obj, fd, obj->data_base, handler, data) ||
683      !rtems_rtl_obj_sections_loader (RTEMS_RTL_OBJ_SECT_BSS,
684                                      obj, fd, obj->bss_base, handler, data))
685  {
686    rtems_rtl_alloc_module_del (&obj->text_base, &obj->const_base,
687                                &obj->data_base, &obj->bss_base);
688    obj->exec_size = 0;
689    return false;
690  }
691
692  return true;
693}
694
695static void
696rtems_rtl_obj_run_cdtors (rtems_rtl_obj_t* obj, uint32_t mask)
697{
698  rtems_chain_node* node = rtems_chain_first (&obj->sections);
699  while (!rtems_chain_is_tail (&obj->sections, node))
700  {
701    rtems_rtl_obj_sect_t* sect = (rtems_rtl_obj_sect_t*) node;
702    if ((sect->flags & mask) == mask)
703    {
704      rtems_rtl_cdtor_t* handler;
705      size_t             handlers = sect->size / sizeof (rtems_rtl_cdtor_t);
706      int                c;
707      for (c = 0, handler = sect->base; c < handlers; ++c)
708        if (*handler)
709          (*handler) ();
710    }
711    node = rtems_chain_next (node);
712  }
713}
714
715void
716rtems_rtl_obj_run_ctors (rtems_rtl_obj_t* obj)
717{
718  return rtems_rtl_obj_run_cdtors (obj, RTEMS_RTL_OBJ_SECT_CTOR);
719}
720
721void
722rtems_rtl_obj_run_dtors (rtems_rtl_obj_t* obj)
723{
724  return rtems_rtl_obj_run_cdtors (obj, RTEMS_RTL_OBJ_SECT_DTOR);
725}
726
727/**
728 * Find a module in an archive returning the offset in the archive in the
729 * object descriptor.
730 */
731static bool
732rtems_rtl_obj_archive_find (rtems_rtl_obj_t* obj, int fd)
733{
734#define RTEMS_RTL_AR_IDENT      "!<arch>\n"
735#define RTEMS_RTL_AR_IDENT_SIZE (sizeof (RTEMS_RTL_AR_IDENT) - 1)
736#define RTEMS_RTL_AR_FHDR_BASE  RTEMS_RTL_AR_IDENT_SIZE
737#define RTEMS_RTL_AR_FNAME      (0)
738#define RTEMS_RTL_AR_FNAME_SIZE (16)
739#define RTEMS_RTL_AR_SIZE       (48)
740#define RTEMS_RTL_AR_SIZE_SIZE  (10)
741#define RTEMS_RTL_AR_MAGIC      (58)
742#define RTEMS_RTL_AR_MAGIC_SIZE (2)
743#define RTEMS_RTL_AR_FHDR_SIZE  (60)
744
745  size_t  fsize = obj->fsize;
746  off_t   extended_file_names;
747  uint8_t header[RTEMS_RTL_AR_FHDR_SIZE];
748  bool    scanning;
749
750  if (read (fd, &header[0], RTEMS_RTL_AR_IDENT_SIZE) !=  RTEMS_RTL_AR_IDENT_SIZE)
751  {
752    rtems_rtl_set_error (errno, "reading archive identifer");
753    return false;
754  }
755
756  if (memcmp (header, RTEMS_RTL_AR_IDENT, RTEMS_RTL_AR_IDENT_SIZE) != 0)
757  {
758    rtems_rtl_set_error (EINVAL, "invalid archive identifer");
759    return false;
760  }
761
762  /*
763   * Seek to the current offset in the archive and if we have a valid archive
764   * file header present check the file name for a match with the oname field
765   * of the object descriptor. If the archive header is not valid and it is the
766   * first pass reset the offset and start the search again in case the offset
767   * provided is not valid any more.
768   *
769   * The archive can have a symbol table at the start. Ignore it. A symbol
770   * table has the file name '/'.
771   *
772   * The archive can also have the GNU extended file name table. This
773   * complicates the processing. If the object's file name starts with '/' the
774   * remainder of the file name is an offset into the extended file name
775   * table. To find the extended file name table we need to scan from start of
776   * the archive for a file name of '//'. Once found we remeber the table's
777   * start and can direct seek to file name location. In other words the scan
778   * only happens once.
779   *
780   * If the name had the offset encoded we go straight to that location.
781   */
782
783  if (obj->ooffset != 0)
784    scanning = false;
785  else
786  {
787    scanning = true;
788    obj->ooffset = RTEMS_RTL_AR_FHDR_BASE;
789  }
790
791  extended_file_names = 0;
792
793  while (obj->ooffset < fsize)
794  {
795    /*
796     * Clean up any existing data.
797     */
798    memset (header, 0, sizeof (header));
799
800    if (!rtems_rtl_seek_read (fd, obj->ooffset, RTEMS_RTL_AR_FHDR_SIZE, &header[0]))
801    {
802      rtems_rtl_set_error (errno, "seek/read archive file header");
803      obj->ooffset = 0;
804      obj->fsize = 0;
805      return false;
806    }
807
808    if ((header[RTEMS_RTL_AR_MAGIC] != 0x60) ||
809        (header[RTEMS_RTL_AR_MAGIC + 1] != 0x0a))
810    {
811      if (scanning)
812      {
813        rtems_rtl_set_error (EINVAL, "invalid archive file header");
814        obj->ooffset = 0;
815        obj->fsize = 0;
816        return false;
817      }
818
819      scanning = true;
820      obj->ooffset = RTEMS_RTL_AR_FHDR_BASE;
821      continue;
822    }
823
824    /*
825     * The archive header is always aligned to an even address.
826     */
827    obj->fsize = (rtems_rtl_scan_decimal (&header[RTEMS_RTL_AR_SIZE],
828                                          RTEMS_RTL_AR_SIZE_SIZE) + 1) & ~1;
829
830    /*
831     * Check for the GNU extensions.
832     */
833    if (header[0] == '/')
834    {
835      off_t extended_off;
836
837      switch (header[1])
838      {
839        case ' ':
840          /*
841           * Symbols table. Ignore the table.
842           */
843          break;
844        case '/':
845          /*
846           * Extended file names table. Remember.
847           */
848          extended_file_names = obj->ooffset + RTEMS_RTL_AR_FHDR_SIZE;
849          break;
850        case '0':
851        case '1':
852        case '2':
853        case '3':
854        case '4':
855        case '5':
856        case '6':
857        case '7':
858        case '8':
859        case '9':
860          /*
861           * Offset into the extended file name table. If we do not have the
862           * offset to the extended file name table find it.
863           */
864          extended_off =
865            rtems_rtl_scan_decimal (&header[1], RTEMS_RTL_AR_FNAME_SIZE);
866
867          if (extended_file_names == 0)
868          {
869            off_t off = obj->ooffset;
870            while (extended_file_names == 0)
871            {
872              off_t esize =
873                (rtems_rtl_scan_decimal (&header[RTEMS_RTL_AR_SIZE],
874                                         RTEMS_RTL_AR_SIZE_SIZE) + 1) & ~1;
875              off += esize + RTEMS_RTL_AR_FHDR_SIZE;
876
877              if (!rtems_rtl_seek_read (fd, off,
878                                        RTEMS_RTL_AR_FHDR_SIZE, &header[0]))
879              {
880                rtems_rtl_set_error (errno,
881                                     "seeking/reading archive ext file name header");
882                obj->ooffset = 0;
883                obj->fsize = 0;
884                return false;
885              }
886
887              if ((header[RTEMS_RTL_AR_MAGIC] != 0x60) ||
888                  (header[RTEMS_RTL_AR_MAGIC + 1] != 0x0a))
889              {
890                rtems_rtl_set_error (errno, "invalid archive file header");
891                obj->ooffset = 0;
892                obj->fsize = 0;
893                return false;
894              }
895
896              if ((header[0] == '/') && (header[1] == '/'))
897              {
898                extended_file_names = off + RTEMS_RTL_AR_FHDR_SIZE;
899                break;
900              }
901            }
902          }
903
904          if (extended_file_names)
905          {
906            /*
907             * We know the offset in the archive to the extended file. Read the
908             * name from the table and compare with the name we are after.
909             */
910#define RTEMS_RTL_MAX_FILE_SIZE (256)
911            char  name[RTEMS_RTL_MAX_FILE_SIZE];
912
913            if (!rtems_rtl_seek_read (fd, extended_file_names + extended_off,
914                                      RTEMS_RTL_MAX_FILE_SIZE, (uint8_t*) &name[0]))
915            {
916              rtems_rtl_set_error (errno,
917                                   "invalid archive ext file seek/read");
918              obj->ooffset = 0;
919              obj->fsize = 0;
920              return false;
921            }
922
923            if (rtems_rtl_match_name (obj, name))
924            {
925              obj->ooffset += RTEMS_RTL_AR_FHDR_SIZE;
926              return true;
927            }
928          }
929          break;
930        default:
931          /*
932           * Ignore the file because we do not know what it it.
933           */
934          break;
935      }
936    }
937    else
938    {
939      if (rtems_rtl_match_name (obj, (const char*) &header[RTEMS_RTL_AR_FNAME]))
940      {
941        obj->ooffset += RTEMS_RTL_AR_FHDR_SIZE;
942        return true;
943      }
944    }
945
946    obj->ooffset += obj->fsize + RTEMS_RTL_AR_FHDR_SIZE;
947  }
948
949  rtems_rtl_set_error (ENOENT, "object file not found");
950  obj->ooffset = 0;
951  obj->fsize = 0;
952  return false;
953}
954
955bool
956rtems_rtl_obj_file_load (rtems_rtl_obj_t* obj, int fd)
957{
958  int l;
959
960  for (l = 0; l < (sizeof (loaders) / sizeof (rtems_rtl_loader_table_t)); ++l)
961  {
962    if (loaders[l].check (obj, fd))
963      return loaders[l].load (obj, fd);
964  }
965
966  rtems_rtl_set_error (ENOENT, "no format loader found");
967  return false;
968}
969
970bool
971rtems_rtl_obj_load (rtems_rtl_obj_t* obj)
972{
973  int fd;
974
975  if (!rtems_rtl_obj_fname_valid (obj))
976  {
977    rtems_rtl_set_error (ENOMEM, "invalid object file name path");
978    return false;
979  }
980
981  fd = open (rtems_rtl_obj_fname (obj), O_RDONLY);
982  if (fd < 0)
983  {
984    rtems_rtl_set_error (ENOMEM, "opening for object file");
985    return false;
986  }
987
988  /*
989   * Find the object file in the archive if it is an archive that
990   * has been opened.
991   */
992  if (rtems_rtl_obj_aname_valid (obj))
993  {
994    if (!rtems_rtl_obj_archive_find (obj, fd))
995    {
996      rtems_rtl_obj_caches_flush ();
997      close (fd);
998      return false;
999    }
1000  }
1001
1002  /*
1003   * Call the format specific loader. Currently this is a call to the ELF
1004   * loader. This call could be changed to allow probes then calls if more than
1005   * one format is supported.
1006   */
1007  if (!rtems_rtl_obj_file_load (obj, fd))
1008  {
1009    rtems_rtl_obj_caches_flush ();
1010    close (fd);
1011    return false;
1012  }
1013
1014  if (!_rtld_linkmap_add (obj)) /* For GDB */
1015  {
1016    close (fd);
1017    return false;
1018  }
1019
1020  rtems_rtl_obj_caches_flush ();
1021
1022  close (fd);
1023
1024  return true;
1025}
1026
1027bool
1028rtems_rtl_obj_unload (rtems_rtl_obj_t* obj)
1029{
1030  _rtld_linkmap_delete(obj);
1031  rtems_rtl_symbol_obj_erase (obj);
1032  return rtems_rtl_obj_free (obj);
1033}
Note: See TracBrowser for help on using the repository browser.