source: rtems/cpukit/libdl/rtl.c @ 990adc5

5
Last change on this file since 990adc5 was 990adc5, checked in by Sebastian Huber <sebastian.huber@…>, on Dec 13, 2017 at 7:20:30 AM

libdl: Include <rtems/rtl/rtl-*.h>

Prepare for header file move to common include directory.

Update #3254.

  • Property mode set to 100644
File size: 14.2 KB
Line 
1/*
2 *  COPYRIGHT (c) 2012 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 "rtl-error.h"
31#include "rtl-string.h"
32#include <rtems/rtl/rtl-trace.h>
33
34/**
35 * Semaphore configuration to create a mutex.
36 */
37#define RTEMS_MUTEX_ATTRIBS \
38  (RTEMS_PRIORITY | RTEMS_BINARY_SEMAPHORE | \
39   RTEMS_INHERIT_PRIORITY | RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL)
40
41/**
42 * Symbol table cache size. They can be big so the cache needs space to work.
43 */
44#define RTEMS_RTL_ELF_SYMBOL_CACHE (2048)
45
46/**
47 * String table cache size.
48 */
49#define RTEMS_RTL_ELF_STRING_CACHE (2048)
50
51/**
52 * Relocations table cache size.
53 */
54#define RTEMS_RTL_ELF_RELOC_CACHE (2048)
55
56/**
57 * Decompression output buffer.
58 */
59#define RTEMS_RTL_COMP_OUTPUT (2048)
60
61/**
62 * Static RTL data is returned to the user when the linker is locked.
63 */
64static rtems_rtl_data_t* rtl;
65static bool              rtl_data_init;
66
67/**
68 * Define a default base global symbol loader function that is weak
69 * so a real table can be linked in when the user wants one.
70 */
71void rtems_rtl_base_global_syms_init (void) __attribute__ ((weak));
72void
73rtems_rtl_base_global_syms_init (void)
74{
75  /*
76   * Do nothing.
77   */
78}
79
80static bool
81rtems_rtl_data_init (void)
82{
83  /*
84   * Lock the RTL. We only create a lock if a call is made. First we test if a
85   * lock is present. If one is present we lock it. If not the libio lock is
86   * locked and we then test the lock again. If not present we create the lock
87   * then release libio lock.
88   */
89  if (!rtl)
90  {
91    rtems_libio_lock ();
92
93    if (!rtl)
94    {
95      rtems_status_code sc;
96      rtems_id          lock;
97
98      /*
99       * We cannot set an error in this code because there is no RTL data to
100       * hold it.
101       */
102
103      if (rtl_data_init)
104      {
105        rtems_libio_unlock ();
106        return false;
107      }
108
109      rtl_data_init = true;
110
111      /*
112       * Always in the heap.
113       */
114      rtl = malloc (sizeof (rtems_rtl_data_t));
115      if (!rtl)
116      {
117        rtems_libio_unlock ();
118        errno = ENOMEM;
119        return false;
120      }
121
122      *rtl = (rtems_rtl_data_t) { 0 };
123
124      /*
125       * The initialise the allocator data.
126       */
127      rtems_rtl_alloc_initialise (&rtl->allocator);
128
129      /*
130       * Create the RTL lock.
131       */
132      sc = rtems_semaphore_create (rtems_build_name ('R', 'T', 'L', 'D'),
133                                   1, RTEMS_MUTEX_ATTRIBS,
134                                   RTEMS_NO_PRIORITY, &lock);
135      if (sc != RTEMS_SUCCESSFUL)
136      {
137        free (rtl);
138        rtems_libio_unlock ();
139        return false;
140      }
141
142      sc = rtems_semaphore_obtain (lock, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
143      if (sc != RTEMS_SUCCESSFUL)
144      {
145        rtems_semaphore_delete (lock);
146        free (rtl);
147        rtems_libio_unlock ();
148        return false;
149      }
150
151      rtl->lock = lock;
152
153      /*
154       * Initialise the objects list and create any required services.
155       */
156      rtems_chain_initialize_empty (&rtl->objects);
157
158      if (!rtems_rtl_symbol_table_open (&rtl->globals,
159                                        RTEMS_RTL_SYMS_GLOBAL_BUCKETS))
160      {
161        rtems_semaphore_delete (lock);
162        free (rtl);
163        rtems_libio_unlock ();
164        return false;
165      }
166
167      if (!rtems_rtl_unresolved_table_open (&rtl->unresolved,
168                                            RTEMS_RTL_UNRESOLVED_BLOCK_SIZE))
169      {
170        rtems_rtl_symbol_table_close (&rtl->globals);
171        rtems_semaphore_delete (lock);
172        free (rtl);
173        rtems_libio_unlock ();
174        return false;
175      }
176
177      if (!rtems_rtl_obj_cache_open (&rtl->symbols,
178                                     RTEMS_RTL_ELF_SYMBOL_CACHE))
179      {
180        rtems_rtl_symbol_table_close (&rtl->globals);
181        rtems_rtl_unresolved_table_close (&rtl->unresolved);
182        rtems_semaphore_delete (lock);
183        free (rtl);
184        rtems_libio_unlock ();
185        return false;
186      }
187
188      if (!rtems_rtl_obj_cache_open (&rtl->strings,
189                                     RTEMS_RTL_ELF_STRING_CACHE))
190      {
191        rtems_rtl_obj_cache_close (&rtl->symbols);
192        rtems_rtl_unresolved_table_close (&rtl->unresolved);
193        rtems_rtl_symbol_table_close (&rtl->globals);
194        rtems_semaphore_delete (lock);
195        free (rtl);
196        rtems_libio_unlock ();
197        return false;
198      }
199
200      if (!rtems_rtl_obj_cache_open (&rtl->relocs,
201                                     RTEMS_RTL_ELF_RELOC_CACHE))
202      {
203        rtems_rtl_obj_cache_close (&rtl->strings);
204        rtems_rtl_obj_cache_close (&rtl->symbols);
205        rtems_rtl_unresolved_table_close (&rtl->unresolved);
206        rtems_rtl_symbol_table_close (&rtl->globals);
207        rtems_semaphore_delete (lock);
208        free (rtl);
209        rtems_libio_unlock ();
210        return false;
211      }
212
213      if (!rtems_rtl_obj_comp_open (&rtl->decomp,
214                                    RTEMS_RTL_COMP_OUTPUT))
215      {
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_semaphore_delete (lock);
222        free (rtl);
223        rtems_libio_unlock ();
224        return false;
225      }
226
227      rtl->base = rtems_rtl_obj_alloc ();
228      if (!rtl->base)
229      {
230        rtems_rtl_obj_comp_close (&rtl->decomp);
231        rtems_rtl_obj_cache_close (&rtl->relocs);
232        rtems_rtl_obj_cache_close (&rtl->strings);
233        rtems_rtl_obj_cache_close (&rtl->symbols);
234        rtems_rtl_unresolved_table_close (&rtl->unresolved);
235        rtems_rtl_symbol_table_close (&rtl->globals);
236        rtems_semaphore_delete (lock);
237        free (rtl);
238        rtems_libio_unlock ();
239        return false;
240      }
241
242      /*
243       * Need to malloc the memory so the free does not complain.
244       */
245      rtl->base->oname = rtems_rtl_strdup ("rtems-kernel");
246
247      rtems_chain_append (&rtl->objects, &rtl->base->link);
248    }
249
250    rtems_libio_unlock ();
251
252    rtems_rtl_path_append (".");
253
254    rtems_rtl_base_global_syms_init ();
255
256    rtems_rtl_unlock ();
257  }
258  return true;
259}
260
261rtems_rtl_data_t*
262rtems_rtl_data (void)
263{
264  return rtl;
265}
266
267rtems_rtl_symbols_t*
268rtems_rtl_global_symbols (void)
269{
270  if (!rtl)
271  {
272    rtems_rtl_set_error (ENOENT, "no rtl");
273    return NULL;
274  }
275  return &rtl->globals;
276}
277
278rtems_rtl_unresolved_t*
279rtems_rtl_unresolved (void)
280{
281  if (!rtl)
282  {
283    rtems_rtl_set_error (ENOENT, "no rtl");
284    return NULL;
285  }
286  return &rtl->unresolved;
287}
288
289void
290rtems_rtl_obj_caches (rtems_rtl_obj_cache_t** symbols,
291                      rtems_rtl_obj_cache_t** strings,
292                      rtems_rtl_obj_cache_t** relocs)
293{
294  if (!rtl)
295  {
296    if (symbols)
297       *symbols = NULL;
298    if (strings)
299      *strings = NULL;
300    if (relocs)
301      *relocs = NULL;
302  }
303  else
304  {
305    if (symbols)
306      *symbols = &rtl->symbols;
307    if (strings)
308      *strings = &rtl->strings;
309    if (relocs)
310      *relocs = &rtl->relocs;
311  }
312}
313
314void
315rtems_rtl_obj_caches_flush (void)
316{
317  if (rtl)
318  {
319    rtems_rtl_obj_cache_flush (&rtl->symbols);
320    rtems_rtl_obj_cache_flush (&rtl->strings);
321    rtems_rtl_obj_cache_flush (&rtl->relocs);
322  }
323}
324
325void
326rtems_rtl_obj_comp (rtems_rtl_obj_comp_t** decomp,
327                    rtems_rtl_obj_cache_t* cache,
328                    int                    fd,
329                    int                    compression,
330                    off_t                  offset)
331{
332  if (!rtl)
333  {
334    *decomp = NULL;
335  }
336  else
337  {
338    *decomp = &rtl->decomp;
339    rtems_rtl_obj_comp_set (*decomp, cache, fd, compression, offset);
340  }
341}
342
343rtems_rtl_data_t*
344rtems_rtl_lock (void)
345{
346  rtems_status_code sc;
347
348  if (!rtems_rtl_data_init ())
349    return NULL;
350
351  sc = rtems_semaphore_obtain (rtl->lock,
352                               RTEMS_WAIT, RTEMS_NO_TIMEOUT);
353  if (sc != RTEMS_SUCCESSFUL)
354  {
355    errno = EINVAL;
356    return NULL;
357  }
358
359  return rtl;
360}
361
362bool
363rtems_rtl_unlock (void)
364{
365  /*
366   * Not sure any error should be returned or an assert.
367   */
368  rtems_status_code sc;
369  sc = rtems_semaphore_release (rtl->lock);
370  if ((sc != RTEMS_SUCCESSFUL) && (errno == 0))
371  {
372    errno = EINVAL;
373    return false;
374  }
375  return true;
376}
377
378rtems_rtl_obj_t*
379rtems_rtl_check_handle (void* handle)
380{
381  rtems_rtl_obj_t*    obj;
382  rtems_chain_node* node;
383
384  obj = handle;
385  node = rtems_chain_first (&rtl->objects);
386
387  while (!rtems_chain_is_tail (&rtl->objects, node))
388  {
389    rtems_rtl_obj_t* check = (rtems_rtl_obj_t*) node;
390    if (check == obj)
391      return obj;
392    node = rtems_chain_next (node);
393  }
394
395  return NULL;
396}
397
398rtems_rtl_obj_t*
399rtems_rtl_find_obj (const char* name)
400{
401  rtems_chain_node* node;
402  rtems_rtl_obj_t*  found = NULL;
403  const char*       aname = NULL;
404  const char*       oname = NULL;
405  off_t             ooffset;
406
407  if (!rtems_rtl_parse_name (name, &aname, &oname, &ooffset))
408    return NULL;
409
410  node = rtems_chain_first (&rtl->objects);
411
412  while (!rtems_chain_is_tail (&rtl->objects, node))
413  {
414    rtems_rtl_obj_t* obj = (rtems_rtl_obj_t*) node;
415    if ((aname == NULL && strcmp (obj->oname, oname) == 0) ||
416        (aname != NULL &&
417         strcmp (obj->aname, aname) == 0 && strcmp (obj->oname, oname) == 0))
418    {
419        found = obj;
420        break;
421    }
422    node = rtems_chain_next (node);
423  }
424
425  if (!aname)
426    rtems_rtl_alloc_del(RTEMS_RTL_ALLOC_OBJECT, (void*) aname);
427
428  if (!oname)
429    rtems_rtl_alloc_del(RTEMS_RTL_ALLOC_OBJECT, (void*) oname);
430
431  return found;
432}
433
434rtems_rtl_obj_t*
435rtems_rtl_load_object (const char* name, int mode)
436{
437  rtems_rtl_obj_t* obj;
438
439  if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD))
440    printf ("rtl: loading '%s'\n", name);
441
442  /*
443   * See if the object module has already been loaded.
444   */
445  obj = rtems_rtl_find_obj (name);
446  if (!obj)
447  {
448    /*
449     * Allocate a new object file descriptor and attempt to load it.
450     */
451    obj = rtems_rtl_obj_alloc ();
452    if (obj == NULL)
453    {
454      rtems_rtl_set_error (ENOMEM, "no memory for object descriptor");
455      return NULL;
456    }
457
458    /*
459     * Find the file in the file system using the search path. The fname field
460     * will point to a valid file name if found.
461     */
462    if (!rtems_rtl_obj_find_file (obj, name))
463    {
464      rtems_rtl_obj_free (obj);
465      rtems_rtl_obj_caches_flush ();
466      return NULL;
467    }
468
469    rtems_chain_append (&rtl->objects, &obj->link);
470
471    if (!rtems_rtl_obj_load (obj))
472    {
473      rtems_rtl_obj_free (obj);
474      rtems_rtl_obj_caches_flush ();
475      return NULL;
476    }
477
478    rtems_rtl_obj_caches_flush ();
479
480    rtems_rtl_unresolved_resolve ();
481  }
482
483  /*
484   * Increase the number of users.
485   */
486  ++obj->users;
487
488  /*
489   * FIXME: Resolving existing unresolved symbols could add more constructors
490   *        lists that need to be called. Make a list in the obj load layer and
491   *        invoke the list here.
492   */
493
494  /*
495   * Run any local constructors if this is the first user because the object
496   * file will have just been loaded. Unlock the linker to avoid any dead locks
497   * if the object file needs to load files or update the symbol table. We also
498   * do not want a constructor to unload this object file.
499   */
500  if (obj->users == 1)
501  {
502    obj->flags |= RTEMS_RTL_OBJ_LOCKED;
503    rtems_rtl_unlock ();
504    rtems_rtl_obj_run_ctors (obj);
505    rtems_rtl_lock ();
506    obj->flags &= ~RTEMS_RTL_OBJ_LOCKED;
507  }
508
509  return obj;
510}
511
512bool
513rtems_rtl_unload_object (rtems_rtl_obj_t* obj)
514{
515  bool ok = true;
516
517  if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNLOAD))
518    printf ("rtl: unloading '%s'\n", rtems_rtl_obj_fname (obj));
519
520  /*
521   * If the object is locked it cannot be unloaded and the unload fails.
522   */
523  if ((obj->flags & RTEMS_RTL_OBJ_LOCKED) == RTEMS_RTL_OBJ_LOCKED)
524  {
525    rtems_rtl_set_error (EINVAL, "cannot unload when locked");
526    return false;
527  }
528
529  /*
530   * Check the number of users in a safe manner. If this is the last user unload the
531   * object file from memory.
532   */
533  if (obj->users > 0)
534    --obj->users;
535
536  if (obj->users == 0)
537  {
538    obj->flags |= RTEMS_RTL_OBJ_LOCKED;
539    rtems_rtl_unlock ();
540    rtems_rtl_obj_run_dtors (obj);
541    rtems_rtl_lock ();
542    obj->flags &= ~RTEMS_RTL_OBJ_LOCKED;
543
544    ok = rtems_rtl_obj_unload (obj);
545
546    rtems_rtl_obj_free (obj);
547    rtems_rtl_obj_caches_flush ();
548  }
549
550  return ok;
551}
552
553void
554rtems_rtl_run_ctors (rtems_rtl_obj_t* obj)
555{
556  rtems_rtl_obj_run_ctors (obj);
557}
558
559static bool
560rtems_rtl_path_update (bool prepend, const char* path)
561{
562  char*       paths;
563  const char* src = NULL;
564  char*       dst;
565  int         len;
566
567  if (!rtems_rtl_lock ())
568    return false;
569
570  len = strlen (path);
571
572  if (rtl->paths)
573    len += strlen (rtl->paths) + 1;
574  else
575    prepend = true;
576
577  paths = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, len + 1, false);
578
579  if (!paths)
580  {
581    rtems_rtl_unlock ();
582    return false;
583  }
584
585  dst = paths;
586
587  if (prepend)
588  {
589    len = strlen (path);
590    src = path;
591  }
592  else if (rtl->paths)
593  {
594    len = strlen (rtl->paths);
595    src = rtl->paths;
596  }
597
598  memcpy (dst, src, len);
599
600  dst += len;
601
602  if (rtl->paths)
603  {
604    *dst = ':';
605    ++dst;
606  }
607
608  if (prepend)
609  {
610    src = rtl->paths;
611    if (src)
612      len = strlen (src);
613  }
614  else
615  {
616    len = strlen (path);
617    src = path;
618  }
619
620  if (src)
621  {
622    memcpy (dst, src, len);
623    dst += len;
624  }
625
626  *dst = '\0';
627
628  rtl->paths = paths;
629
630  rtems_rtl_unlock ();
631  return false;
632}
633
634bool
635rtems_rtl_path_append (const char* path)
636{
637  return rtems_rtl_path_update (false, path);
638}
639
640bool
641rtems_rtl_path_prepend (const char* path)
642{
643  return rtems_rtl_path_update (true, path);
644}
645
646void
647rtems_rtl_base_sym_global_add (const unsigned char* esyms,
648                               unsigned int         size)
649{
650  if (rtems_rtl_trace (RTEMS_RTL_TRACE_GLOBAL_SYM))
651    printf ("rtl: adding global symbols, table size %u\n", size);
652
653  if (!rtems_rtl_lock ())
654  {
655    rtems_rtl_set_error (EINVAL, "global add cannot lock rtl");
656    return;
657  }
658
659  rtems_rtl_symbol_global_add (rtl->base, esyms, size);
660
661  rtems_rtl_unlock ();
662}
663
664rtems_rtl_obj_t*
665rtems_rtl_baseimage (void)
666{
667  return NULL;
668}
Note: See TracBrowser for help on using the repository browser.