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

5
Last change on this file since f59d435d was f59d435d, checked in by Chris Johns <chrisj@…>, on 04/12/18 at 07:46:49

libdl: Remove _t from all structures as this is reserved for the standards

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