source: rtems/cpukit/libdl/rtl-obj.c @ 5b951175

5
Last change on this file since 5b951175 was 9c12bcfd, checked in by Sebastian Huber <sebastian.huber@…>, on 01/07/19 at 08:32:16

Fix format warnings

  • 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%08" PRIu32 "\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.