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

Last change on this file since 4408603 was 4408603, checked in by Chris Johns <chrisj@…>, on Jan 9, 2019 at 11:14:11 AM

libdl: Fix the support for constructors and desctructors.

  • Fix the handling of pending objects.
  • Add a constructor flags in objects to track then being called.

Closes #2921

  • Property mode set to 100644
File size: 19.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 rtems_rtld
12 *
13 * @brief RTEMS Run-Time Link Editor
14 *
15 * This is the RTL implementation.
16 */
17
18#if HAVE_CONFIG_H
19#include "config.h"
20#endif
21
22#include <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 <rtems/rtl/rtl-allocator.h>
30#include <rtems/rtl/rtl-trace.h>
31#include "rtl-chain-iterator.h"
32#include "rtl-error.h"
33#include "rtl-string.h"
34
35/**
36 * Symbol table cache size. They can be big so the cache needs space to work.
37 */
38#define RTEMS_RTL_ELF_SYMBOL_CACHE (2048)
39
40/**
41 * String table cache size.
42 */
43#define RTEMS_RTL_ELF_STRING_CACHE (2048)
44
45/**
46 * Relocations table cache size.
47 */
48#define RTEMS_RTL_ELF_RELOC_CACHE (2048)
49
50/**
51 * Decompression output buffer.
52 */
53#define RTEMS_RTL_COMP_OUTPUT (2048)
54
55/**
56 * Static RTL data is returned to the user when the linker is locked.
57 */
58static rtems_rtl_data* rtl;
59static bool            rtl_data_init;
60
61/**
62 * Define a default base global symbol loader function that is weak
63 * so a real table can be linked in when the user wants one.
64 */
65void rtems_rtl_base_global_syms_init (void) __attribute__ ((weak));
66void
67rtems_rtl_base_global_syms_init (void)
68{
69  /*
70   * Do nothing.
71   */
72}
73
74static bool
75rtems_rtl_data_init (void)
76{
77  /*
78   * Lock the RTL. We only create a lock if a call is made. First we test if a
79   * lock is present. If one is present we lock it. If not the libio lock is
80   * locked and we then test the lock again. If not present we create the lock
81   * then release libio lock.
82   */
83  if (!rtl)
84  {
85    rtems_libio_lock ();
86
87    if (!rtl)
88    {
89      /*
90       * We cannot set an error in this code because there is no RTL data to
91       * hold it.
92       */
93
94      if (rtl_data_init)
95      {
96        rtems_libio_unlock ();
97        return false;
98      }
99
100      rtl_data_init = true;
101
102      /*
103       * Always in the heap.
104       */
105      rtl = malloc (sizeof (rtems_rtl_data));
106      if (!rtl)
107      {
108        rtems_libio_unlock ();
109        errno = ENOMEM;
110        return false;
111      }
112
113      *rtl = (rtems_rtl_data) { 0 };
114
115      /*
116       * The initialise the allocator data.
117       */
118      rtems_rtl_alloc_initialise (&rtl->allocator);
119
120      /*
121       * Create the RTL lock.
122       */
123      rtems_recursive_mutex_init (&rtl->lock, "Run-Time Linker");
124      rtems_recursive_mutex_lock (&rtl->lock);
125
126      /*
127       * Initialise the objects and pending list.
128       */
129      rtems_chain_initialize_empty (&rtl->objects);
130      rtems_chain_initialize_empty (&rtl->pending);
131
132      /*
133       * Open the global symbol table.
134       */
135      if (!rtems_rtl_symbol_table_open (&rtl->globals,
136                                        RTEMS_RTL_SYMS_GLOBAL_BUCKETS))
137      {
138        rtems_recursive_mutex_destroy (&rtl->lock);
139        free (rtl);
140        rtems_libio_unlock ();
141        return false;
142      }
143
144      /*
145       * Open the archives.
146       */
147      rtems_rtl_archives_open (&rtl->archives, "/etc/rtl-libs.conf");
148
149      /*
150       * Open the unresolved table.
151       */
152      if (!rtems_rtl_unresolved_table_open (&rtl->unresolved,
153                                            RTEMS_RTL_UNRESOLVED_BLOCK_SIZE))
154      {
155        rtems_rtl_symbol_table_close (&rtl->globals);
156        rtems_recursive_mutex_destroy (&rtl->lock);
157        free (rtl);
158        rtems_libio_unlock ();
159        return false;
160      }
161
162      if (!rtems_rtl_obj_cache_open (&rtl->symbols,
163                                     RTEMS_RTL_ELF_SYMBOL_CACHE))
164      {
165        rtems_rtl_symbol_table_close (&rtl->globals);
166        rtems_rtl_unresolved_table_close (&rtl->unresolved);
167        rtems_recursive_mutex_destroy (&rtl->lock);
168        free (rtl);
169        rtems_libio_unlock ();
170        return false;
171      }
172
173      if (!rtems_rtl_obj_cache_open (&rtl->strings,
174                                     RTEMS_RTL_ELF_STRING_CACHE))
175      {
176        rtems_rtl_obj_cache_close (&rtl->symbols);
177        rtems_rtl_unresolved_table_close (&rtl->unresolved);
178        rtems_rtl_symbol_table_close (&rtl->globals);
179        rtems_recursive_mutex_destroy (&rtl->lock);
180        free (rtl);
181        rtems_libio_unlock ();
182        return false;
183      }
184
185      if (!rtems_rtl_obj_cache_open (&rtl->relocs,
186                                     RTEMS_RTL_ELF_RELOC_CACHE))
187      {
188        rtems_rtl_obj_cache_close (&rtl->strings);
189        rtems_rtl_obj_cache_close (&rtl->symbols);
190        rtems_rtl_unresolved_table_close (&rtl->unresolved);
191        rtems_rtl_symbol_table_close (&rtl->globals);
192        rtems_recursive_mutex_destroy (&rtl->lock);
193        free (rtl);
194        rtems_libio_unlock ();
195        return false;
196      }
197
198      if (!rtems_rtl_obj_comp_open (&rtl->decomp,
199                                    RTEMS_RTL_COMP_OUTPUT))
200      {
201        rtems_rtl_obj_cache_close (&rtl->relocs);
202        rtems_rtl_obj_cache_close (&rtl->strings);
203        rtems_rtl_obj_cache_close (&rtl->symbols);
204        rtems_rtl_unresolved_table_close (&rtl->unresolved);
205        rtems_rtl_symbol_table_close (&rtl->globals);
206        rtems_recursive_mutex_destroy (&rtl->lock);
207        free (rtl);
208        rtems_libio_unlock ();
209        return false;
210      }
211
212      rtl->base = rtems_rtl_obj_alloc ();
213      if (!rtl->base)
214      {
215        rtems_rtl_obj_comp_close (&rtl->decomp);
216        rtems_rtl_obj_cache_close (&rtl->relocs);
217        rtems_rtl_obj_cache_close (&rtl->strings);
218        rtems_rtl_obj_cache_close (&rtl->symbols);
219        rtems_rtl_unresolved_table_close (&rtl->unresolved);
220        rtems_rtl_symbol_table_close (&rtl->globals);
221        rtems_recursive_mutex_destroy (&rtl->lock);
222        free (rtl);
223        rtems_libio_unlock ();
224        return false;
225      }
226
227      /*
228       * Need to malloc the memory so the free does not complain.
229       */
230      rtl->base->oname = rtems_rtl_strdup ("rtems-kernel");
231
232      /*
233       * Lock the base image and flag it as the base image.
234       */
235      rtl->base->flags |= RTEMS_RTL_OBJ_LOCKED | RTEMS_RTL_OBJ_BASE;
236
237      rtems_chain_append (&rtl->objects, &rtl->base->link);
238    }
239
240    rtems_libio_unlock ();
241
242    rtems_rtl_path_append (".");
243
244    rtems_rtl_base_global_syms_init ();
245
246    rtems_rtl_unlock ();
247  }
248  return true;
249}
250
251rtems_rtl_data*
252rtems_rtl_data_unprotected (void)
253{
254  return rtl;
255}
256
257rtems_rtl_symbols*
258rtems_rtl_global_symbols (void)
259{
260  if (!rtl)
261  {
262    rtems_rtl_set_error (ENOENT, "no rtl");
263    return NULL;
264  }
265  return &rtl->globals;
266}
267
268rtems_chain_control*
269rtems_rtl_objects_unprotected (void)
270{
271  if (!rtl)
272  {
273    rtems_rtl_set_error (ENOENT, "no rtl");
274    return NULL;
275  }
276  return &rtl->objects;
277}
278
279rtems_chain_control*
280rtems_rtl_pending_unprotected (void)
281{
282  if (!rtl)
283  {
284    rtems_rtl_set_error (ENOENT, "no rtl");
285    return NULL;
286  }
287  return &rtl->pending;
288}
289
290rtems_rtl_unresolved*
291rtems_rtl_unresolved_unprotected (void)
292{
293  if (!rtl)
294  {
295    rtems_rtl_set_error (ENOENT, "no rtl");
296    return NULL;
297  }
298  return &rtl->unresolved;
299}
300
301rtems_rtl_archives*
302rtems_rtl_archives_unprotected (void)
303{
304  if (!rtl)
305  {
306    rtems_rtl_set_error (ENOENT, "no rtl");
307    return NULL;
308  }
309  return &rtl->archives;
310}
311
312void
313rtems_rtl_obj_caches (rtems_rtl_obj_cache** symbols,
314                      rtems_rtl_obj_cache** strings,
315                      rtems_rtl_obj_cache** relocs)
316{
317  if (!rtl)
318  {
319    if (symbols)
320       *symbols = NULL;
321    if (strings)
322      *strings = NULL;
323    if (relocs)
324      *relocs = NULL;
325  }
326  else
327  {
328    if (symbols)
329      *symbols = &rtl->symbols;
330    if (strings)
331      *strings = &rtl->strings;
332    if (relocs)
333      *relocs = &rtl->relocs;
334  }
335}
336
337void
338rtems_rtl_obj_caches_flush (void)
339{
340  if (rtl)
341  {
342    rtems_rtl_obj_cache_flush (&rtl->symbols);
343    rtems_rtl_obj_cache_flush (&rtl->strings);
344    rtems_rtl_obj_cache_flush (&rtl->relocs);
345  }
346}
347
348void
349rtems_rtl_obj_decompress (rtems_rtl_obj_comp** decomp,
350                          rtems_rtl_obj_cache* cache,
351                          int                  fd,
352                          int                  compression,
353                          off_t                offset)
354{
355  if (!rtl)
356  {
357    *decomp = NULL;
358  }
359  else
360  {
361    *decomp = &rtl->decomp;
362    rtems_rtl_obj_comp_set (*decomp, cache, fd, compression, offset);
363  }
364}
365
366typedef struct rtems_rtl_obj_flags_data
367{
368  uint32_t clear;   /**< Flags to clear, do not invert. */
369  uint32_t set;     /**< Flags to set, applied after clearing. */
370} rtems_rtl_obj_flags_data;
371
372static bool
373rtems_rtl_obj_flags_iterator (rtems_chain_node* node, void* data)
374{
375  rtems_rtl_obj* obj              = (rtems_rtl_obj*) node;
376  rtems_rtl_obj_flags_data* flags = (rtems_rtl_obj_flags_data*) data;
377  if (flags->clear != 0)
378    obj->flags &= ~flags->clear;
379  if (flags->set != 0)
380    obj->flags |= flags->set;
381  return true;
382}
383
384void
385rtems_rtl_obj_update_flags (uint32_t clear, uint32_t set)
386{
387  rtems_rtl_obj_flags_data flags = {
388    .clear = clear,
389    .set   = set
390  };
391  rtems_rtl_chain_iterate (&rtl->objects,
392                           rtems_rtl_obj_flags_iterator,
393                           &flags);
394}
395
396rtems_rtl_data*
397rtems_rtl_lock (void)
398{
399  if (!rtems_rtl_data_init ())
400    return NULL;
401
402  rtems_recursive_mutex_lock (&rtl->lock);
403
404  return rtl;
405}
406
407void
408rtems_rtl_unlock (void)
409{
410  rtems_recursive_mutex_unlock (&rtl->lock);
411}
412
413rtems_rtl_obj*
414rtems_rtl_check_handle (void* handle)
415{
416  rtems_rtl_obj*    obj;
417  rtems_chain_node* node;
418
419  obj = handle;
420  node = rtems_chain_first (&rtl->objects);
421
422  while (!rtems_chain_is_tail (&rtl->objects, node))
423  {
424    rtems_rtl_obj* check = (rtems_rtl_obj*) node;
425    if (check == obj)
426      return obj;
427    node = rtems_chain_next (node);
428  }
429
430  return NULL;
431}
432
433rtems_rtl_obj*
434rtems_rtl_find_obj (const char* name)
435{
436  rtems_chain_node* node;
437  rtems_rtl_obj*    found = NULL;
438  const char*       aname = NULL;
439  const char*       oname = NULL;
440  off_t             ooffset;
441
442  if (!rtems_rtl_parse_name (name, &aname, &oname, &ooffset))
443    return NULL;
444
445  node = rtems_chain_first (&rtl->objects);
446
447  while (!rtems_chain_is_tail (&rtl->objects, node))
448  {
449    rtems_rtl_obj* obj = (rtems_rtl_obj*) node;
450    if ((aname == NULL && strcmp (obj->oname, oname) == 0) ||
451        (aname != NULL &&
452         strcmp (obj->aname, aname) == 0 && strcmp (obj->oname, oname) == 0))
453    {
454      found = obj;
455      break;
456    }
457    node = rtems_chain_next (node);
458  }
459
460  if (aname != NULL)
461    rtems_rtl_alloc_del(RTEMS_RTL_ALLOC_OBJECT, (void*) aname);
462
463  if (oname != NULL)
464    rtems_rtl_alloc_del(RTEMS_RTL_ALLOC_OBJECT, (void*) oname);
465
466  return found;
467}
468
469rtems_rtl_obj*
470rtems_rtl_find_obj_with_symbol (const rtems_rtl_obj_sym* sym)
471{
472  rtems_chain_node* node = rtems_chain_first (&rtl->objects);
473  while (!rtems_chain_is_tail (&rtl->objects, node))
474  {
475    rtems_rtl_obj* obj = (rtems_rtl_obj*) node;
476    if (rtems_rtl_obj_has_symbol (obj, sym))
477      return obj;
478    node = rtems_chain_next (node);
479  }
480  node = rtems_chain_first (&rtl->pending);
481  while (!rtems_chain_is_tail (&rtl->pending, node))
482  {
483    rtems_rtl_obj* obj = (rtems_rtl_obj*) node;
484    if (rtems_rtl_obj_has_symbol (obj, sym))
485      return obj;
486    node = rtems_chain_next (node);
487  }
488  return NULL;
489}
490
491rtems_rtl_obj*
492rtems_rtl_load_object (const char* name, int mode)
493{
494  rtems_rtl_obj* obj;
495
496  if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD))
497    printf ("rtl: loading '%s'\n", name);
498
499  /*
500   * See if the object module has already been loaded.
501   */
502  obj = rtems_rtl_find_obj (name);
503  if (!obj)
504  {
505    /*
506     * Allocate a new object file descriptor and attempt to load it.
507     */
508    obj = rtems_rtl_obj_alloc ();
509    if (obj == NULL)
510    {
511      rtems_rtl_set_error (ENOMEM, "no memory for object descriptor");
512      return NULL;
513    }
514
515    rtems_chain_append (&rtl->pending, &obj->link);
516
517    /*
518     * Find the file in the file system using the search path. The fname field
519     * will point to a valid file name if found.
520     */
521    if (!rtems_rtl_obj_find_file (obj, name))
522    {
523      rtems_rtl_obj_free (obj);
524      rtems_rtl_obj_caches_flush ();
525      return NULL;
526    }
527
528    if (!rtems_rtl_obj_load (obj))
529    {
530      rtems_chain_extract (&obj->link);
531      rtems_rtl_obj_free (obj);
532      rtems_rtl_obj_caches_flush ();
533      return NULL;
534    }
535
536    /*
537     * If there are unresolved externals remove from the pending queue and place
538     * on the objects list until the symbols are resolved.
539     */
540    if (obj->unresolved != 0)
541    {
542      rtems_chain_extract (&obj->link);
543      rtems_chain_append (&rtl->objects, &obj->link);
544    }
545
546    rtems_rtl_obj_caches_flush ();
547  }
548
549  /*
550   * Increase the number of users.
551   */
552  ++obj->users;
553
554  return obj;
555}
556
557rtems_rtl_obj*
558rtems_rtl_load (const char* name, int mode)
559{
560  rtems_rtl_obj* obj;
561
562  /*
563   * Refesh the archives.
564   */
565  rtems_rtl_archives_refresh (&rtl->archives);
566
567  /*
568   * Collect the loaded object files.
569   */
570  rtems_chain_initialize_empty (&rtl->pending);
571
572  obj = rtems_rtl_load_object (name, mode);
573  if (obj != NULL)
574  {
575    rtems_chain_node* node;
576
577    rtems_rtl_unresolved_resolve ();
578
579    /*
580     * Iterator over the pending list of object files that have been loaded.
581     */
582    node = rtems_chain_first (&rtl->pending);
583    while (!rtems_chain_is_tail (&rtl->pending, node))
584    {
585      rtems_rtl_obj* pobj = (rtems_rtl_obj*) node;
586
587      /*
588       * Move to the next pending object file and place this object file on the
589       * RTL's objects list.
590       */
591      node = rtems_chain_next (&pobj->link);
592      rtems_chain_extract (&pobj->link);
593      rtems_chain_append (&rtl->objects, &pobj->link);
594
595      /*
596       * Make sure the object file and cache is synchronized.
597       */
598      rtems_rtl_obj_synchronize_cache (pobj);
599
600      /*
601       * Run any local constructors if they have not been run. Unlock the linker
602       * to avoid any dead locks if the object file needs to load files or
603       * update the symbol table. We also do not want a constructor to unload
604       * this object file.
605       */
606      if ((pobj->flags & RTEMS_RTL_OBJ_CTOR_RUN) == 0)
607      {
608        pobj->flags |= RTEMS_RTL_OBJ_LOCKED | RTEMS_RTL_OBJ_CTOR_RUN;
609        rtems_rtl_unlock ();
610        rtems_rtl_obj_run_ctors (pobj);
611        rtems_rtl_lock ();
612        pobj->flags &= ~RTEMS_RTL_OBJ_LOCKED;
613      }
614    }
615  }
616
617  return obj;
618}
619
620bool
621rtems_rtl_unload_object (rtems_rtl_obj* obj)
622{
623  if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNLOAD))
624    printf ("rtl: unload object '%s'\n", rtems_rtl_obj_fname (obj));
625
626  /*
627   * If the object is locked it cannot be unloaded and the unload fails.
628   */
629  if ((obj->flags & RTEMS_RTL_OBJ_LOCKED) == RTEMS_RTL_OBJ_LOCKED)
630  {
631    rtems_rtl_set_error (EINVAL, "object file is locked");
632    return false;
633  }
634
635  /*
636   * The object file cannot be unloaded if it is referenced.
637   */
638  if (rtems_rtl_obj_get_reference (obj) > 0)
639  {
640    rtems_rtl_set_error (EINVAL, "object file has references to it");
641    return false;
642  }
643
644  /*
645   * Check the number of users in a safe manner. If this is the last user unload
646   * the object file from memory.
647   */
648  if (obj->users > 0)
649    --obj->users;
650
651  return true;
652}
653
654bool
655rtems_rtl_unload (rtems_rtl_obj* obj)
656{
657  bool ok = rtems_rtl_unload_object (obj);
658  if (ok && obj->users == 0)
659  {
660    rtems_chain_control unloading;
661    rtems_chain_node*   node;
662    bool                orphaned_found = true;
663    int                 loop = 0;
664
665    /*
666     * Remove the orphaned object files from the objects list. The unloading is
667     * private so any changes in any desctructors will not effect the list as it
668     * is being iterated over.
669     *
670     * To avoid maintaining a complex tree loop while oprhans are still be found.
671     */
672
673    rtems_chain_initialize_empty (&unloading);
674
675    while (orphaned_found)
676    {
677      orphaned_found = false;
678      ++loop;
679      node = rtems_chain_first (&rtl->objects);
680      while (!rtems_chain_is_tail (&rtl->objects, node))
681      {
682        rtems_chain_node* next_node = rtems_chain_next (node);
683        rtems_rtl_obj* uobj = (rtems_rtl_obj*) node;
684        if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNLOAD))
685          printf ("rtl: unload object: %3i: %9s: %s\n",
686                  loop,
687                  rtems_rtl_obj_orphaned (uobj) ? "orphaned" : "inuse",
688                  rtems_rtl_obj_oname (uobj));
689        if (rtems_rtl_obj_orphaned (uobj))
690        {
691          orphaned_found = true;
692          rtems_rtl_obj_remove_dependencies (uobj);
693          rtems_chain_extract (&uobj->link);
694          rtems_chain_append (&unloading, &uobj->link);
695          uobj->flags |= RTEMS_RTL_OBJ_LOCKED;
696        }
697        node = next_node;
698      }
699    }
700
701    /*
702     * Call the desctructors unlocked. An RTL call will not deadlock.
703     */
704    rtems_rtl_unlock ();
705
706    node = rtems_chain_first (&unloading);
707    while (!rtems_chain_is_tail (&unloading, node))
708    {
709      rtems_rtl_obj* uobj = (rtems_rtl_obj*) node;
710      if ((uobj->flags & RTEMS_RTL_OBJ_CTOR_RUN) != 0)
711      {
712        rtems_rtl_obj_run_dtors (uobj);
713        uobj->flags &= ~RTEMS_RTL_OBJ_CTOR_RUN;
714      }
715      node = rtems_chain_next (node);
716    }
717
718    rtems_rtl_lock ();
719
720    /*
721     * Unload the object files.
722     */
723    node = rtems_chain_first (&unloading);
724    while (!rtems_chain_is_tail (&unloading, node))
725    {
726      rtems_chain_node* next_node = rtems_chain_next (node);
727      rtems_rtl_obj*    uobj = (rtems_rtl_obj*) node;
728      if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNLOAD))
729        printf ("rtl: unloading '%s'\n", rtems_rtl_obj_oname (uobj));
730      uobj->flags &= ~RTEMS_RTL_OBJ_LOCKED;
731      if (!rtems_rtl_obj_unload (uobj))
732        ok = false;
733      rtems_rtl_obj_free (uobj);
734      rtems_rtl_obj_caches_flush ();
735      node = next_node;
736    }
737  }
738  return ok;
739}
740
741static bool
742rtems_rtl_path_update (bool prepend, const char* path)
743{
744  char*       paths;
745  const char* src = NULL;
746  char*       dst;
747  int         len;
748
749  if (!rtems_rtl_lock ())
750    return false;
751
752  len = strlen (path);
753
754  if (rtl->paths)
755    len += strlen (rtl->paths) + 1;
756  else
757    prepend = true;
758
759  paths = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, len + 1, false);
760
761  if (!paths)
762  {
763    rtems_rtl_unlock ();
764    return false;
765  }
766
767  dst = paths;
768
769  if (prepend)
770  {
771    len = strlen (path);
772    src = path;
773  }
774  else if (rtl->paths)
775  {
776    len = strlen (rtl->paths);
777    src = rtl->paths;
778  }
779
780  memcpy (dst, src, len);
781
782  dst += len;
783
784  if (rtl->paths)
785  {
786    *dst = ':';
787    ++dst;
788  }
789
790  if (prepend)
791  {
792    src = rtl->paths;
793    if (src)
794      len = strlen (src);
795  }
796  else
797  {
798    len = strlen (path);
799    src = path;
800  }
801
802  if (src)
803  {
804    memcpy (dst, src, len);
805    dst += len;
806  }
807
808  *dst = '\0';
809
810  rtl->paths = paths;
811
812  rtems_rtl_unlock ();
813  return false;
814}
815
816bool
817rtems_rtl_path_append (const char* path)
818{
819  return rtems_rtl_path_update (false, path);
820}
821
822bool
823rtems_rtl_path_prepend (const char* path)
824{
825  return rtems_rtl_path_update (true, path);
826}
827
828void
829rtems_rtl_base_sym_global_add (const unsigned char* esyms,
830                               unsigned int         size)
831{
832  if (rtems_rtl_trace (RTEMS_RTL_TRACE_GLOBAL_SYM))
833    printf ("rtl: adding global symbols, table size %u\n", size);
834
835  if (!rtems_rtl_lock ())
836  {
837    rtems_rtl_set_error (EINVAL, "global add cannot lock rtl");
838    return;
839  }
840
841  rtems_rtl_symbol_global_add (rtl->base, esyms, size);
842
843  rtems_rtl_unlock ();
844}
845
846rtems_rtl_obj*
847rtems_rtl_baseimage (void)
848{
849  rtems_rtl_obj* base = NULL;
850  if (rtems_rtl_lock ())
851  {
852    base = rtl->base;
853    rtems_rtl_unlock ();
854  }
855  return base;
856}
Note: See TracBrowser for help on using the repository browser.