source: rtems/cpukit/libdl/rtl-obj.c @ 03139d5b

5
Last change on this file since 03139d5b was 03139d5b, checked in by Chris Johns <chrisj@…>, on Nov 20, 2018 at 3:56:11 AM

libdl: Add object file dependencies to track references

Tracking references lets us manage when an object file can be
unloaded. If an object file has references to it, it cannot be
unloaded.

Modules that depend on each other cannot be unloaded.

Updates #3605

  • Property mode set to 100644
File size: 39.1 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 rtl
12 *
13 * @brief RTEMS Run-Time Linker Error
14 */
15
16#if HAVE_CONFIG_H
17#include "config.h"
18#endif
19
20#include <errno.h>
21#include <inttypes.h>
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 "rtl-chain-iterator.h"
30#include <rtems/rtl/rtl-obj.h>
31#include "rtl-error.h"
32#include "rtl-find-file.h"
33#include "rtl-string.h"
34#include <rtems/rtl/rtl-trace.h>
35
36#define RTEMS_RTL_ELF_LOADER 1
37#define RTEMS_RTL_RAP_LOADER 1
38
39#if RTEMS_RTL_RAP_LOADER
40#include "rtl-rap.h"
41#define RTEMS_RTL_RAP_LOADER_COUNT 1
42#else
43#define RTEMS_RTL_RAP_LOADER_COUNT 0
44#endif
45
46#if RTEMS_RTL_ELF_LOADER
47#include "rtl-elf.h"
48#define RTEMS_RTL_ELF_LOADER_COUNT 1
49#else
50#define RTEMS_RTL_ELF_LOADER_COUNT 0
51#endif
52
53/**
54 * The table of supported loader formats.
55 */
56#define RTEMS_RTL_LOADERS (RTEMS_RTL_ELF_LOADER_COUNT + RTEMS_RTL_RAP_LOADER_COUNT)
57static const rtems_rtl_loader_table loaders[RTEMS_RTL_LOADERS] =
58{
59#if RTEMS_RTL_RAP_LOADER
60  { .check     = rtems_rtl_rap_file_check,
61    .load      = rtems_rtl_rap_file_load,
62    .unload    = rtems_rtl_rap_file_unload,
63    .unload    = rtems_rtl_rap_file_unload,
64    .signature = rtems_rtl_rap_file_sig },
65#endif
66#if RTEMS_RTL_ELF_LOADER
67  { .check     = rtems_rtl_elf_file_check,
68    .load      = rtems_rtl_elf_file_load,
69    .unload    = rtems_rtl_elf_file_unload,
70    .signature = rtems_rtl_elf_file_sig },
71#endif
72};
73
74rtems_rtl_obj*
75rtems_rtl_obj_alloc (void)
76{
77  rtems_rtl_obj* obj = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT,
78                                            sizeof (rtems_rtl_obj),
79                                            true);
80  if (obj)
81  {
82    /*
83     * Initialise the chains.
84     */
85    rtems_chain_initialize_empty (&obj->sections);
86    rtems_chain_initialize_empty (&obj->dependents);
87    /*
88     * No valid format.
89     */
90    obj->format = -1;
91  }
92  return obj;
93}
94
95static void
96rtems_rtl_obj_free_names (rtems_rtl_obj* obj)
97{
98  if (rtems_rtl_obj_oname_valid (obj))
99    rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, (void*) obj->oname);
100  if (rtems_rtl_obj_aname_valid (obj))
101    rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, (void*) obj->aname);
102  if (rtems_rtl_obj_fname_valid (obj))
103    rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, (void*) obj->fname);
104}
105
106bool
107rtems_rtl_obj_free (rtems_rtl_obj* obj)
108{
109  if (obj->users || ((obj->flags & RTEMS_RTL_OBJ_LOCKED) != 0))
110  {
111    rtems_rtl_set_error (EINVAL, "cannot free obj still in use");
112    return false;
113  }
114  if (!rtems_chain_is_node_off_chain (&obj->link))
115    rtems_chain_extract (&obj->link);
116  rtems_rtl_alloc_module_del (&obj->text_base, &obj->const_base, &obj->eh_base,
117                              &obj->data_base, &obj->bss_base);
118  rtems_rtl_obj_erase_sections (obj);
119  rtems_rtl_obj_erase_dependents (obj);
120  rtems_rtl_symbol_obj_erase (obj);
121  rtems_rtl_obj_free_names (obj);
122  if (obj->sec_num)
123    free (obj->sec_num);
124  if (obj->linkmap)
125    rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, (void*) obj->linkmap);
126  rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, obj);
127  return true;
128}
129
130bool
131rtems_rtl_obj_unresolved (rtems_rtl_obj* obj)
132{
133  return (obj->flags & RTEMS_RTL_OBJ_UNRESOLVED) != 0 ? true : false;
134}
135
136bool
137rtems_rtl_parse_name (const char*  name,
138                      const char** aname,
139                      const char** oname,
140                      off_t*       ooffset)
141{
142  const char* laname = NULL;
143  const char* loname = NULL;
144  const char* colon;
145  const char* end;
146
147  /*
148   * Parse the name to determine if the object file is part of an archive or it
149   * is an object file. If an archive check the name for a '@' to see if the
150   * archive contains an offset.
151   */
152  end = name + strlen (name);
153  colon = strrchr (name, ':');
154  if (colon == NULL || colon < strrchr(name, '/'))
155    colon = end;
156
157  loname = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, colon - name + 1, true);
158  if (!oname)
159  {
160    rtems_rtl_set_error (ENOMEM, "no memory for object file name");
161    return false;
162  }
163
164  memcpy ((void*) loname, name, colon - name);
165
166  /*
167   * If the pointers match there is no ':' delimiter.
168   */
169  if (colon != end)
170  {
171    const char* at;
172
173    /*
174     * The file name is an archive and the object file name is next after the
175     * delimiter. Move the pointer to the archive name.
176     */
177    laname = loname;
178    ++colon;
179
180    /*
181     * See if there is a '@' to delimit an archive offset for the object in the
182     * archive.
183     */
184    at = strchr (colon, '@');
185
186    if (at == NULL)
187      at = end;
188
189
190    loname = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, at - colon + 1, true);
191    if (!loname)
192    {
193      rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, (void*) laname);
194      rtems_rtl_set_error (ENOMEM, "no memory for object file name");
195      return false;
196    }
197
198    memcpy ((void*) loname, colon, at - colon);
199
200    if (at != end)
201    {
202      /*
203       * The object name has an archive offset. If the number
204       * does not parse 0 will be returned and the archive will be
205       * searched.
206       */
207      *ooffset = strtoul (at + 1, 0, 0);
208    }
209  }
210
211  *oname = loname;
212  *aname = laname;
213  return true;
214}
215
216static bool
217rtems_rtl_obj_parse_name (rtems_rtl_obj* obj, const char* name)
218{
219  return rtems_rtl_parse_name (name, &(obj->aname), &(obj->oname), &(obj->ooffset));
220}
221
222static bool
223rtems_rtl_seek_read (int fd, off_t off, size_t len, uint8_t* buffer)
224{
225  if (lseek (fd, off, SEEK_SET) < 0)
226    return false;
227  if (read (fd, buffer, len) != len)
228    return false;
229  return true;
230}
231
232/**
233 * Scan the decimal number returning the value found.
234 */
235static uint64_t
236rtems_rtl_scan_decimal (const uint8_t* string, size_t len)
237{
238  uint64_t value = 0;
239
240  while (len && (*string != ' '))
241  {
242    value *= 10;
243    value += *string - '0';
244    ++string;
245    --len;
246  }
247
248  return value;
249}
250
251/**
252 * Section size summer iterator data.
253 */
254typedef struct
255{
256  uint32_t mask; /**< The selection mask to sum. */
257  size_t   size; /**< The size of all section fragments. */
258} rtems_rtl_obj_sect_summer_data;
259
260static bool
261rtems_rtl_obj_sect_summer (rtems_chain_node* node, void* data)
262{
263  rtems_rtl_obj_sect*             sect = (rtems_rtl_obj_sect*) node;
264  rtems_rtl_obj_sect_summer_data* summer = data;
265  if ((sect->flags & summer->mask) == summer->mask)
266    summer->size =
267      rtems_rtl_obj_align (summer->size, sect->alignment) + sect->size;
268  return true;
269}
270
271static size_t
272rtems_rtl_obj_section_size (const rtems_rtl_obj* obj, uint32_t mask)
273{
274  rtems_rtl_obj_sect_summer_data summer;
275  summer.mask = mask;
276  summer.size = 0;
277  rtems_rtl_chain_iterate ((rtems_chain_control*) &obj->sections,
278                           rtems_rtl_obj_sect_summer,
279                           &summer);
280  return summer.size;
281}
282
283/**
284 * Section alignment iterator data. The first section's alignment sets the
285 * alignment for that type of section.
286 */
287typedef struct
288{
289  uint32_t mask;      /**< The selection mask to look for alignment. */
290  uint32_t alignment; /**< The alignment of the section type. */
291} rtems_rtl_obj_sect_aligner_data;
292
293/**
294 * The section aligner iterator.
295 */
296static bool
297rtems_rtl_obj_sect_aligner (rtems_chain_node* node, void* data)
298{
299  rtems_rtl_obj_sect*              sect = (rtems_rtl_obj_sect*) node;
300  rtems_rtl_obj_sect_aligner_data* aligner = data;
301  if ((sect->flags & aligner->mask) == aligner->mask)
302  {
303    aligner->alignment = sect->alignment;
304    return false;
305  }
306  return true;
307}
308
309static size_t
310rtems_rtl_obj_section_alignment (const rtems_rtl_obj* obj, uint32_t mask)
311{
312  rtems_rtl_obj_sect_aligner_data aligner;
313  aligner.mask = mask;
314  aligner.alignment = 0;
315  rtems_rtl_chain_iterate ((rtems_chain_control*) &obj->sections,
316                           rtems_rtl_obj_sect_aligner,
317                           &aligner);
318  return aligner.alignment;
319}
320
321static bool
322rtems_rtl_obj_section_handler (uint32_t                   mask,
323                               rtems_rtl_obj*             obj,
324                               int                        fd,
325                               rtems_rtl_obj_sect_handler handler,
326                               void*                      data)
327{
328  rtems_chain_node* node = rtems_chain_first (&obj->sections);
329  while (!rtems_chain_is_tail (&obj->sections, node))
330  {
331    rtems_rtl_obj_sect* sect = (rtems_rtl_obj_sect*) node;
332    if ((sect->flags & mask) != 0)
333    {
334      if (!handler (obj, fd, sect, data))
335        return false;
336    }
337    node = rtems_chain_next (node);
338  }
339  return true;
340}
341
342bool
343rtems_rtl_match_name (rtems_rtl_obj* obj, const char* name)
344{
345  const char* n1 = obj->oname;
346  while ((*n1 != '\0') && (*n1 != '\n') && (*n1 != '/') &&
347         (*name != '\0') && (*name != '/') && (*n1 == *name))
348  {
349    ++n1;
350    ++name;
351  }
352  if (((*n1 == '\0') || (*n1 == '\n') || (*n1 == '/')) &&
353      ((*name == '\0') || (*name == '/')))
354    return true;
355  return false;
356}
357
358bool
359rtems_rtl_obj_find_file (rtems_rtl_obj* obj, const char* name)
360{
361  const char*     pname;
362  rtems_rtl_data* rtl;
363
364  /*
365   * Parse the name. The object descriptor will have the archive name and/or
366   * object name fields filled in. A find of the file will result in the file
367   * name (fname) field pointing to the actual file if present on the file
368   * system.
369   */
370  if (!rtems_rtl_obj_parse_name (obj, name))
371    return false;
372
373  /*
374   * If the archive field (aname) is set we use that name else we use the
375   * object field (oname). If selected name is absolute we just point the aname
376   * field to the fname field to that name. If the field is relative we search
377   * the paths set in the RTL for the file.
378   */
379  if (rtems_rtl_obj_aname_valid (obj))
380    pname = rtems_rtl_obj_aname (obj);
381  else
382    pname = rtems_rtl_obj_oname (obj);
383
384  rtl = rtems_rtl_lock ();
385
386  if (!rtems_rtl_find_file (pname, rtl->paths, &obj->fname, &obj->fsize))
387  {
388    rtems_rtl_set_error (ENOENT, "file not found");
389    rtems_rtl_unlock ();
390    return false;
391  }
392
393  rtems_rtl_unlock ();
394
395  return true;
396}
397
398bool
399rtems_rtl_obj_add_section (rtems_rtl_obj* obj,
400                           int            section,
401                           const char*    name,
402                           size_t         size,
403                           off_t          offset,
404                           uint32_t       alignment,
405                           int            link,
406                           int            info,
407                           uint32_t       flags)
408{
409  if (size > 0)
410  {
411    rtems_rtl_obj_sect* sect = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT,
412                                                    sizeof (rtems_rtl_obj_sect),
413                                                    true);
414    if (!sect)
415    {
416      rtems_rtl_set_error (ENOMEM, "adding allocated section");
417      return false;
418    }
419    sect->section = section;
420    sect->name = rtems_rtl_strdup (name);
421    sect->size = size;
422    sect->offset = offset;
423    sect->alignment = alignment;
424    sect->link = link;
425    sect->info = info;
426    sect->flags = flags;
427    sect->base = NULL;
428    rtems_chain_append (&obj->sections, &sect->node);
429
430    if (rtems_rtl_trace (RTEMS_RTL_TRACE_SECTION))
431      printf ("rtl: sect: add: %-2d: %s (%zu) 0x%08lx\n",
432              section, name, size, flags);
433  }
434  return true;
435}
436
437void
438rtems_rtl_obj_erase_sections (rtems_rtl_obj* obj)
439{
440  rtems_chain_node* node = rtems_chain_first (&obj->sections);
441  while (!rtems_chain_is_tail (&obj->sections, node))
442  {
443    rtems_rtl_obj_sect* sect = (rtems_rtl_obj_sect*) node;
444    rtems_chain_node*   next_node = rtems_chain_next (node);
445    rtems_chain_extract (node);
446    rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, (void*) sect->name);
447    rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, sect);
448    node = next_node;
449  }
450}
451
452/**
453 * Section finder iterator data.
454 */
455typedef struct
456{
457  rtems_rtl_obj_sect*  sect;  /**< The matching section. */
458  const char*          name;  /**< The name to match. */
459  int                  index; /**< The index to match. */
460  uint32_t             mask;  /**< The mask to match. */
461  unsigned int         flags; /**< The flags to use when matching. */
462} rtems_rtl_obj_sect_finder;
463
464static bool
465rtems_rtl_obj_sect_match_name (rtems_chain_node* node, void* data)
466{
467  rtems_rtl_obj_sect*        sect = (rtems_rtl_obj_sect*) node;
468  rtems_rtl_obj_sect_finder* match = data;
469  if (strcmp (sect->name, match->name) == 0)
470  {
471    match->sect = sect;
472    return false;
473  }
474  return true;
475}
476
477rtems_rtl_obj_sect*
478rtems_rtl_obj_find_section (const rtems_rtl_obj* obj,
479                            const char*          name)
480{
481  rtems_rtl_obj_sect_finder match;
482  match.sect = NULL;
483  match.name = name;
484  match.mask = 0;
485  match.flags = 0;
486  rtems_rtl_chain_iterate ((rtems_chain_control*) &obj->sections,
487                           rtems_rtl_obj_sect_match_name,
488                           &match);
489  return match.sect;
490}
491
492static bool
493rtems_rtl_obj_sect_match_index (rtems_chain_node* node, void* data)
494{
495  rtems_rtl_obj_sect*        sect = (rtems_rtl_obj_sect*) node;
496  rtems_rtl_obj_sect_finder* match = data;
497  if (sect->section == match->index)
498  {
499    match->sect = sect;
500    return false;
501  }
502  return true;
503}
504
505rtems_rtl_obj_sect*
506rtems_rtl_obj_find_section_by_index (const rtems_rtl_obj* obj,
507                                     int                  index)
508{
509  rtems_rtl_obj_sect_finder match;
510  match.sect = NULL;
511  match.index = index;
512  match.mask = 0;
513  match.flags = 0;
514  rtems_rtl_chain_iterate ((rtems_chain_control*) &obj->sections,
515                           rtems_rtl_obj_sect_match_index,
516                           &match);
517  return match.sect;
518}
519
520static bool
521rtems_rtl_obj_sect_match_mask (rtems_chain_node* node, void* data)
522{
523  rtems_rtl_obj_sect*        sect = (rtems_rtl_obj_sect*) node;
524  rtems_rtl_obj_sect_finder* match = data;
525  if (match->flags == 0)
526  {
527    if (match->index < 0 || sect->section == match->index)
528      match->flags = 1;
529    if (match->index >= 0)
530      return true;
531  }
532  if ((sect->flags & match->mask) != 0)
533  {
534    match->sect = sect;
535    return false;
536  }
537  return true;
538}
539
540rtems_rtl_obj_sect*
541rtems_rtl_obj_find_section_by_mask (const rtems_rtl_obj* obj,
542                                    int                  index,
543                                    uint32_t             mask)
544{
545  rtems_rtl_obj_sect_finder match;
546  match.sect = NULL;
547  match.index = index;
548  match.mask = mask;
549  match.flags = 0;
550  rtems_rtl_chain_iterate ((rtems_chain_control*) &obj->sections,
551                           rtems_rtl_obj_sect_match_mask,
552                           &match);
553  return match.sect;
554}
555
556bool
557rtems_rtl_obj_alloc_dependents (rtems_rtl_obj* obj, size_t dependents)
558{
559  rtems_rtl_obj_depends* depends;
560  size_t                 size;
561
562  size = sizeof (rtems_rtl_obj_depends) + sizeof (rtems_rtl_obj*) * dependents;
563
564  depends = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT,
565                                 size,
566                                 true);
567  if (depends == NULL)
568  {
569    rtems_rtl_set_error (ENOMEM, "no memory for the dependency");
570  }
571  else
572  {
573    depends->dependents = dependents;
574    rtems_chain_append (&obj->dependents, &depends->node);
575  }
576
577  return depends != NULL;
578}
579
580void
581rtems_rtl_obj_erase_dependents (rtems_rtl_obj* obj)
582{
583  rtems_chain_node* node = rtems_chain_first (&obj->dependents);
584  while (!rtems_chain_is_tail (&obj->dependents, node))
585  {
586    rtems_rtl_obj_depends* depends = (rtems_rtl_obj_depends*) node;
587    rtems_chain_node*      next_node = rtems_chain_next (node);
588    rtems_chain_extract (node);
589    rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, depends);
590    node = next_node;
591  }
592}
593
594bool
595rtems_rtl_obj_add_dependent (rtems_rtl_obj* obj, rtems_rtl_obj* dependent)
596{
597  rtems_rtl_obj**   free_slot;
598  rtems_chain_node* node;
599  if (obj == dependent || dependent == rtems_rtl_baseimage ())
600    return false;
601  free_slot = NULL;
602  node = rtems_chain_first (&obj->dependents);
603  while (!rtems_chain_is_tail (&obj->dependents, node))
604  {
605    rtems_rtl_obj_depends* depends = (rtems_rtl_obj_depends*) node;
606    size_t                 d;
607    for (d = 0; d < depends->dependents; ++d)
608    {
609      if (free_slot == NULL && depends->depends[d] == NULL)
610        free_slot = &(depends->depends[d]);
611      if (depends->depends[d] == dependent)
612        return false;
613    }
614    node = rtems_chain_next (node);
615  }
616  if (free_slot == NULL)
617  {
618    if (rtems_rtl_obj_alloc_dependents (obj,
619                                        RTEMS_RTL_DEPENDENCY_BLOCK_SIZE))
620    {
621      rtems_rtl_obj_depends* depends;
622      node = rtems_chain_last (&obj->dependents);
623      depends = (rtems_rtl_obj_depends*) node;
624      free_slot = &(depends->depends[0]);
625      if (*free_slot != NULL)
626      {
627        rtems_rtl_set_error (EINVAL, "new dependency node not empty");
628        free_slot = NULL;
629      }
630    }
631  }
632  if (free_slot != NULL)
633    *free_slot = dependent;
634  return free_slot != NULL;
635}
636
637bool
638rtems_rtl_obj_iterate_dependents (rtems_rtl_obj*                 obj,
639                                  rtems_rtl_obj_depends_iterator iterator,
640                                  void*                          data)
641{
642  rtems_chain_node* node = rtems_chain_first (&obj->dependents);
643  while (!rtems_chain_is_tail (&obj->dependents, node))
644  {
645    rtems_rtl_obj_depends* depends = (rtems_rtl_obj_depends*) node;
646    size_t                 d;
647    for (d = 0; d < depends->dependents; ++d)
648    {
649      if (depends->depends[d])
650      {
651        if (iterator (obj, depends->depends[d], data))
652          return true;
653      }
654    }
655    node = rtems_chain_next (node);
656  }
657  return false;
658}
659
660size_t
661rtems_rtl_obj_text_size (const rtems_rtl_obj* obj)
662{
663  return rtems_rtl_obj_section_size (obj, RTEMS_RTL_OBJ_SECT_TEXT);
664}
665
666uint32_t
667rtems_rtl_obj_text_alignment (const rtems_rtl_obj* obj)
668{
669  return rtems_rtl_obj_section_alignment (obj, RTEMS_RTL_OBJ_SECT_TEXT);
670}
671
672size_t
673rtems_rtl_obj_const_size (const rtems_rtl_obj* obj)
674{
675  return rtems_rtl_obj_section_size (obj, RTEMS_RTL_OBJ_SECT_CONST);
676}
677
678uint32_t
679rtems_rtl_obj_eh_alignment (const rtems_rtl_obj* obj)
680{
681  return rtems_rtl_obj_section_alignment (obj, RTEMS_RTL_OBJ_SECT_EH);
682}
683
684size_t
685rtems_rtl_obj_eh_size (const rtems_rtl_obj* obj)
686{
687  return rtems_rtl_obj_section_size (obj, RTEMS_RTL_OBJ_SECT_EH);
688}
689
690uint32_t
691rtems_rtl_obj_const_alignment (const rtems_rtl_obj* obj)
692{
693  return rtems_rtl_obj_section_alignment (obj, RTEMS_RTL_OBJ_SECT_CONST);
694}
695
696size_t
697rtems_rtl_obj_data_size (const rtems_rtl_obj* obj)
698{
699  return rtems_rtl_obj_section_size (obj, RTEMS_RTL_OBJ_SECT_DATA);
700}
701
702uint32_t
703rtems_rtl_obj_data_alignment (const rtems_rtl_obj* obj)
704{
705  return rtems_rtl_obj_section_alignment (obj, RTEMS_RTL_OBJ_SECT_DATA);
706}
707
708size_t
709rtems_rtl_obj_bss_size (const rtems_rtl_obj* obj)
710{
711  return rtems_rtl_obj_section_size (obj, RTEMS_RTL_OBJ_SECT_BSS);
712}
713
714uint32_t
715rtems_rtl_obj_bss_alignment (const rtems_rtl_obj* obj)
716{
717  return rtems_rtl_obj_section_alignment (obj, RTEMS_RTL_OBJ_SECT_BSS);
718}
719
720bool
721rtems_rtl_obj_relocate (rtems_rtl_obj*             obj,
722                        int                        fd,
723                        rtems_rtl_obj_sect_handler handler,
724                        void*                      data)
725{
726  uint32_t mask = RTEMS_RTL_OBJ_SECT_REL | RTEMS_RTL_OBJ_SECT_RELA;
727  return rtems_rtl_obj_section_handler (mask, obj, fd, handler, data);
728}
729
730/**
731 * Cache synchronization after runtime object load (dlopen)
732 */
733typedef struct
734{
735  uint32_t mask;
736  void     *start_va;
737  void     *end_va;
738  size_t   cache_line_size;
739} rtems_rtl_obj_sect_sync_ctx;
740
741static bool
742rtems_rtl_obj_sect_sync_handler (rtems_chain_node* node, void* data)
743{
744  rtems_rtl_obj_sect*          sect = (rtems_rtl_obj_sect*) node;
745  rtems_rtl_obj_sect_sync_ctx* sync_ctx = data;
746  uintptr_t                    old_end;
747  uintptr_t                    new_start;
748
749  if ((sect->flags & sync_ctx->mask) == 0 || sect->size == 0)
750    return true;
751
752  if (sync_ctx->end_va == sync_ctx->start_va)
753  {
754    sync_ctx->start_va = sect->base;
755  }
756  else
757  {
758    old_end = (uintptr_t) sync_ctx->end_va & ~(sync_ctx->cache_line_size - 1);
759    new_start = (uintptr_t) sect->base & ~(sync_ctx->cache_line_size - 1);
760    if ((sect->base <  sync_ctx->start_va) ||
761        (new_start - old_end > sync_ctx->cache_line_size))
762    {
763      rtems_cache_instruction_sync_after_code_change(sync_ctx->start_va,
764                             sync_ctx->end_va - sync_ctx->start_va + 1);
765      sync_ctx->start_va = sect->base;
766    }
767  }
768
769  sync_ctx->end_va = sect->base + sect->size;
770
771  return true;
772}
773
774void
775rtems_rtl_obj_synchronize_cache (rtems_rtl_obj* obj)
776{
777  rtems_rtl_obj_sect_sync_ctx sync_ctx;
778
779  if (rtems_cache_get_instruction_line_size() == 0)
780    return;
781
782  sync_ctx.cache_line_size = rtems_cache_get_maximal_line_size();
783
784  sync_ctx.mask = RTEMS_RTL_OBJ_SECT_TEXT | RTEMS_RTL_OBJ_SECT_CONST |
785                  RTEMS_RTL_OBJ_SECT_DATA | RTEMS_RTL_OBJ_SECT_BSS |
786                  RTEMS_RTL_OBJ_SECT_EH   | RTEMS_RTL_OBJ_SECT_EXEC;
787
788  sync_ctx.start_va = 0;
789  sync_ctx.end_va = sync_ctx.start_va;
790  rtems_rtl_chain_iterate (&obj->sections,
791                           rtems_rtl_obj_sect_sync_handler,
792                           &sync_ctx);
793
794  if (sync_ctx.end_va != sync_ctx.start_va) {
795    rtems_cache_instruction_sync_after_code_change(sync_ctx.start_va,
796                              sync_ctx.end_va - sync_ctx.start_va);
797  }
798}
799
800bool
801rtems_rtl_obj_load_symbols (rtems_rtl_obj*             obj,
802                            int                        fd,
803                            rtems_rtl_obj_sect_handler handler,
804                            void*                      data)
805{
806  uint32_t mask = RTEMS_RTL_OBJ_SECT_SYM;
807  return rtems_rtl_obj_section_handler (mask, obj, fd, handler, data);
808}
809
810static int
811rtems_rtl_obj_sections_linked_to_order (rtems_rtl_obj* obj,
812                                        int            section,
813                                        uint32_t       visited_mask)
814{
815  rtems_chain_control* sections = &obj->sections;
816  rtems_chain_node*    node = rtems_chain_first (sections);
817  /*
818   * Find the section being linked-to. If the linked-to link field is 0 we have
819   * the end and the section's order is the position we are after.
820   */
821  while (!rtems_chain_is_tail (sections, node))
822  {
823    rtems_rtl_obj_sect* sect = (rtems_rtl_obj_sect*) node;
824    if (sect->section == section)
825    {
826      const uint32_t mask = sect->flags & RTEMS_RTL_OBJ_SECT_TYPES;
827      int            order = 0;
828      if (sect->link != 0)
829      {
830        /*
831         * Have we already visited this type of section? Avoid nesting for
832         * ever.
833         */
834        if ((sect->flags & visited_mask) != 0)
835        {
836          rtems_rtl_set_error (errno, "section link loop");
837          return -1;
838        }
839        return rtems_rtl_obj_sections_linked_to_order (obj,
840                                                       sect->link,
841                                                       visited_mask | mask);
842      }
843      node = rtems_chain_first (sections);
844      while (!rtems_chain_is_tail (sections, node))
845      {
846        sect = (rtems_rtl_obj_sect*) node;
847        if ((sect->flags & mask) == mask)
848        {
849          if (sect->section == section)
850            return order;
851          ++order;
852        }
853        node = rtems_chain_next (node);
854      }
855    }
856    node = rtems_chain_next (node);
857  }
858  rtems_rtl_set_error (errno, "section link not found");
859  return -1;
860}
861
862static void
863rtems_rtl_obj_sections_link_order (uint32_t mask, rtems_rtl_obj* obj)
864{
865  rtems_chain_control* sections = &obj->sections;
866  rtems_chain_node*    node = rtems_chain_first (sections);
867  int                  order = 0;
868  while (!rtems_chain_is_tail (sections, node))
869  {
870    rtems_rtl_obj_sect* sect = (rtems_rtl_obj_sect*) node;
871    if ((sect->flags & mask) == mask)
872    {
873      /*
874       * If the section is linked in order find the linked-to section's order
875       * and move the section in the section list to
876       */
877      if (sect->link == 0)
878        sect->load_order = order++;
879      else
880      {
881        sect->load_order =
882          rtems_rtl_obj_sections_linked_to_order (obj,
883                                                  sect->link,
884                                                  mask);
885      }
886    }
887    node = rtems_chain_next (node);
888  }
889}
890
891static size_t
892rtems_rtl_obj_sections_loader (uint32_t                   mask,
893                               rtems_rtl_obj*             obj,
894                               int                        fd,
895                               uint8_t*                   base,
896                               rtems_rtl_obj_sect_handler handler,
897                               void*                      data)
898{
899  rtems_chain_control* sections = &obj->sections;
900  rtems_chain_node*    node = rtems_chain_first (sections);
901  size_t               base_offset = 0;
902  bool                 first = true;
903  int                  order = 0;
904
905  while (!rtems_chain_is_tail (sections, node))
906  {
907    rtems_rtl_obj_sect* sect = (rtems_rtl_obj_sect*) node;
908
909    if ((sect->size != 0) && ((sect->flags & mask) != 0))
910    {
911      if (sect->load_order == order)
912      {
913        if (!first)
914          base_offset = rtems_rtl_obj_align (base_offset, sect->alignment);
915
916        first = false;
917
918        sect->base = base + base_offset;
919
920        if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD_SECT))
921          printf ("rtl: loading:%2d: %s -> %8p (s:%zi f:%04" PRIx32
922                  " a:%" PRIu32 " l:%02d)\n",
923                  order, sect->name, sect->base, sect->size,
924                  sect->flags, sect->alignment, sect->link);
925
926        if ((sect->flags & RTEMS_RTL_OBJ_SECT_LOAD) == RTEMS_RTL_OBJ_SECT_LOAD)
927        {
928          if (!handler (obj, fd, sect, data))
929          {
930            sect->base = 0;
931            return false;
932          }
933        }
934        else if ((sect->flags & RTEMS_RTL_OBJ_SECT_ZERO) == RTEMS_RTL_OBJ_SECT_ZERO)
935        {
936          memset (base + base_offset, 0, sect->size);
937        }
938        else
939        {
940          sect->base = 0;
941          rtems_rtl_set_error (errno, "section has no load/clear op");
942          return false;
943        }
944
945        base_offset += sect->size;
946
947        ++order;
948
949        node = rtems_chain_first (sections);
950        continue;
951      }
952    }
953
954    node = rtems_chain_next (node);
955  }
956
957  return true;
958}
959
960bool
961rtems_rtl_obj_load_sections (rtems_rtl_obj*             obj,
962                             int                        fd,
963                             rtems_rtl_obj_sect_handler handler,
964                             void*                      data)
965{
966  size_t text_size;
967  size_t const_size;
968  size_t eh_size;
969  size_t data_size;
970  size_t bss_size;
971
972  text_size  = rtems_rtl_obj_text_size (obj) + rtems_rtl_obj_const_alignment (obj);
973  const_size = rtems_rtl_obj_const_size (obj) + rtems_rtl_obj_eh_alignment (obj);
974  eh_size    = rtems_rtl_obj_eh_size (obj) + rtems_rtl_obj_data_alignment (obj);
975  data_size  = rtems_rtl_obj_data_size (obj) + rtems_rtl_obj_bss_alignment (obj);
976  bss_size   = rtems_rtl_obj_bss_size (obj);
977
978  /*
979   * Set the sizes held in the object data. We need this for a fast reference.
980   */
981  obj->text_size = text_size;
982  obj->eh_size   = eh_size;
983  obj->bss_size  = bss_size;
984
985  /*
986   * Let the allocator manage the actual allocation. The user can use the
987   * standard heap or provide a specific allocator with memory protection.
988   */
989  if (!rtems_rtl_alloc_module_new (&obj->text_base, text_size,
990                                   &obj->const_base, const_size,
991                                   &obj->eh_base, eh_size,
992                                   &obj->data_base, data_size,
993                                   &obj->bss_base, bss_size))
994  {
995    obj->exec_size = 0;
996    rtems_rtl_set_error (ENOMEM, "no memory to load obj");
997    return false;
998  }
999
1000  obj->exec_size = text_size + const_size + eh_size + data_size + bss_size;
1001
1002  if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD_SECT))
1003  {
1004    printf ("rtl: load sect: text  - b:%p s:%zi a:%" PRIu32 "\n",
1005            obj->text_base, text_size, rtems_rtl_obj_text_alignment (obj));
1006    printf ("rtl: load sect: const - b:%p s:%zi a:%" PRIu32 "\n",
1007            obj->const_base, const_size, rtems_rtl_obj_const_alignment (obj));
1008    printf ("rtl: load sect: eh    - b:%p s:%zi a:%" PRIu32 "\n",
1009            obj->eh_base, eh_size, rtems_rtl_obj_eh_alignment (obj));
1010    printf ("rtl: load sect: data  - b:%p s:%zi a:%" PRIu32 "\n",
1011            obj->data_base, data_size, rtems_rtl_obj_data_alignment (obj));
1012    printf ("rtl: load sect: bss   - b:%p s:%zi a:%" PRIu32 "\n",
1013            obj->bss_base, bss_size, rtems_rtl_obj_bss_alignment (obj));
1014  }
1015
1016  /*
1017   * Determine the load order.
1018   */
1019  rtems_rtl_obj_sections_link_order (RTEMS_RTL_OBJ_SECT_TEXT,  obj);
1020  rtems_rtl_obj_sections_link_order (RTEMS_RTL_OBJ_SECT_CONST, obj);
1021  rtems_rtl_obj_sections_link_order (RTEMS_RTL_OBJ_SECT_EH,    obj);
1022  rtems_rtl_obj_sections_link_order (RTEMS_RTL_OBJ_SECT_DATA,  obj);
1023
1024  /*
1025   * Load all text then data then bss sections in seperate operations so each
1026   * type of section is grouped together.
1027   */
1028  if (!rtems_rtl_obj_sections_loader (RTEMS_RTL_OBJ_SECT_TEXT,
1029                                      obj, fd, obj->text_base, handler, data) ||
1030      !rtems_rtl_obj_sections_loader (RTEMS_RTL_OBJ_SECT_CONST,
1031                                      obj, fd, obj->const_base, handler, data) ||
1032      !rtems_rtl_obj_sections_loader (RTEMS_RTL_OBJ_SECT_EH,
1033                                      obj, fd, obj->eh_base, handler, data) ||
1034      !rtems_rtl_obj_sections_loader (RTEMS_RTL_OBJ_SECT_DATA,
1035                                      obj, fd, obj->data_base, handler, data) ||
1036      !rtems_rtl_obj_sections_loader (RTEMS_RTL_OBJ_SECT_BSS,
1037                                      obj, fd, obj->bss_base, handler, data))
1038  {
1039    rtems_rtl_alloc_module_del (&obj->text_base, &obj->const_base, &obj->eh_base,
1040                                &obj->data_base, &obj->bss_base);
1041    obj->exec_size = 0;
1042    return false;
1043  }
1044
1045  return true;
1046}
1047
1048static void
1049rtems_rtl_obj_run_cdtors (rtems_rtl_obj* obj, uint32_t mask)
1050{
1051  rtems_chain_node* node = rtems_chain_first (&obj->sections);
1052  while (!rtems_chain_is_tail (&obj->sections, node))
1053  {
1054    rtems_rtl_obj_sect* sect = (rtems_rtl_obj_sect*) node;
1055    if ((sect->flags & mask) == mask)
1056    {
1057      rtems_rtl_cdtor* handler;
1058      size_t           handlers = sect->size / sizeof (rtems_rtl_cdtor);
1059      int              c;
1060      for (c = 0, handler = sect->base; c < handlers; ++c)
1061        if (*handler)
1062          (*handler) ();
1063    }
1064    node = rtems_chain_next (node);
1065  }
1066}
1067
1068void
1069rtems_rtl_obj_run_ctors (rtems_rtl_obj* obj)
1070{
1071  return rtems_rtl_obj_run_cdtors (obj, RTEMS_RTL_OBJ_SECT_CTOR);
1072}
1073
1074void
1075rtems_rtl_obj_run_dtors (rtems_rtl_obj* obj)
1076{
1077  return rtems_rtl_obj_run_cdtors (obj, RTEMS_RTL_OBJ_SECT_DTOR);
1078}
1079
1080/**
1081 * Find a module in an archive returning the offset in the archive in the
1082 * object descriptor.
1083 */
1084static bool
1085rtems_rtl_obj_archive_find (rtems_rtl_obj* obj, int fd)
1086{
1087#define RTEMS_RTL_AR_IDENT      "!<arch>\n"
1088#define RTEMS_RTL_AR_IDENT_SIZE (sizeof (RTEMS_RTL_AR_IDENT) - 1)
1089#define RTEMS_RTL_AR_FHDR_BASE  RTEMS_RTL_AR_IDENT_SIZE
1090#define RTEMS_RTL_AR_FNAME      (0)
1091#define RTEMS_RTL_AR_FNAME_SIZE (16)
1092#define RTEMS_RTL_AR_SIZE       (48)
1093#define RTEMS_RTL_AR_SIZE_SIZE  (10)
1094#define RTEMS_RTL_AR_MAGIC      (58)
1095#define RTEMS_RTL_AR_MAGIC_SIZE (2)
1096#define RTEMS_RTL_AR_FHDR_SIZE  (60)
1097
1098  size_t  fsize = obj->fsize;
1099  off_t   extended_file_names;
1100  uint8_t header[RTEMS_RTL_AR_FHDR_SIZE];
1101  bool    scanning;
1102
1103  if (read (fd, &header[0], RTEMS_RTL_AR_IDENT_SIZE) !=  RTEMS_RTL_AR_IDENT_SIZE)
1104  {
1105    rtems_rtl_set_error (errno, "reading archive identifer");
1106    return false;
1107  }
1108
1109  if (memcmp (header, RTEMS_RTL_AR_IDENT, RTEMS_RTL_AR_IDENT_SIZE) != 0)
1110  {
1111    rtems_rtl_set_error (EINVAL, "invalid archive identifer");
1112    return false;
1113  }
1114
1115  /*
1116   * Seek to the current offset in the archive and if we have a valid archive
1117   * file header present check the file name for a match with the oname field
1118   * of the object descriptor. If the archive header is not valid and it is the
1119   * first pass reset the offset and start the search again in case the offset
1120   * provided is not valid any more.
1121   *
1122   * The archive can have a symbol table at the start. Ignore it. A symbol
1123   * table has the file name '/'.
1124   *
1125   * The archive can also have the GNU extended file name table. This
1126   * complicates the processing. If the object's file name starts with '/' the
1127   * remainder of the file name is an offset into the extended file name
1128   * table. To find the extended file name table we need to scan from start of
1129   * the archive for a file name of '//'. Once found we remeber the table's
1130   * start and can direct seek to file name location. In other words the scan
1131   * only happens once.
1132   *
1133   * If the name had the offset encoded we go straight to that location.
1134   */
1135
1136  if (obj->ooffset != 0)
1137    scanning = false;
1138  else
1139  {
1140    scanning = true;
1141    obj->ooffset = RTEMS_RTL_AR_FHDR_BASE;
1142  }
1143
1144  extended_file_names = 0;
1145
1146  while (obj->ooffset < fsize)
1147  {
1148    /*
1149     * Clean up any existing data.
1150     */
1151    memset (header, 0, sizeof (header));
1152
1153    if (!rtems_rtl_seek_read (fd, obj->ooffset, RTEMS_RTL_AR_FHDR_SIZE, &header[0]))
1154    {
1155      rtems_rtl_set_error (errno, "seek/read archive file header");
1156      obj->ooffset = 0;
1157      obj->fsize = 0;
1158      return false;
1159    }
1160
1161    if ((header[RTEMS_RTL_AR_MAGIC] != 0x60) ||
1162        (header[RTEMS_RTL_AR_MAGIC + 1] != 0x0a))
1163    {
1164      if (scanning)
1165      {
1166        rtems_rtl_set_error (EINVAL, "invalid archive file header");
1167        obj->ooffset = 0;
1168        obj->fsize = 0;
1169        return false;
1170      }
1171
1172      scanning = true;
1173      obj->ooffset = RTEMS_RTL_AR_FHDR_BASE;
1174      continue;
1175    }
1176
1177    /*
1178     * The archive header is always aligned to an even address.
1179     */
1180    obj->fsize = (rtems_rtl_scan_decimal (&header[RTEMS_RTL_AR_SIZE],
1181                                          RTEMS_RTL_AR_SIZE_SIZE) + 1) & ~1;
1182
1183    /*
1184     * Check for the GNU extensions.
1185     */
1186    if (header[0] == '/')
1187    {
1188      off_t extended_off;
1189
1190      switch (header[1])
1191      {
1192        case ' ':
1193          /*
1194           * Symbols table. Ignore the table.
1195           */
1196          break;
1197        case '/':
1198          /*
1199           * Extended file names table. Remember.
1200           */
1201          extended_file_names = obj->ooffset + RTEMS_RTL_AR_FHDR_SIZE;
1202          break;
1203        case '0':
1204        case '1':
1205        case '2':
1206        case '3':
1207        case '4':
1208        case '5':
1209        case '6':
1210        case '7':
1211        case '8':
1212        case '9':
1213          /*
1214           * Offset into the extended file name table. If we do not have the
1215           * offset to the extended file name table find it.
1216           */
1217          extended_off =
1218            rtems_rtl_scan_decimal (&header[1], RTEMS_RTL_AR_FNAME_SIZE);
1219
1220          if (extended_file_names == 0)
1221          {
1222            off_t off = obj->ooffset;
1223            while (extended_file_names == 0)
1224            {
1225              off_t esize =
1226                (rtems_rtl_scan_decimal (&header[RTEMS_RTL_AR_SIZE],
1227                                         RTEMS_RTL_AR_SIZE_SIZE) + 1) & ~1;
1228              off += esize + RTEMS_RTL_AR_FHDR_SIZE;
1229
1230              if (!rtems_rtl_seek_read (fd, off,
1231                                        RTEMS_RTL_AR_FHDR_SIZE, &header[0]))
1232              {
1233                rtems_rtl_set_error (errno,
1234                                     "seeking/reading archive ext file name header");
1235                obj->ooffset = 0;
1236                obj->fsize = 0;
1237                return false;
1238              }
1239
1240              if ((header[RTEMS_RTL_AR_MAGIC] != 0x60) ||
1241                  (header[RTEMS_RTL_AR_MAGIC + 1] != 0x0a))
1242              {
1243                rtems_rtl_set_error (errno, "invalid archive file header");
1244                obj->ooffset = 0;
1245                obj->fsize = 0;
1246                return false;
1247              }
1248
1249              if ((header[0] == '/') && (header[1] == '/'))
1250              {
1251                extended_file_names = off + RTEMS_RTL_AR_FHDR_SIZE;
1252                break;
1253              }
1254            }
1255          }
1256
1257          if (extended_file_names)
1258          {
1259            /*
1260             * We know the offset in the archive to the extended file. Read the
1261             * name from the table and compare with the name we are after.
1262             */
1263#define RTEMS_RTL_MAX_FILE_SIZE (256)
1264            char name[RTEMS_RTL_MAX_FILE_SIZE];
1265
1266            if (!rtems_rtl_seek_read (fd, extended_file_names + extended_off,
1267                                      RTEMS_RTL_MAX_FILE_SIZE, (uint8_t*) &name[0]))
1268            {
1269              rtems_rtl_set_error (errno,
1270                                   "invalid archive ext file seek/read");
1271              obj->ooffset = 0;
1272              obj->fsize = 0;
1273              return false;
1274            }
1275
1276            if (rtems_rtl_match_name (obj, name))
1277            {
1278              obj->ooffset += RTEMS_RTL_AR_FHDR_SIZE;
1279              return true;
1280            }
1281          }
1282          break;
1283        default:
1284          /*
1285           * Ignore the file because we do not know what it it.
1286           */
1287          break;
1288      }
1289    }
1290    else
1291    {
1292      if (rtems_rtl_match_name (obj, (const char*) &header[RTEMS_RTL_AR_FNAME]))
1293      {
1294        obj->ooffset += RTEMS_RTL_AR_FHDR_SIZE;
1295        return true;
1296      }
1297    }
1298
1299    obj->ooffset += obj->fsize + RTEMS_RTL_AR_FHDR_SIZE;
1300  }
1301
1302  rtems_rtl_set_error (ENOENT, "object file not found");
1303  obj->ooffset = 0;
1304  obj->fsize = 0;
1305  return false;
1306}
1307
1308static bool
1309rtems_rtl_obj_file_load (rtems_rtl_obj* obj, int fd)
1310{
1311  int l;
1312
1313  for (l = 0; l < (sizeof (loaders) / sizeof (rtems_rtl_loader_table)); ++l)
1314  {
1315    if (loaders[l].check (obj, fd))
1316    {
1317      obj->format = l;
1318      return loaders[l].load (obj, fd);
1319    }
1320  }
1321
1322  rtems_rtl_set_error (ENOENT, "no format loader found");
1323  return false;
1324}
1325
1326static bool
1327rtems_rtl_obj_file_unload (rtems_rtl_obj* obj)
1328{
1329  if (obj->format >= 0 && obj->format < RTEMS_RTL_LOADERS)
1330  {
1331    rtems_chain_node* node;
1332
1333    if (!loaders[obj->format].unload (obj))
1334      return false;
1335
1336    node = rtems_chain_first (&obj->dependents);
1337    while (!rtems_chain_is_tail (&obj->dependents, node))
1338    {
1339      rtems_rtl_obj_depends* depends = (rtems_rtl_obj_depends*) node;
1340      size_t                 d;
1341      for (d = 0; d < depends->dependents; ++d)
1342      {
1343        if (depends->depends[d] != NULL)
1344          rtems_rtl_obj_dec_reference (depends->depends[d]);
1345      }
1346      node = rtems_chain_next (node);
1347    }
1348  }
1349
1350  return false;
1351}
1352
1353void
1354rtems_rtl_obj_inc_reference (rtems_rtl_obj* obj)
1355{
1356  ++obj->refs;
1357}
1358
1359void
1360rtems_rtl_obj_dec_reference (rtems_rtl_obj* obj)
1361{
1362  if (obj->refs)
1363    --obj->refs;
1364}
1365
1366bool
1367rtems_rtl_obj_load (rtems_rtl_obj* obj)
1368{
1369  int fd;
1370
1371  if (!rtems_rtl_obj_fname_valid (obj))
1372  {
1373    rtems_rtl_set_error (ENOMEM, "invalid object file name path");
1374    return false;
1375  }
1376
1377  fd = open (rtems_rtl_obj_fname (obj), O_RDONLY);
1378  if (fd < 0)
1379  {
1380    rtems_rtl_set_error (ENOMEM, "opening for object file");
1381    return false;
1382  }
1383
1384  /*
1385   * Find the object file in the archive if it is an archive that
1386   * has been opened.
1387   */
1388  if (rtems_rtl_obj_aname_valid (obj))
1389  {
1390    if (!rtems_rtl_obj_archive_find (obj, fd))
1391    {
1392      close (fd);
1393      return false;
1394    }
1395  }
1396
1397  /*
1398   * Call the format specific loader.
1399   */
1400  if (!rtems_rtl_obj_file_load (obj, fd))
1401  {
1402    close (fd);
1403    return false;
1404  }
1405
1406  if (!_rtld_linkmap_add (obj)) /* For GDB */
1407  {
1408    close (fd);
1409    return false;
1410  }
1411
1412  close (fd);
1413
1414  return true;
1415}
1416
1417bool
1418rtems_rtl_obj_unload (rtems_rtl_obj* obj)
1419{
1420  _rtld_linkmap_delete(obj);
1421  rtems_rtl_obj_file_unload (obj);
1422  return true;
1423}
Note: See TracBrowser for help on using the repository browser.