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

5
Last change on this file since be50969 was 194eb403, checked in by Chris Johns <chrisj@…>, on 01/21/19 at 21:48:19

libdl: Add support for large memory programs

  • Add trampolines to support relocs that are out of range on support architectures.
  • Support not loading separate text/data sections in an object file if the symbol provided in the section is a duplicate. A base image may have pulled in part of an object and another part needs to be dynamically loaded.
  • Refactor the unresolved handling to scale to hundreds of unresolved symbols when loading large number of files.

Updates #3685

  • Property mode set to 100644
File size: 19.3 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/libdl.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
268const char*
269rtems_rtl_last_error_unprotected (void)
270{
271  if (!rtl)
272    return NULL;
273  return rtl->last_error;
274}
275
276rtems_chain_control*
277rtems_rtl_objects_unprotected (void)
278{
279  if (!rtl)
280  {
281    rtems_rtl_set_error (ENOENT, "no rtl");
282    return NULL;
283  }
284  return &rtl->objects;
285}
286
287rtems_chain_control*
288rtems_rtl_pending_unprotected (void)
289{
290  if (!rtl)
291  {
292    rtems_rtl_set_error (ENOENT, "no rtl");
293    return NULL;
294  }
295  return &rtl->pending;
296}
297
298rtems_rtl_unresolved*
299rtems_rtl_unresolved_unprotected (void)
300{
301  if (!rtl)
302  {
303    rtems_rtl_set_error (ENOENT, "no rtl");
304    return NULL;
305  }
306  return &rtl->unresolved;
307}
308
309rtems_rtl_archives*
310rtems_rtl_archives_unprotected (void)
311{
312  if (!rtl)
313  {
314    rtems_rtl_set_error (ENOENT, "no rtl");
315    return NULL;
316  }
317  return &rtl->archives;
318}
319
320void
321rtems_rtl_obj_caches (rtems_rtl_obj_cache** symbols,
322                      rtems_rtl_obj_cache** strings,
323                      rtems_rtl_obj_cache** relocs)
324{
325  if (!rtl)
326  {
327    if (symbols)
328       *symbols = NULL;
329    if (strings)
330      *strings = NULL;
331    if (relocs)
332      *relocs = NULL;
333  }
334  else
335  {
336    if (symbols)
337      *symbols = &rtl->symbols;
338    if (strings)
339      *strings = &rtl->strings;
340    if (relocs)
341      *relocs = &rtl->relocs;
342  }
343}
344
345void
346rtems_rtl_obj_caches_flush (void)
347{
348  if (rtl)
349  {
350    rtems_rtl_obj_cache_flush (&rtl->symbols);
351    rtems_rtl_obj_cache_flush (&rtl->strings);
352    rtems_rtl_obj_cache_flush (&rtl->relocs);
353  }
354}
355
356void
357rtems_rtl_obj_decompress (rtems_rtl_obj_comp** decomp,
358                          rtems_rtl_obj_cache* cache,
359                          int                  fd,
360                          int                  compression,
361                          off_t                offset)
362{
363  if (!rtl)
364  {
365    *decomp = NULL;
366  }
367  else
368  {
369    *decomp = &rtl->decomp;
370    rtems_rtl_obj_comp_set (*decomp, cache, fd, compression, offset);
371  }
372}
373
374typedef struct rtems_rtl_obj_flags_data
375{
376  uint32_t clear;   /**< Flags to clear, do not invert. */
377  uint32_t set;     /**< Flags to set, applied after clearing. */
378} rtems_rtl_obj_flags_data;
379
380static bool
381rtems_rtl_obj_flags_iterator (rtems_chain_node* node, void* data)
382{
383  rtems_rtl_obj* obj              = (rtems_rtl_obj*) node;
384  rtems_rtl_obj_flags_data* flags = (rtems_rtl_obj_flags_data*) data;
385  if (flags->clear != 0)
386    obj->flags &= ~flags->clear;
387  if (flags->set != 0)
388    obj->flags |= flags->set;
389  return true;
390}
391
392void
393rtems_rtl_obj_update_flags (uint32_t clear, uint32_t set)
394{
395  rtems_rtl_obj_flags_data flags = {
396    .clear = clear,
397    .set   = set
398  };
399  rtems_rtl_chain_iterate (&rtl->objects,
400                           rtems_rtl_obj_flags_iterator,
401                           &flags);
402}
403
404rtems_rtl_data*
405rtems_rtl_lock (void)
406{
407  if (!rtems_rtl_data_init ())
408    return NULL;
409
410  rtems_recursive_mutex_lock (&rtl->lock);
411
412  return rtl;
413}
414
415void
416rtems_rtl_unlock (void)
417{
418  rtems_recursive_mutex_unlock (&rtl->lock);
419}
420
421rtems_rtl_obj*
422rtems_rtl_check_handle (void* handle)
423{
424  rtems_rtl_obj*    obj;
425  rtems_chain_node* node;
426
427  obj = handle;
428  node = rtems_chain_first (&rtl->objects);
429
430  while (!rtems_chain_is_tail (&rtl->objects, node))
431  {
432    rtems_rtl_obj* check = (rtems_rtl_obj*) node;
433    if (check == obj)
434      return obj;
435    node = rtems_chain_next (node);
436  }
437
438  return NULL;
439}
440
441rtems_rtl_obj*
442rtems_rtl_find_obj (const char* name)
443{
444  rtems_chain_node* node;
445  rtems_rtl_obj*    found = NULL;
446  const char*       aname = NULL;
447  const char*       oname = NULL;
448  off_t             ooffset;
449
450  if (!rtems_rtl_parse_name (name, &aname, &oname, &ooffset))
451    return NULL;
452
453  node = rtems_chain_first (&rtl->objects);
454
455  while (!rtems_chain_is_tail (&rtl->objects, node))
456  {
457    rtems_rtl_obj* obj = (rtems_rtl_obj*) node;
458    if ((aname == NULL && strcmp (obj->oname, oname) == 0) ||
459        (aname != NULL &&
460         strcmp (obj->aname, aname) == 0 && strcmp (obj->oname, oname) == 0))
461    {
462      found = obj;
463      break;
464    }
465    node = rtems_chain_next (node);
466  }
467
468  if (aname != NULL)
469    rtems_rtl_alloc_del(RTEMS_RTL_ALLOC_OBJECT, (void*) aname);
470
471  if (oname != NULL)
472    rtems_rtl_alloc_del(RTEMS_RTL_ALLOC_OBJECT, (void*) oname);
473
474  return found;
475}
476
477rtems_rtl_obj*
478rtems_rtl_find_obj_with_symbol (const rtems_rtl_obj_sym* sym)
479{
480  rtems_chain_node* node = rtems_chain_first (&rtl->objects);
481  while (!rtems_chain_is_tail (&rtl->objects, 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  node = rtems_chain_first (&rtl->pending);
489  while (!rtems_chain_is_tail (&rtl->pending, node))
490  {
491    rtems_rtl_obj* obj = (rtems_rtl_obj*) node;
492    if (rtems_rtl_obj_has_symbol (obj, sym))
493      return obj;
494    node = rtems_chain_next (node);
495  }
496  return NULL;
497}
498
499rtems_rtl_obj*
500rtems_rtl_load_object (const char* name, int mode)
501{
502  rtems_rtl_obj* obj;
503
504  if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD))
505    printf ("rtl: loading '%s'\n", name);
506
507  /*
508   * See if the object module has already been loaded.
509   */
510  obj = rtems_rtl_find_obj (name);
511  if (!obj)
512  {
513    /*
514     * Allocate a new object file descriptor and attempt to load it.
515     */
516    obj = rtems_rtl_obj_alloc ();
517    if (obj == NULL)
518    {
519      rtems_rtl_set_error (ENOMEM, "no memory for object descriptor");
520      return NULL;
521    }
522
523    rtems_chain_append (&rtl->pending, &obj->link);
524
525    /*
526     * Find the file in the file system using the search path. The fname field
527     * will point to a valid file name if found.
528     */
529    if (!rtems_rtl_obj_find_file (obj, name))
530    {
531      rtems_rtl_obj_free (obj);
532      rtems_rtl_obj_caches_flush ();
533      return NULL;
534    }
535
536    if (!rtems_rtl_obj_load (obj))
537    {
538      rtems_chain_extract (&obj->link);
539      rtems_rtl_obj_free (obj);
540      rtems_rtl_obj_caches_flush ();
541      return NULL;
542    }
543
544    /*
545     * If there are unresolved externals remove from the pending queue and place
546     * on the objects list until the symbols are resolved.
547     */
548    if (obj->unresolved != 0)
549    {
550      rtems_chain_extract (&obj->link);
551      rtems_chain_append (&rtl->objects, &obj->link);
552    }
553
554    rtems_rtl_obj_caches_flush ();
555  }
556
557  /*
558   * Increase the number of users.
559   */
560  ++obj->users;
561
562  return obj;
563}
564
565rtems_rtl_obj*
566rtems_rtl_load (const char* name, int mode)
567{
568  rtems_rtl_obj* obj;
569
570  /*
571   * Refesh the archives.
572   */
573  rtems_rtl_archives_refresh (&rtl->archives);
574
575  /*
576   * Collect the loaded object files.
577   */
578  rtems_chain_initialize_empty (&rtl->pending);
579
580  obj = rtems_rtl_load_object (name, mode);
581  if (obj != NULL)
582  {
583    rtems_chain_node* node;
584
585    rtems_rtl_unresolved_resolve ();
586
587    /*
588     * Iterator over the pending list of object files that have been loaded.
589     */
590    node = rtems_chain_first (&rtl->pending);
591    while (!rtems_chain_is_tail (&rtl->pending, node))
592    {
593      rtems_rtl_obj* pobj = (rtems_rtl_obj*) node;
594
595      /*
596       * Move to the next pending object file and place this object file on the
597       * RTL's objects list.
598       */
599      node = rtems_chain_next (&pobj->link);
600      rtems_chain_extract (&pobj->link);
601      rtems_chain_append (&rtl->objects, &pobj->link);
602
603      /*
604       * Make sure the object file and cache is synchronized.
605       */
606      rtems_rtl_obj_synchronize_cache (pobj);
607
608      /*
609       * Run any local constructors if they have not been run. Unlock the linker
610       * to avoid any dead locks if the object file needs to load files or
611       * update the symbol table. We also do not want a constructor to unload
612       * this object file.
613       */
614      if ((pobj->flags & RTEMS_RTL_OBJ_CTOR_RUN) == 0)
615      {
616        pobj->flags |= RTEMS_RTL_OBJ_LOCKED | RTEMS_RTL_OBJ_CTOR_RUN;
617        rtems_rtl_unlock ();
618        rtems_rtl_obj_run_ctors (pobj);
619        rtems_rtl_lock ();
620        pobj->flags &= ~RTEMS_RTL_OBJ_LOCKED;
621      }
622    }
623  }
624
625  return obj;
626}
627
628bool
629rtems_rtl_unload_object (rtems_rtl_obj* obj)
630{
631  if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNLOAD))
632    printf ("rtl: unload object '%s'\n", rtems_rtl_obj_fname (obj));
633
634  /*
635   * If the object is locked it cannot be unloaded and the unload fails.
636   */
637  if ((obj->flags & RTEMS_RTL_OBJ_LOCKED) == RTEMS_RTL_OBJ_LOCKED)
638  {
639    rtems_rtl_set_error (EINVAL, "object file is locked");
640    return false;
641  }
642
643  /*
644   * The object file cannot be unloaded if it is referenced.
645   */
646  if (rtems_rtl_obj_get_reference (obj) > 0)
647  {
648    rtems_rtl_set_error (EINVAL, "object file has references to it");
649    return false;
650  }
651
652  /*
653   * Check the number of users in a safe manner. If this is the last user unload
654   * the object file from memory.
655   */
656  if (obj->users > 0)
657    --obj->users;
658
659  return true;
660}
661
662bool
663rtems_rtl_unload (rtems_rtl_obj* obj)
664{
665  bool ok = rtems_rtl_unload_object (obj);
666  if (ok && obj->users == 0)
667  {
668    rtems_chain_control unloading;
669    rtems_chain_node*   node;
670    bool                orphaned_found = true;
671    int                 loop = 0;
672
673    /*
674     * Remove the orphaned object files from the objects list. The unloading is
675     * private so any changes in any desctructors will not effect the list as it
676     * is being iterated over.
677     *
678     * To avoid maintaining a complex tree loop while oprhans are still be found.
679     */
680
681    rtems_chain_initialize_empty (&unloading);
682
683    while (orphaned_found)
684    {
685      orphaned_found = false;
686      ++loop;
687      node = rtems_chain_first (&rtl->objects);
688      while (!rtems_chain_is_tail (&rtl->objects, node))
689      {
690        rtems_chain_node* next_node = rtems_chain_next (node);
691        rtems_rtl_obj* uobj = (rtems_rtl_obj*) node;
692        if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNLOAD))
693          printf ("rtl: unload object: %3i: %9s: %s\n",
694                  loop,
695                  rtems_rtl_obj_orphaned (uobj) ? "orphaned" : "inuse",
696                  rtems_rtl_obj_oname (uobj));
697        if (rtems_rtl_obj_orphaned (uobj))
698        {
699          orphaned_found = true;
700          rtems_rtl_obj_remove_dependencies (uobj);
701          rtems_chain_extract (&uobj->link);
702          rtems_chain_append (&unloading, &uobj->link);
703          uobj->flags |= RTEMS_RTL_OBJ_LOCKED;
704        }
705        node = next_node;
706      }
707    }
708
709    /*
710     * Call the desctructors unlocked. An RTL call will not deadlock.
711     */
712    rtems_rtl_unlock ();
713
714    node = rtems_chain_first (&unloading);
715    while (!rtems_chain_is_tail (&unloading, node))
716    {
717      rtems_rtl_obj* uobj = (rtems_rtl_obj*) node;
718      if ((uobj->flags & RTEMS_RTL_OBJ_CTOR_RUN) != 0)
719      {
720        rtems_rtl_obj_run_dtors (uobj);
721        uobj->flags &= ~RTEMS_RTL_OBJ_CTOR_RUN;
722      }
723      node = rtems_chain_next (node);
724    }
725
726    rtems_rtl_lock ();
727
728    /*
729     * Unload the object files.
730     */
731    node = rtems_chain_first (&unloading);
732    while (!rtems_chain_is_tail (&unloading, node))
733    {
734      rtems_chain_node* next_node = rtems_chain_next (node);
735      rtems_rtl_obj*    uobj = (rtems_rtl_obj*) node;
736      if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNLOAD))
737        printf ("rtl: unloading '%s'\n", rtems_rtl_obj_oname (uobj));
738      uobj->flags &= ~RTEMS_RTL_OBJ_LOCKED;
739      if (!rtems_rtl_obj_unload (uobj))
740        ok = false;
741      rtems_rtl_obj_free (uobj);
742      rtems_rtl_obj_caches_flush ();
743      node = next_node;
744    }
745  }
746  return ok;
747}
748
749static bool
750rtems_rtl_path_update (bool prepend, const char* path)
751{
752  char*       paths;
753  const char* src = NULL;
754  char*       dst;
755  int         len;
756
757  if (!rtems_rtl_lock ())
758    return false;
759
760  len = strlen (path);
761
762  if (rtl->paths)
763    len += strlen (rtl->paths) + 1;
764  else
765    prepend = true;
766
767  paths = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, len + 1, false);
768
769  if (!paths)
770  {
771    rtems_rtl_unlock ();
772    return false;
773  }
774
775  dst = paths;
776
777  if (prepend)
778  {
779    len = strlen (path);
780    src = path;
781  }
782  else if (rtl->paths)
783  {
784    len = strlen (rtl->paths);
785    src = rtl->paths;
786  }
787
788  memcpy (dst, src, len);
789
790  dst += len;
791
792  if (rtl->paths)
793  {
794    *dst = ':';
795    ++dst;
796  }
797
798  if (prepend)
799  {
800    src = rtl->paths;
801    if (src)
802      len = strlen (src);
803  }
804  else
805  {
806    len = strlen (path);
807    src = path;
808  }
809
810  if (src)
811  {
812    memcpy (dst, src, len);
813    dst += len;
814  }
815
816  *dst = '\0';
817
818  rtl->paths = paths;
819
820  rtems_rtl_unlock ();
821  return false;
822}
823
824bool
825rtems_rtl_path_append (const char* path)
826{
827  return rtems_rtl_path_update (false, path);
828}
829
830bool
831rtems_rtl_path_prepend (const char* path)
832{
833  return rtems_rtl_path_update (true, path);
834}
835
836void
837rtems_rtl_base_sym_global_add (const unsigned char* esyms,
838                               unsigned int         size)
839{
840  if (rtems_rtl_trace (RTEMS_RTL_TRACE_GLOBAL_SYM))
841    printf ("rtl: adding global symbols, table size %u\n", size);
842
843  if (!rtems_rtl_lock ())
844  {
845    rtems_rtl_set_error (EINVAL, "global add cannot lock rtl");
846    return;
847  }
848
849  rtems_rtl_symbol_global_add (rtl->base, esyms, size);
850
851  rtems_rtl_unlock ();
852}
853
854rtems_rtl_obj*
855rtems_rtl_baseimage (void)
856{
857  rtems_rtl_obj* base = NULL;
858  if (rtems_rtl_lock ())
859  {
860    base = rtl->base;
861    rtems_rtl_unlock ();
862  }
863  return base;
864}
Note: See TracBrowser for help on using the repository browser.