Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:16

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup rtems_rtld
0007  *
0008  * @brief RTEMS Run-Time Link Editor
0009  *
0010  * This is the RTL implementation.
0011  */
0012 
0013 /*
0014  *  COPYRIGHT (c) 2012, 2018 Chris Johns <chrisj@rtems.org>
0015  *
0016  * Redistribution and use in source and binary forms, with or without
0017  * modification, are permitted provided that the following conditions
0018  * are met:
0019  * 1. Redistributions of source code must retain the above copyright
0020  *    notice, this list of conditions and the following disclaimer.
0021  * 2. Redistributions in binary form must reproduce the above copyright
0022  *    notice, this list of conditions and the following disclaimer in the
0023  *    documentation and/or other materials provided with the distribution.
0024  *
0025  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0026  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0027  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0028  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0029  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0030  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0031  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0032  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0033  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0034  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0035  * POSSIBILITY OF SUCH DAMAGE.
0036  */
0037 
0038 #ifdef HAVE_CONFIG_H
0039 #include "config.h"
0040 #endif
0041 
0042 #include <stdlib.h>
0043 #include <stdio.h>
0044 #include <string.h>
0045 
0046 #include <rtems/libio_.h>
0047 
0048 #include <rtems/rtl/rtl.h>
0049 #include <rtems/rtl/rtl-allocator.h>
0050 #include <rtems/rtl/rtl-trace.h>
0051 #include "rtl-chain-iterator.h"
0052 #include "rtl-error.h"
0053 #include "rtl-string.h"
0054 
0055 /**
0056  * Symbol table cache size. They can be big so the cache needs space to work.
0057  */
0058 #define RTEMS_RTL_ELF_SYMBOL_CACHE (2048)
0059 
0060 /**
0061  * String table cache size.
0062  */
0063 #define RTEMS_RTL_ELF_STRING_CACHE (2048)
0064 
0065 /**
0066  * Relocations table cache size.
0067  */
0068 #define RTEMS_RTL_ELF_RELOC_CACHE (2048)
0069 
0070 /**
0071  * Decompression output buffer.
0072  */
0073 #define RTEMS_RTL_COMP_OUTPUT (2048)
0074 
0075 /**
0076  * Static RTL data is returned to the user when the linker is locked.
0077  */
0078 static rtems_rtl_data* rtl;
0079 static bool            rtl_data_init;
0080 
0081 /**
0082  * Define a default base global symbol loader function that is weak
0083  * so a real table can be linked in when the user wants one.
0084  */
0085 void rtems_rtl_base_global_syms_init (void) __attribute__ ((weak));
0086 void
0087 rtems_rtl_base_global_syms_init (void)
0088 {
0089   /*
0090    * Do nothing.
0091    */
0092 }
0093 
0094 static bool
0095 rtems_rtl_data_init (void)
0096 {
0097   /*
0098    * Lock the RTL. We only create a lock if a call is made. First we test if a
0099    * lock is present. If one is present we lock it. If not the libio lock is
0100    * locked and we then test the lock again. If not present we create the lock
0101    * then release libio lock.
0102    */
0103   if (!rtl)
0104   {
0105     rtems_libio_lock ();
0106 
0107     if (!rtl)
0108     {
0109       /*
0110        * We cannot set an error in this code because there is no RTL data to
0111        * hold it.
0112        */
0113 
0114       if (rtl_data_init)
0115       {
0116         rtems_libio_unlock ();
0117         return false;
0118       }
0119 
0120       rtl_data_init = true;
0121 
0122       /*
0123        * Always in the heap.
0124        */
0125       rtl = malloc (sizeof (rtems_rtl_data));
0126       if (!rtl)
0127       {
0128         rtems_libio_unlock ();
0129         errno = ENOMEM;
0130         return false;
0131       }
0132 
0133       *rtl = (rtems_rtl_data) { 0 };
0134 
0135       /*
0136        * The initialise the allocator data.
0137        */
0138       rtems_rtl_alloc_initialise (&rtl->allocator);
0139 
0140       /*
0141        * Create the RTL lock.
0142        */
0143       rtems_recursive_mutex_init (&rtl->lock, "Run-Time Linker");
0144       rtems_recursive_mutex_lock (&rtl->lock);
0145 
0146       /*
0147        * Initialise the objects and pending list.
0148        */
0149       rtems_chain_initialize_empty (&rtl->objects);
0150       rtems_chain_initialize_empty (&rtl->pending);
0151 
0152       /*
0153        * Open the global symbol table.
0154        */
0155       if (!rtems_rtl_symbol_table_open (&rtl->globals,
0156                                         RTEMS_RTL_SYMS_GLOBAL_BUCKETS))
0157       {
0158         rtems_recursive_mutex_destroy (&rtl->lock);
0159         free (rtl);
0160         rtems_libio_unlock ();
0161         return false;
0162       }
0163 
0164       /*
0165        * Open the archives.
0166        */
0167       rtems_rtl_archives_open (&rtl->archives, "/etc/libdl.conf");
0168 
0169       /*
0170        * Open the unresolved table.
0171        */
0172       if (!rtems_rtl_unresolved_table_open (&rtl->unresolved,
0173                                             RTEMS_RTL_UNRESOLVED_BLOCK_SIZE))
0174       {
0175         rtems_rtl_symbol_table_close (&rtl->globals);
0176         rtems_recursive_mutex_destroy (&rtl->lock);
0177         free (rtl);
0178         rtems_libio_unlock ();
0179         return false;
0180       }
0181 
0182       if (!rtems_rtl_obj_cache_open (&rtl->symbols,
0183                                      RTEMS_RTL_ELF_SYMBOL_CACHE))
0184       {
0185         rtems_rtl_symbol_table_close (&rtl->globals);
0186         rtems_rtl_unresolved_table_close (&rtl->unresolved);
0187         rtems_recursive_mutex_destroy (&rtl->lock);
0188         free (rtl);
0189         rtems_libio_unlock ();
0190         return false;
0191       }
0192 
0193       if (!rtems_rtl_obj_cache_open (&rtl->strings,
0194                                      RTEMS_RTL_ELF_STRING_CACHE))
0195       {
0196         rtems_rtl_obj_cache_close (&rtl->symbols);
0197         rtems_rtl_unresolved_table_close (&rtl->unresolved);
0198         rtems_rtl_symbol_table_close (&rtl->globals);
0199         rtems_recursive_mutex_destroy (&rtl->lock);
0200         free (rtl);
0201         rtems_libio_unlock ();
0202         return false;
0203       }
0204 
0205       if (!rtems_rtl_obj_cache_open (&rtl->relocs,
0206                                      RTEMS_RTL_ELF_RELOC_CACHE))
0207       {
0208         rtems_rtl_obj_cache_close (&rtl->strings);
0209         rtems_rtl_obj_cache_close (&rtl->symbols);
0210         rtems_rtl_unresolved_table_close (&rtl->unresolved);
0211         rtems_rtl_symbol_table_close (&rtl->globals);
0212         rtems_recursive_mutex_destroy (&rtl->lock);
0213         free (rtl);
0214         rtems_libio_unlock ();
0215         return false;
0216       }
0217 
0218       if (!rtems_rtl_obj_comp_open (&rtl->decomp,
0219                                     RTEMS_RTL_COMP_OUTPUT))
0220       {
0221         rtems_rtl_obj_cache_close (&rtl->relocs);
0222         rtems_rtl_obj_cache_close (&rtl->strings);
0223         rtems_rtl_obj_cache_close (&rtl->symbols);
0224         rtems_rtl_unresolved_table_close (&rtl->unresolved);
0225         rtems_rtl_symbol_table_close (&rtl->globals);
0226         rtems_recursive_mutex_destroy (&rtl->lock);
0227         free (rtl);
0228         rtems_libio_unlock ();
0229         return false;
0230       }
0231 
0232       rtl->base = rtems_rtl_obj_alloc ();
0233       if (!rtl->base)
0234       {
0235         rtems_rtl_obj_comp_close (&rtl->decomp);
0236         rtems_rtl_obj_cache_close (&rtl->relocs);
0237         rtems_rtl_obj_cache_close (&rtl->strings);
0238         rtems_rtl_obj_cache_close (&rtl->symbols);
0239         rtems_rtl_unresolved_table_close (&rtl->unresolved);
0240         rtems_rtl_symbol_table_close (&rtl->globals);
0241         rtems_recursive_mutex_destroy (&rtl->lock);
0242         free (rtl);
0243         rtems_libio_unlock ();
0244         return false;
0245       }
0246 
0247       /*
0248        * Need to malloc the memory so the free does not complain.
0249        */
0250       rtl->base->oname = rtems_rtl_strdup ("rtems-kernel");
0251 
0252       /*
0253        * Lock the base image and flag it as the base image.
0254        */
0255       rtl->base->flags |= RTEMS_RTL_OBJ_LOCKED | RTEMS_RTL_OBJ_BASE;
0256 
0257       rtems_chain_append (&rtl->objects, &rtl->base->link);
0258     }
0259 
0260     rtems_libio_unlock ();
0261 
0262     rtems_rtl_path_append (".");
0263 
0264     rtems_rtl_base_global_syms_init ();
0265 
0266     rtems_rtl_unlock ();
0267   }
0268   return true;
0269 }
0270 
0271 rtems_rtl_data*
0272 rtems_rtl_data_unprotected (void)
0273 {
0274   return rtl;
0275 }
0276 
0277 rtems_rtl_symbols*
0278 rtems_rtl_global_symbols (void)
0279 {
0280   if (!rtl)
0281   {
0282     rtems_rtl_set_error (ENOENT, "no rtl");
0283     return NULL;
0284   }
0285   return &rtl->globals;
0286 }
0287 
0288 const char*
0289 rtems_rtl_last_error_unprotected (void)
0290 {
0291   if (!rtl)
0292     return NULL;
0293   return rtl->last_error;
0294 }
0295 
0296 rtems_chain_control*
0297 rtems_rtl_objects_unprotected (void)
0298 {
0299   if (!rtl)
0300   {
0301     rtems_rtl_set_error (ENOENT, "no rtl");
0302     return NULL;
0303   }
0304   return &rtl->objects;
0305 }
0306 
0307 rtems_chain_control*
0308 rtems_rtl_pending_unprotected (void)
0309 {
0310   if (!rtl)
0311   {
0312     rtems_rtl_set_error (ENOENT, "no rtl");
0313     return NULL;
0314   }
0315   return &rtl->pending;
0316 }
0317 
0318 rtems_rtl_unresolved*
0319 rtems_rtl_unresolved_unprotected (void)
0320 {
0321   if (!rtl)
0322   {
0323     rtems_rtl_set_error (ENOENT, "no rtl");
0324     return NULL;
0325   }
0326   return &rtl->unresolved;
0327 }
0328 
0329 rtems_rtl_archives*
0330 rtems_rtl_archives_unprotected (void)
0331 {
0332   if (!rtl)
0333   {
0334     rtems_rtl_set_error (ENOENT, "no rtl");
0335     return NULL;
0336   }
0337   return &rtl->archives;
0338 }
0339 
0340 void
0341 rtems_rtl_obj_caches (rtems_rtl_obj_cache** symbols,
0342                       rtems_rtl_obj_cache** strings,
0343                       rtems_rtl_obj_cache** relocs)
0344 {
0345   if (!rtl)
0346   {
0347     if (symbols)
0348        *symbols = NULL;
0349     if (strings)
0350       *strings = NULL;
0351     if (relocs)
0352       *relocs = NULL;
0353   }
0354   else
0355   {
0356     if (symbols)
0357       *symbols = &rtl->symbols;
0358     if (strings)
0359       *strings = &rtl->strings;
0360     if (relocs)
0361       *relocs = &rtl->relocs;
0362   }
0363 }
0364 
0365 void
0366 rtems_rtl_obj_caches_flush (void)
0367 {
0368   if (rtl)
0369   {
0370     rtems_rtl_obj_cache_flush (&rtl->symbols);
0371     rtems_rtl_obj_cache_flush (&rtl->strings);
0372     rtems_rtl_obj_cache_flush (&rtl->relocs);
0373   }
0374 }
0375 
0376 void
0377 rtems_rtl_obj_decompress (rtems_rtl_obj_comp** decomp,
0378                           rtems_rtl_obj_cache* cache,
0379                           int                  fd,
0380                           int                  compression,
0381                           off_t                offset)
0382 {
0383   if (!rtl)
0384   {
0385     *decomp = NULL;
0386   }
0387   else
0388   {
0389     *decomp = &rtl->decomp;
0390     rtems_rtl_obj_comp_set (*decomp, cache, fd, compression, offset);
0391   }
0392 }
0393 
0394 typedef struct rtems_rtl_obj_flags_data
0395 {
0396   uint32_t clear;   /**< Flags to clear, do not invert. */
0397   uint32_t set;     /**< Flags to set, applied after clearing. */
0398 } rtems_rtl_obj_flags_data;
0399 
0400 static bool
0401 rtems_rtl_obj_flags_iterator (rtems_chain_node* node, void* data)
0402 {
0403   rtems_rtl_obj* obj              = (rtems_rtl_obj*) node;
0404   rtems_rtl_obj_flags_data* flags = (rtems_rtl_obj_flags_data*) data;
0405   if (flags->clear != 0)
0406     obj->flags &= ~flags->clear;
0407   if (flags->set != 0)
0408     obj->flags |= flags->set;
0409   return true;
0410 }
0411 
0412 void
0413 rtems_rtl_obj_update_flags (uint32_t clear, uint32_t set)
0414 {
0415   rtems_rtl_obj_flags_data flags = {
0416     .clear = clear,
0417     .set   = set
0418   };
0419   rtems_rtl_chain_iterate (&rtl->objects,
0420                            rtems_rtl_obj_flags_iterator,
0421                            &flags);
0422 }
0423 
0424 rtems_rtl_data*
0425 rtems_rtl_lock (void)
0426 {
0427   if (!rtems_rtl_data_init ())
0428     return NULL;
0429 
0430   rtems_recursive_mutex_lock (&rtl->lock);
0431 
0432   return rtl;
0433 }
0434 
0435 void
0436 rtems_rtl_unlock (void)
0437 {
0438   rtems_recursive_mutex_unlock (&rtl->lock);
0439 }
0440 
0441 rtems_rtl_obj*
0442 rtems_rtl_check_handle (void* handle)
0443 {
0444   rtems_rtl_obj*    obj;
0445   rtems_chain_node* node;
0446 
0447   obj = handle;
0448   node = rtems_chain_first (&rtl->objects);
0449 
0450   while (!rtems_chain_is_tail (&rtl->objects, node))
0451   {
0452     rtems_rtl_obj* check = (rtems_rtl_obj*) node;
0453     if (check == obj)
0454       return obj;
0455     node = rtems_chain_next (node);
0456   }
0457 
0458   return NULL;
0459 }
0460 
0461 rtems_rtl_obj*
0462 rtems_rtl_find_obj (const char* name)
0463 {
0464   rtems_chain_node* node;
0465   rtems_rtl_obj*    found = NULL;
0466   const char*       aname = NULL;
0467   const char*       oname = NULL;
0468   off_t             ooffset;
0469 
0470   if (!rtems_rtl_parse_name (name, &aname, &oname, &ooffset))
0471     return NULL;
0472 
0473   node = rtems_chain_first (&rtl->objects);
0474 
0475   while (!rtems_chain_is_tail (&rtl->objects, node))
0476   {
0477     rtems_rtl_obj* obj = (rtems_rtl_obj*) node;
0478     if ((aname == NULL && strcmp (obj->oname, oname) == 0) ||
0479         (aname != NULL &&
0480          strcmp (obj->aname, aname) == 0 && strcmp (obj->oname, oname) == 0))
0481     {
0482       found = obj;
0483       break;
0484     }
0485     node = rtems_chain_next (node);
0486   }
0487 
0488   if (aname != NULL)
0489     rtems_rtl_alloc_del(RTEMS_RTL_ALLOC_OBJECT, (void*) aname);
0490 
0491   if (oname != NULL)
0492     rtems_rtl_alloc_del(RTEMS_RTL_ALLOC_OBJECT, (void*) oname);
0493 
0494   return found;
0495 }
0496 
0497 rtems_rtl_obj*
0498 rtems_rtl_find_obj_with_symbol (const rtems_rtl_obj_sym* sym)
0499 {
0500   if (sym != NULL)
0501   {
0502     rtems_chain_node* node = rtems_chain_first (&rtl->objects);
0503     while (!rtems_chain_is_tail (&rtl->objects, node))
0504     {
0505       rtems_rtl_obj* obj = (rtems_rtl_obj*) node;
0506       if (rtems_rtl_obj_has_symbol (obj, sym))
0507         return obj;
0508       node = rtems_chain_next (node);
0509     }
0510     node = rtems_chain_first (&rtl->pending);
0511     while (!rtems_chain_is_tail (&rtl->pending, node))
0512     {
0513       rtems_rtl_obj* obj = (rtems_rtl_obj*) node;
0514       if (rtems_rtl_obj_has_symbol (obj, sym))
0515         return obj;
0516       node = rtems_chain_next (node);
0517     }
0518   }
0519   return NULL;
0520 }
0521 
0522 rtems_rtl_obj*
0523 rtems_rtl_load_object (const char* name, int mode)
0524 {
0525   rtems_rtl_obj* obj;
0526 
0527   if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD))
0528     printf ("rtl: loading '%s'\n", name);
0529 
0530   /*
0531    * See if the object module has already been loaded.
0532    */
0533   obj = rtems_rtl_find_obj (name);
0534   if (!obj)
0535   {
0536     /*
0537      * Allocate a new object file descriptor and attempt to load it.
0538      */
0539     obj = rtems_rtl_obj_alloc ();
0540     if (obj == NULL)
0541     {
0542       rtems_rtl_set_error (ENOMEM, "no memory for object descriptor");
0543       return NULL;
0544     }
0545 
0546     rtems_chain_append (&rtl->pending, &obj->link);
0547 
0548     /*
0549      * Find the file in the file system using the search path. The fname field
0550      * will point to a valid file name if found.
0551      */
0552     if (!rtems_rtl_obj_find_file (obj, name))
0553     {
0554       rtems_rtl_obj_free (obj);
0555       rtems_rtl_obj_caches_flush ();
0556       return NULL;
0557     }
0558 
0559     if (!rtems_rtl_obj_load (obj))
0560     {
0561       rtems_chain_extract (&obj->link);
0562       rtems_rtl_obj_free (obj);
0563       rtems_rtl_obj_caches_flush ();
0564       return NULL;
0565     }
0566 
0567     /*
0568      * If there are unresolved externals remove from the pending queue and place
0569      * on the objects list until the symbols are resolved.
0570      */
0571     if (obj->unresolved != 0)
0572     {
0573       rtems_chain_extract (&obj->link);
0574       rtems_chain_append (&rtl->objects, &obj->link);
0575     }
0576 
0577     rtems_rtl_obj_caches_flush ();
0578   }
0579 
0580   /*
0581    * Increase the number of users.
0582    */
0583   ++obj->users;
0584 
0585   return obj;
0586 }
0587 
0588 rtems_rtl_obj*
0589 rtems_rtl_load (const char* name, int mode)
0590 {
0591   rtems_rtl_obj* obj;
0592 
0593   /*
0594    * Refesh the archives.
0595    */
0596   rtems_rtl_archives_refresh (&rtl->archives);
0597 
0598   /*
0599    * Collect the loaded object files.
0600    */
0601   rtems_chain_initialize_empty (&rtl->pending);
0602 
0603   obj = rtems_rtl_load_object (name, mode);
0604   if (obj != NULL)
0605   {
0606     rtems_chain_node* node;
0607 
0608     rtems_rtl_unresolved_resolve ();
0609 
0610     /*
0611      * Iterator over the pending list of object files that have been loaded.
0612      */
0613     node = rtems_chain_first (&rtl->pending);
0614     while (!rtems_chain_is_tail (&rtl->pending, node))
0615     {
0616       rtems_rtl_obj* pobj = (rtems_rtl_obj*) node;
0617 
0618       /*
0619        * Move to the next pending object file and place this object file on the
0620        * RTL's objects list.
0621        */
0622       node = rtems_chain_next (&pobj->link);
0623       rtems_chain_extract (&pobj->link);
0624       rtems_chain_append (&rtl->objects, &pobj->link);
0625 
0626       /*
0627        * Make sure the object file and cache is synchronized.
0628        */
0629       rtems_rtl_obj_synchronize_cache (pobj);
0630 
0631       /*
0632        * Run any local constructors if they have not been run. Unlock the linker
0633        * to avoid any dead locks if the object file needs to load files or
0634        * update the symbol table. We also do not want a constructor to unload
0635        * this object file.
0636        */
0637       if ((pobj->flags & RTEMS_RTL_OBJ_CTOR_RUN) == 0)
0638       {
0639         pobj->flags |= RTEMS_RTL_OBJ_LOCKED | RTEMS_RTL_OBJ_CTOR_RUN;
0640         rtems_rtl_unlock ();
0641         rtems_rtl_obj_run_ctors (pobj);
0642         rtems_rtl_lock ();
0643         pobj->flags &= ~RTEMS_RTL_OBJ_LOCKED;
0644       }
0645     }
0646   }
0647 
0648   return obj;
0649 }
0650 
0651 bool
0652 rtems_rtl_unload_object (rtems_rtl_obj* obj)
0653 {
0654   if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNLOAD))
0655     printf ("rtl: unload object '%s'\n", rtems_rtl_obj_fname (obj));
0656 
0657   /*
0658    * If the object is locked it cannot be unloaded and the unload fails.
0659    */
0660   if ((obj->flags & RTEMS_RTL_OBJ_LOCKED) == RTEMS_RTL_OBJ_LOCKED)
0661   {
0662     rtems_rtl_set_error (EINVAL, "object file is locked");
0663     return false;
0664   }
0665 
0666   /*
0667    * The object file cannot be unloaded if it is referenced.
0668    */
0669   if (rtems_rtl_obj_get_reference (obj) > 0)
0670   {
0671     rtems_rtl_set_error (EINVAL, "object file has references to it");
0672     return false;
0673   }
0674 
0675   /*
0676    * Check the number of users in a safe manner. If this is the last user unload
0677    * the object file from memory.
0678    */
0679   if (obj->users > 0)
0680     --obj->users;
0681 
0682   return true;
0683 }
0684 
0685 bool
0686 rtems_rtl_unload (rtems_rtl_obj* obj)
0687 {
0688   bool ok = rtems_rtl_unload_object (obj);
0689   if (ok && obj->users == 0)
0690   {
0691     rtems_chain_control unloading;
0692     rtems_chain_node*   node;
0693     bool                orphaned_found = true;
0694     int                 loop = 0;
0695 
0696     /*
0697      * Remove the orphaned object files from the objects list. The unloading is
0698      * private so any changes in any desctructors will not effect the list as it
0699      * is being iterated over.
0700      *
0701      * To avoid maintaining a complex tree loop while oprhans are still be found.
0702      */
0703 
0704     rtems_chain_initialize_empty (&unloading);
0705 
0706     while (orphaned_found)
0707     {
0708       orphaned_found = false;
0709       ++loop;
0710       node = rtems_chain_first (&rtl->objects);
0711       while (!rtems_chain_is_tail (&rtl->objects, node))
0712       {
0713         rtems_chain_node* next_node = rtems_chain_next (node);
0714         rtems_rtl_obj* uobj = (rtems_rtl_obj*) node;
0715         if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNLOAD))
0716           printf ("rtl: unload object: %3i: %9s: %s\n",
0717                   loop,
0718                   rtems_rtl_obj_orphaned (uobj) ? "orphaned" : "inuse",
0719                   rtems_rtl_obj_oname (uobj));
0720         if (rtems_rtl_obj_orphaned (uobj))
0721         {
0722           orphaned_found = true;
0723           rtems_rtl_obj_remove_dependencies (uobj);
0724           rtems_chain_extract (&uobj->link);
0725           rtems_chain_append (&unloading, &uobj->link);
0726           uobj->flags |= RTEMS_RTL_OBJ_LOCKED;
0727         }
0728         node = next_node;
0729       }
0730     }
0731 
0732     /*
0733      * Call the desctructors unlocked. An RTL call will not deadlock.
0734      */
0735     rtems_rtl_unlock ();
0736 
0737     node = rtems_chain_first (&unloading);
0738     while (!rtems_chain_is_tail (&unloading, node))
0739     {
0740       rtems_rtl_obj* uobj = (rtems_rtl_obj*) node;
0741       if ((uobj->flags & RTEMS_RTL_OBJ_CTOR_RUN) != 0)
0742       {
0743         rtems_rtl_obj_run_dtors (uobj);
0744         uobj->flags &= ~RTEMS_RTL_OBJ_CTOR_RUN;
0745       }
0746       node = rtems_chain_next (node);
0747     }
0748 
0749     rtems_rtl_lock ();
0750 
0751     /*
0752      * Unload the object files.
0753      */
0754     node = rtems_chain_first (&unloading);
0755     while (!rtems_chain_is_tail (&unloading, node))
0756     {
0757       rtems_chain_node* next_node = rtems_chain_next (node);
0758       rtems_rtl_obj*    uobj = (rtems_rtl_obj*) node;
0759       if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNLOAD))
0760         printf ("rtl: unloading '%s'\n", rtems_rtl_obj_oname (uobj));
0761       uobj->flags &= ~RTEMS_RTL_OBJ_LOCKED;
0762       if (!rtems_rtl_obj_unload (uobj))
0763         ok = false;
0764       rtems_rtl_obj_free (uobj);
0765       rtems_rtl_obj_caches_flush ();
0766       node = next_node;
0767     }
0768   }
0769   return ok;
0770 }
0771 
0772 static bool
0773 rtems_rtl_path_update (bool prepend, const char* path)
0774 {
0775   char*       paths;
0776   const char* src = NULL;
0777   char*       dst;
0778   int         len;
0779 
0780   if (!rtems_rtl_lock ())
0781     return false;
0782 
0783   len = strlen (path);
0784 
0785   if (rtl->paths)
0786     len += strlen (rtl->paths) + 1;
0787   else
0788     prepend = true;
0789 
0790   paths = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, len + 1, false);
0791 
0792   if (!paths)
0793   {
0794     rtems_rtl_unlock ();
0795     return false;
0796   }
0797 
0798   dst = paths;
0799 
0800   if (prepend)
0801   {
0802     len = strlen (path);
0803     src = path;
0804   }
0805   else if (rtl->paths)
0806   {
0807     len = strlen (rtl->paths);
0808     src = rtl->paths;
0809   }
0810 
0811   memcpy (dst, src, len);
0812 
0813   dst += len;
0814 
0815   if (rtl->paths)
0816   {
0817     *dst = ':';
0818     ++dst;
0819   }
0820 
0821   if (prepend)
0822   {
0823     src = rtl->paths;
0824     if (src)
0825       len = strlen (src);
0826   }
0827   else
0828   {
0829     len = strlen (path);
0830     src = path;
0831   }
0832 
0833   if (src)
0834   {
0835     memcpy (dst, src, len);
0836     dst += len;
0837   }
0838 
0839   *dst = '\0';
0840 
0841   rtl->paths = paths;
0842 
0843   rtems_rtl_unlock ();
0844   return false;
0845 }
0846 
0847 bool
0848 rtems_rtl_path_append (const char* path)
0849 {
0850   return rtems_rtl_path_update (false, path);
0851 }
0852 
0853 bool
0854 rtems_rtl_path_prepend (const char* path)
0855 {
0856   return rtems_rtl_path_update (true, path);
0857 }
0858 
0859 void
0860 rtems_rtl_base_sym_global_add (const unsigned char*        esyms,
0861                                unsigned int                size,
0862                                const rtems_rtl_tls_offset* tls_offsets,
0863                                unsigned int                tls_size)
0864 {
0865   if (rtems_rtl_trace (RTEMS_RTL_TRACE_GLOBAL_SYM))
0866     printf ("rtl: adding global symbols, table size %u\n", size);
0867 
0868   if (!rtems_rtl_lock ())
0869   {
0870     rtems_rtl_set_error (EINVAL, "global add cannot lock rtl");
0871     return;
0872   }
0873 
0874   rtems_rtl_symbol_global_add (rtl->base, esyms, size, tls_offsets, tls_size);
0875 
0876   rtems_rtl_unlock ();
0877 }
0878 
0879 rtems_rtl_obj*
0880 rtems_rtl_baseimage (void)
0881 {
0882   rtems_rtl_obj* base = NULL;
0883   if (rtems_rtl_lock ())
0884   {
0885     base = rtl->base;
0886     rtems_rtl_unlock ();
0887   }
0888   return base;
0889 }