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

Last change on this file since 4408603 was 89c59be, checked in by Chris Johns <chrisj@…>, on Dec 17, 2018 at 5:36:48 AM

libdl: Add symbol searching and loading from archives.

  • Load archive symbol tables to support searching of archives for symbols.
  • Search archive symbols and load the object file that contains the symbol.
  • Search the global and archives until all remaining unresolved symbols are not found. Group the loaded object files in the pending queue.
  • Run the object file and loaded dependents as a group before adding to the main object list.
  • Remove orphaned object files after references are removed.

Updates #3686

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