source: rtems/cpukit/libdl/rtl-obj.c @ 89b4a5cc

5
Last change on this file since 89b4a5cc was 89b4a5cc, checked in by Pavel Pisa <pisa@…>, on 10/03/16 at 09:01:39

libdl/rtl-obj.c: synchronize cache should not depend on CPU_CACHE_LINE_BYTES.

Use of rtems_cache_get_maximal_line_size() is more descriptive
choice. The min/max data/instruction cache line size is not critical
there, value is used for optimization only to use single operation
for directly following sections.

  • Property mode set to 100644
File size: 29.9 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
561/**
562 * Cache synchronization after runtime object load (dlopen)
563 */
564typedef struct
565{
566  uint32_t mask;
567  void     *start_va;
568  void     *end_va;
569  size_t   cache_line_size;
570} rtems_rtl_obj_sect_sync_ctx_t;
571
572static bool
573rtems_rtl_obj_sect_sync_handler (rtems_chain_node* node, void* data)
574{
575  rtems_rtl_obj_sect_t*   sect = (rtems_rtl_obj_sect_t*) node;
576  rtems_rtl_obj_sect_sync_ctx_t* sync_ctx = data;
577  uintptr_t old_end;
578  uintptr_t new_start;
579
580  if ( !(sect->flags & sync_ctx->mask) || !sect->size)
581    return true;
582
583  if (sync_ctx->end_va == sync_ctx->start_va) {
584    sync_ctx->start_va = sect->base;
585  } else {
586    old_end = (uintptr_t)sync_ctx->end_va & ~(sync_ctx->cache_line_size - 1);
587    new_start = (uintptr_t)sect->base & ~(sync_ctx->cache_line_size - 1);
588    if ( (sect->base <  sync_ctx->start_va) ||
589         (new_start - old_end > sync_ctx->cache_line_size) ) {
590      rtems_cache_instruction_sync_after_code_change(sync_ctx->start_va,
591                             sync_ctx->end_va - sync_ctx->start_va + 1);
592      sync_ctx->start_va = sect->base;
593    }
594  }
595
596  sync_ctx->end_va = sect->base + sect->size;
597
598  return true;
599}
600
601void
602rtems_rtl_obj_synchronize_cache (rtems_rtl_obj_t*    obj)
603{
604  rtems_rtl_obj_sect_sync_ctx_t sync_ctx;
605
606  if (rtems_cache_get_instruction_line_size() == 0)
607    return;
608
609  sync_ctx.cache_line_size = rtems_cache_get_maximal_line_size();
610
611  sync_ctx.mask = RTEMS_RTL_OBJ_SECT_TEXT | RTEMS_RTL_OBJ_SECT_CONST |
612                  RTEMS_RTL_OBJ_SECT_DATA | RTEMS_RTL_OBJ_SECT_BSS |
613                  RTEMS_RTL_OBJ_SECT_EXEC;
614
615  sync_ctx.start_va = 0;
616  sync_ctx.end_va = sync_ctx.start_va;
617  rtems_rtl_chain_iterate (&obj->sections,
618                           rtems_rtl_obj_sect_sync_handler,
619                           &sync_ctx);
620
621  if (sync_ctx.end_va != sync_ctx.start_va) {
622    rtems_cache_instruction_sync_after_code_change(sync_ctx.start_va,
623                              sync_ctx.end_va - sync_ctx.start_va);
624  }
625}
626
627bool
628rtems_rtl_obj_load_symbols (rtems_rtl_obj_t*             obj,
629                            int                          fd,
630                            rtems_rtl_obj_sect_handler_t handler,
631                            void*                        data)
632{
633  uint32_t mask = RTEMS_RTL_OBJ_SECT_SYM;
634  return rtems_rtl_obj_section_handler (mask, obj, fd, handler, data);
635}
636
637static size_t
638rtems_rtl_obj_sections_loader (uint32_t                     mask,
639                               rtems_rtl_obj_t*             obj,
640                               int                          fd,
641                               uint8_t*                     base,
642                               rtems_rtl_obj_sect_handler_t handler,
643                               void*                        data)
644{
645  rtems_chain_control* sections = &obj->sections;
646  rtems_chain_node*    node = rtems_chain_first (sections);
647  size_t               base_offset = 0;
648  bool                 first = true;
649  while (!rtems_chain_is_tail (sections, node))
650  {
651    rtems_rtl_obj_sect_t* sect = (rtems_rtl_obj_sect_t*) node;
652
653    if ((sect->size != 0) && ((sect->flags & mask) != 0))
654    {
655      if (!first)
656        base_offset = rtems_rtl_sect_align (base_offset, sect->alignment);
657
658      sect->base = base + base_offset;
659
660      if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD_SECT))
661        printf ("rtl: loading: %s -> %8p (%zi)\n",
662                sect->name, sect->base, sect->size);
663
664      if ((sect->flags & RTEMS_RTL_OBJ_SECT_LOAD) == RTEMS_RTL_OBJ_SECT_LOAD)
665      {
666        if (!handler (obj, fd, sect, data))
667        {
668          sect->base = 0;
669          return false;
670        }
671      }
672      else if ((sect->flags & RTEMS_RTL_OBJ_SECT_ZERO) == RTEMS_RTL_OBJ_SECT_ZERO)
673      {
674        memset (base + base_offset, 0, sect->size);
675      }
676      else
677      {
678        sect->base = 0;
679        rtems_rtl_set_error (errno, "section has no load op");
680        return false;
681      }
682
683      base_offset += sect->size;
684      first = false;
685    }
686
687    node = rtems_chain_next (node);
688  }
689
690  return true;
691}
692
693bool
694rtems_rtl_obj_load_sections (rtems_rtl_obj_t*             obj,
695                             int                          fd,
696                             rtems_rtl_obj_sect_handler_t handler,
697                             void*                        data)
698{
699  size_t text_size;
700  size_t const_size;
701  size_t data_size;
702  size_t bss_size;
703
704  text_size  = rtems_rtl_obj_text_size (obj) + rtems_rtl_obj_const_alignment (obj);
705  const_size = rtems_rtl_obj_const_size (obj) + rtems_rtl_obj_data_alignment (obj);
706  data_size  = rtems_rtl_obj_data_size (obj) + rtems_rtl_obj_bss_alignment (obj);
707  bss_size   = rtems_rtl_obj_bss_size (obj);
708
709  /*
710   * Let the allocator manage the actual allocation. The user can use the
711   * standard heap or provide a specific allocator with memory protection.
712   */
713  if (!rtems_rtl_alloc_module_new (&obj->text_base, text_size,
714                                   &obj->const_base, const_size,
715                                   &obj->data_base, data_size,
716                                   &obj->bss_base, bss_size))
717  {
718    obj->exec_size = 0;
719    rtems_rtl_set_error (ENOMEM, "no memory to load obj");
720    return false;
721  }
722
723  obj->exec_size = text_size + const_size + data_size + bss_size;
724
725  if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD_SECT))
726  {
727    printf ("rtl: load sect: text  - b:%p s:%zi a:%" PRIu32 "\n",
728            obj->text_base, text_size, rtems_rtl_obj_text_alignment (obj));
729    printf ("rtl: load sect: const - b:%p s:%zi a:%" PRIu32 "\n",
730            obj->const_base, const_size, rtems_rtl_obj_const_alignment (obj));
731    printf ("rtl: load sect: data  - b:%p s:%zi a:%" PRIu32 "\n",
732            obj->data_base, data_size, rtems_rtl_obj_data_alignment (obj));
733    printf ("rtl: load sect: bss   - b:%p s:%zi a:%" PRIu32 "\n",
734            obj->bss_base, bss_size, rtems_rtl_obj_bss_alignment (obj));
735  }
736
737  /*
738   * Load all text then data then bss sections in seperate operations so each
739   * type of section is grouped together.
740   */
741  if (!rtems_rtl_obj_sections_loader (RTEMS_RTL_OBJ_SECT_TEXT,
742                                      obj, fd, obj->text_base, handler, data) ||
743      !rtems_rtl_obj_sections_loader (RTEMS_RTL_OBJ_SECT_CONST,
744                                      obj, fd, obj->const_base, handler, data) ||
745      !rtems_rtl_obj_sections_loader (RTEMS_RTL_OBJ_SECT_DATA,
746                                      obj, fd, obj->data_base, handler, data) ||
747      !rtems_rtl_obj_sections_loader (RTEMS_RTL_OBJ_SECT_BSS,
748                                      obj, fd, obj->bss_base, handler, data))
749  {
750    rtems_rtl_alloc_module_del (&obj->text_base, &obj->const_base,
751                                &obj->data_base, &obj->bss_base);
752    obj->exec_size = 0;
753    return false;
754  }
755
756  return true;
757}
758
759static void
760rtems_rtl_obj_run_cdtors (rtems_rtl_obj_t* obj, uint32_t mask)
761{
762  rtems_chain_node* node = rtems_chain_first (&obj->sections);
763  while (!rtems_chain_is_tail (&obj->sections, node))
764  {
765    rtems_rtl_obj_sect_t* sect = (rtems_rtl_obj_sect_t*) node;
766    if ((sect->flags & mask) == mask)
767    {
768      rtems_rtl_cdtor_t* handler;
769      size_t             handlers = sect->size / sizeof (rtems_rtl_cdtor_t);
770      int                c;
771      for (c = 0, handler = sect->base; c < handlers; ++c)
772        if (*handler)
773          (*handler) ();
774    }
775    node = rtems_chain_next (node);
776  }
777}
778
779void
780rtems_rtl_obj_run_ctors (rtems_rtl_obj_t* obj)
781{
782  return rtems_rtl_obj_run_cdtors (obj, RTEMS_RTL_OBJ_SECT_CTOR);
783}
784
785void
786rtems_rtl_obj_run_dtors (rtems_rtl_obj_t* obj)
787{
788  return rtems_rtl_obj_run_cdtors (obj, RTEMS_RTL_OBJ_SECT_DTOR);
789}
790
791/**
792 * Find a module in an archive returning the offset in the archive in the
793 * object descriptor.
794 */
795static bool
796rtems_rtl_obj_archive_find (rtems_rtl_obj_t* obj, int fd)
797{
798#define RTEMS_RTL_AR_IDENT      "!<arch>\n"
799#define RTEMS_RTL_AR_IDENT_SIZE (sizeof (RTEMS_RTL_AR_IDENT) - 1)
800#define RTEMS_RTL_AR_FHDR_BASE  RTEMS_RTL_AR_IDENT_SIZE
801#define RTEMS_RTL_AR_FNAME      (0)
802#define RTEMS_RTL_AR_FNAME_SIZE (16)
803#define RTEMS_RTL_AR_SIZE       (48)
804#define RTEMS_RTL_AR_SIZE_SIZE  (10)
805#define RTEMS_RTL_AR_MAGIC      (58)
806#define RTEMS_RTL_AR_MAGIC_SIZE (2)
807#define RTEMS_RTL_AR_FHDR_SIZE  (60)
808
809  size_t  fsize = obj->fsize;
810  off_t   extended_file_names;
811  uint8_t header[RTEMS_RTL_AR_FHDR_SIZE];
812  bool    scanning;
813
814  if (read (fd, &header[0], RTEMS_RTL_AR_IDENT_SIZE) !=  RTEMS_RTL_AR_IDENT_SIZE)
815  {
816    rtems_rtl_set_error (errno, "reading archive identifer");
817    return false;
818  }
819
820  if (memcmp (header, RTEMS_RTL_AR_IDENT, RTEMS_RTL_AR_IDENT_SIZE) != 0)
821  {
822    rtems_rtl_set_error (EINVAL, "invalid archive identifer");
823    return false;
824  }
825
826  /*
827   * Seek to the current offset in the archive and if we have a valid archive
828   * file header present check the file name for a match with the oname field
829   * of the object descriptor. If the archive header is not valid and it is the
830   * first pass reset the offset and start the search again in case the offset
831   * provided is not valid any more.
832   *
833   * The archive can have a symbol table at the start. Ignore it. A symbol
834   * table has the file name '/'.
835   *
836   * The archive can also have the GNU extended file name table. This
837   * complicates the processing. If the object's file name starts with '/' the
838   * remainder of the file name is an offset into the extended file name
839   * table. To find the extended file name table we need to scan from start of
840   * the archive for a file name of '//'. Once found we remeber the table's
841   * start and can direct seek to file name location. In other words the scan
842   * only happens once.
843   *
844   * If the name had the offset encoded we go straight to that location.
845   */
846
847  if (obj->ooffset != 0)
848    scanning = false;
849  else
850  {
851    scanning = true;
852    obj->ooffset = RTEMS_RTL_AR_FHDR_BASE;
853  }
854
855  extended_file_names = 0;
856
857  while (obj->ooffset < fsize)
858  {
859    /*
860     * Clean up any existing data.
861     */
862    memset (header, 0, sizeof (header));
863
864    if (!rtems_rtl_seek_read (fd, obj->ooffset, RTEMS_RTL_AR_FHDR_SIZE, &header[0]))
865    {
866      rtems_rtl_set_error (errno, "seek/read archive file header");
867      obj->ooffset = 0;
868      obj->fsize = 0;
869      return false;
870    }
871
872    if ((header[RTEMS_RTL_AR_MAGIC] != 0x60) ||
873        (header[RTEMS_RTL_AR_MAGIC + 1] != 0x0a))
874    {
875      if (scanning)
876      {
877        rtems_rtl_set_error (EINVAL, "invalid archive file header");
878        obj->ooffset = 0;
879        obj->fsize = 0;
880        return false;
881      }
882
883      scanning = true;
884      obj->ooffset = RTEMS_RTL_AR_FHDR_BASE;
885      continue;
886    }
887
888    /*
889     * The archive header is always aligned to an even address.
890     */
891    obj->fsize = (rtems_rtl_scan_decimal (&header[RTEMS_RTL_AR_SIZE],
892                                          RTEMS_RTL_AR_SIZE_SIZE) + 1) & ~1;
893
894    /*
895     * Check for the GNU extensions.
896     */
897    if (header[0] == '/')
898    {
899      off_t extended_off;
900
901      switch (header[1])
902      {
903        case ' ':
904          /*
905           * Symbols table. Ignore the table.
906           */
907          break;
908        case '/':
909          /*
910           * Extended file names table. Remember.
911           */
912          extended_file_names = obj->ooffset + RTEMS_RTL_AR_FHDR_SIZE;
913          break;
914        case '0':
915        case '1':
916        case '2':
917        case '3':
918        case '4':
919        case '5':
920        case '6':
921        case '7':
922        case '8':
923        case '9':
924          /*
925           * Offset into the extended file name table. If we do not have the
926           * offset to the extended file name table find it.
927           */
928          extended_off =
929            rtems_rtl_scan_decimal (&header[1], RTEMS_RTL_AR_FNAME_SIZE);
930
931          if (extended_file_names == 0)
932          {
933            off_t off = obj->ooffset;
934            while (extended_file_names == 0)
935            {
936              off_t esize =
937                (rtems_rtl_scan_decimal (&header[RTEMS_RTL_AR_SIZE],
938                                         RTEMS_RTL_AR_SIZE_SIZE) + 1) & ~1;
939              off += esize + RTEMS_RTL_AR_FHDR_SIZE;
940
941              if (!rtems_rtl_seek_read (fd, off,
942                                        RTEMS_RTL_AR_FHDR_SIZE, &header[0]))
943              {
944                rtems_rtl_set_error (errno,
945                                     "seeking/reading archive ext file name header");
946                obj->ooffset = 0;
947                obj->fsize = 0;
948                return false;
949              }
950
951              if ((header[RTEMS_RTL_AR_MAGIC] != 0x60) ||
952                  (header[RTEMS_RTL_AR_MAGIC + 1] != 0x0a))
953              {
954                rtems_rtl_set_error (errno, "invalid archive file header");
955                obj->ooffset = 0;
956                obj->fsize = 0;
957                return false;
958              }
959
960              if ((header[0] == '/') && (header[1] == '/'))
961              {
962                extended_file_names = off + RTEMS_RTL_AR_FHDR_SIZE;
963                break;
964              }
965            }
966          }
967
968          if (extended_file_names)
969          {
970            /*
971             * We know the offset in the archive to the extended file. Read the
972             * name from the table and compare with the name we are after.
973             */
974#define RTEMS_RTL_MAX_FILE_SIZE (256)
975            char  name[RTEMS_RTL_MAX_FILE_SIZE];
976
977            if (!rtems_rtl_seek_read (fd, extended_file_names + extended_off,
978                                      RTEMS_RTL_MAX_FILE_SIZE, (uint8_t*) &name[0]))
979            {
980              rtems_rtl_set_error (errno,
981                                   "invalid archive ext file seek/read");
982              obj->ooffset = 0;
983              obj->fsize = 0;
984              return false;
985            }
986
987            if (rtems_rtl_match_name (obj, name))
988            {
989              obj->ooffset += RTEMS_RTL_AR_FHDR_SIZE;
990              return true;
991            }
992          }
993          break;
994        default:
995          /*
996           * Ignore the file because we do not know what it it.
997           */
998          break;
999      }
1000    }
1001    else
1002    {
1003      if (rtems_rtl_match_name (obj, (const char*) &header[RTEMS_RTL_AR_FNAME]))
1004      {
1005        obj->ooffset += RTEMS_RTL_AR_FHDR_SIZE;
1006        return true;
1007      }
1008    }
1009
1010    obj->ooffset += obj->fsize + RTEMS_RTL_AR_FHDR_SIZE;
1011  }
1012
1013  rtems_rtl_set_error (ENOENT, "object file not found");
1014  obj->ooffset = 0;
1015  obj->fsize = 0;
1016  return false;
1017}
1018
1019bool
1020rtems_rtl_obj_file_load (rtems_rtl_obj_t* obj, int fd)
1021{
1022  int l;
1023
1024  for (l = 0; l < (sizeof (loaders) / sizeof (rtems_rtl_loader_table_t)); ++l)
1025  {
1026    if (loaders[l].check (obj, fd))
1027      return loaders[l].load (obj, fd);
1028  }
1029
1030  rtems_rtl_set_error (ENOENT, "no format loader found");
1031  return false;
1032}
1033
1034bool
1035rtems_rtl_obj_load (rtems_rtl_obj_t* obj)
1036{
1037  int fd;
1038
1039  if (!rtems_rtl_obj_fname_valid (obj))
1040  {
1041    rtems_rtl_set_error (ENOMEM, "invalid object file name path");
1042    return false;
1043  }
1044
1045  fd = open (rtems_rtl_obj_fname (obj), O_RDONLY);
1046  if (fd < 0)
1047  {
1048    rtems_rtl_set_error (ENOMEM, "opening for object file");
1049    return false;
1050  }
1051
1052  /*
1053   * Find the object file in the archive if it is an archive that
1054   * has been opened.
1055   */
1056  if (rtems_rtl_obj_aname_valid (obj))
1057  {
1058    if (!rtems_rtl_obj_archive_find (obj, fd))
1059    {
1060      rtems_rtl_obj_caches_flush ();
1061      close (fd);
1062      return false;
1063    }
1064  }
1065
1066  /*
1067   * Call the format specific loader. Currently this is a call to the ELF
1068   * loader. This call could be changed to allow probes then calls if more than
1069   * one format is supported.
1070   */
1071  if (!rtems_rtl_obj_file_load (obj, fd))
1072  {
1073    rtems_rtl_obj_caches_flush ();
1074    close (fd);
1075    return false;
1076  }
1077
1078  if (!_rtld_linkmap_add (obj)) /* For GDB */
1079  {
1080    close (fd);
1081    return false;
1082  }
1083
1084  rtems_rtl_obj_caches_flush ();
1085
1086  close (fd);
1087
1088  return true;
1089}
1090
1091bool
1092rtems_rtl_obj_unload (rtems_rtl_obj_t* obj)
1093{
1094  _rtld_linkmap_delete(obj);
1095  rtems_rtl_symbol_obj_erase (obj);
1096  return rtems_rtl_obj_free (obj);
1097}
Note: See TracBrowser for help on using the repository browser.