File indexing completed on 2025-05-11 08:24:16
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
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
0057
0058 #define RTEMS_RTL_ELF_SYMBOL_CACHE (2048)
0059
0060
0061
0062
0063 #define RTEMS_RTL_ELF_STRING_CACHE (2048)
0064
0065
0066
0067
0068 #define RTEMS_RTL_ELF_RELOC_CACHE (2048)
0069
0070
0071
0072
0073 #define RTEMS_RTL_COMP_OUTPUT (2048)
0074
0075
0076
0077
0078 static rtems_rtl_data* rtl;
0079 static bool rtl_data_init;
0080
0081
0082
0083
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
0091
0092 }
0093
0094 static bool
0095 rtems_rtl_data_init (void)
0096 {
0097
0098
0099
0100
0101
0102
0103 if (!rtl)
0104 {
0105 rtems_libio_lock ();
0106
0107 if (!rtl)
0108 {
0109
0110
0111
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
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
0137
0138 rtems_rtl_alloc_initialise (&rtl->allocator);
0139
0140
0141
0142
0143 rtems_recursive_mutex_init (&rtl->lock, "Run-Time Linker");
0144 rtems_recursive_mutex_lock (&rtl->lock);
0145
0146
0147
0148
0149 rtems_chain_initialize_empty (&rtl->objects);
0150 rtems_chain_initialize_empty (&rtl->pending);
0151
0152
0153
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
0166
0167 rtems_rtl_archives_open (&rtl->archives, "/etc/libdl.conf");
0168
0169
0170
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
0249
0250 rtl->base->oname = rtems_rtl_strdup ("rtems-kernel");
0251
0252
0253
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;
0397 uint32_t set;
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
0532
0533 obj = rtems_rtl_find_obj (name);
0534 if (!obj)
0535 {
0536
0537
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
0550
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
0569
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
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
0595
0596 rtems_rtl_archives_refresh (&rtl->archives);
0597
0598
0599
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
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
0620
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
0628
0629 rtems_rtl_obj_synchronize_cache (pobj);
0630
0631
0632
0633
0634
0635
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
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
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
0677
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
0698
0699
0700
0701
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
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
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 }