source: rtems/cpukit/libdl/rtl-unresolved.c @ 8e7c72a7

5
Last change on this file since 8e7c72a7 was 8e7c72a7, checked in by Chris Johns <chrisj@…>, on 11/20/18 at 03:00:48

libdl: Reindex unresolved names after removing used records.

Updates #3194

  • Property mode set to 100644
File size: 16.3 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 rtems_rtl
12 *
13 * @brief RTEMS Run-Time Linker Object File Unresolved Relocations Table.
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/rtl/rtl.h>
27#include "rtl-error.h"
28#include <rtems/rtl/rtl-unresolved.h>
29#include <rtems/rtl/rtl-trace.h>
30
31static rtems_rtl_unresolv_block*
32rtems_rtl_unresolved_block_alloc (rtems_rtl_unresolved* unresolved)
33{
34  /*
35   * The block header contains a record.
36   */
37  size_t size =
38    (sizeof(rtems_rtl_unresolv_block) +
39     (sizeof(rtems_rtl_unresolv_rec) * (unresolved->block_recs - 1)));
40  rtems_rtl_unresolv_block* block =
41    rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_EXTERNAL, size, true);
42  if (block)
43  {
44    if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED))
45      printf ("rtl: unresolv: block-alloc %p\n", block);
46    rtems_chain_append (&unresolved->blocks, &block->link);
47  }
48  else
49    rtems_rtl_set_error (ENOMEM, "no memory for unresolved block");
50  return block;
51}
52
53static size_t
54rtems_rtl_unresolved_name_recs (const char* name)
55{
56  size_t length = strlen (name);
57  return ((length + sizeof(rtems_rtl_unresolv_name) - 1) /
58          sizeof(rtems_rtl_unresolv_name));
59}
60
61static int
62rtems_rtl_unresolved_rec_index (rtems_rtl_unresolv_block* block,
63                                rtems_rtl_unresolv_rec* rec)
64{
65  return (rec - &block->rec) / sizeof (rtems_rtl_unresolv_rec);
66}
67
68static rtems_rtl_unresolv_rec*
69rtems_rtl_unresolved_rec_first (rtems_rtl_unresolv_block* block)
70{
71  return &block->rec;
72}
73
74static rtems_rtl_unresolv_rec*
75rtems_rtl_unresolved_rec_next (rtems_rtl_unresolv_rec* rec)
76{
77  switch (rec->type)
78  {
79    case rtems_rtl_unresolved_empty:
80      /*
81       * Empty returns NULL. The end of the records in the block.
82       */
83      rec = NULL;
84      break;
85
86    case rtems_rtl_unresolved_name:
87      /*
88       * Determine how many records the name occupies. Round up.
89       */
90      rec += ((rec->rec.name.length + sizeof(rtems_rtl_unresolv_name) - 1) /
91              sizeof(rtems_rtl_unresolv_name));
92      break;
93
94    case rtems_rtl_unresolved_reloc:
95      ++rec;
96      break;
97
98    default:
99      break;
100  }
101
102  return rec;
103}
104
105static bool
106rtems_rtl_unresolved_rec_is_last (rtems_rtl_unresolv_block* block,
107                                  rtems_rtl_unresolv_rec*   rec)
108{
109  int index = (rec - &block->rec) / sizeof (rec);
110  return !rec || (index >= block->recs) || (rec->type == rtems_rtl_unresolved_empty);
111}
112
113static rtems_rtl_unresolv_rec*
114rtems_rtl_unresolved_rec_first_free (rtems_rtl_unresolv_block* block)
115{
116  return &block->rec + block->recs;
117}
118
119static int
120rtems_rtl_unresolved_find_name (rtems_rtl_unresolved* unresolved,
121                                const char*           name,
122                                bool                  update_refcount)
123{
124  size_t length = strlen (name) + 1;
125  int    index = 1;
126
127  rtems_chain_node* node = rtems_chain_first (&unresolved->blocks);
128  while (!rtems_chain_is_tail (&unresolved->blocks, node))
129  {
130    rtems_rtl_unresolv_block* block = (rtems_rtl_unresolv_block*) node;
131    rtems_rtl_unresolv_rec* rec = rtems_rtl_unresolved_rec_first (block);
132
133    while (!rtems_rtl_unresolved_rec_is_last (block, rec))
134    {
135      if (rec->type == rtems_rtl_unresolved_name)
136      {
137        if ((rec->rec.name.length == length)
138            && (strcmp (rec->rec.name.name, name) == 0))
139        {
140          if (update_refcount)
141            ++rec->rec.name.refs;
142          return index;
143        }
144        ++index;
145      }
146      rec = rtems_rtl_unresolved_rec_next (rec);
147    }
148
149    node = rtems_chain_next (node);
150  }
151
152  return 0 - index;
153}
154
155/**
156 * Struct to pass relocation data in the interator.
157 */
158typedef struct rtems_rtl_unresolved_reloc_data
159{
160  uint16_t                name;     /**< Name index. */
161  rtems_rtl_unresolv_rec* name_rec; /**< Name record. */
162  rtems_rtl_obj_sym*      sym;      /**< The symbol record. */
163} rtems_rtl_unresolved_reloc_data;
164
165static bool
166rtems_rtl_unresolved_resolve_reloc (rtems_rtl_unresolv_rec* rec,
167                                    void*                   data)
168{
169  if (rec->type == rtems_rtl_unresolved_reloc)
170  {
171    rtems_rtl_unresolved_reloc_data* rd;
172    rd = (rtems_rtl_unresolved_reloc_data*) data;
173
174    if (rec->rec.reloc.name == rd->name)
175    {
176      if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED))
177        printf ("rtl: unresolv: resolve reloc: %s\n", rd->name_rec->rec.name.name);
178
179      rtems_rtl_obj_relocate_unresolved (&rec->rec.reloc, rd->sym);
180
181      /*
182       * Set the object pointer to NULL to indicate the record is not used
183       * anymore. Update the reference count of the name. The sweep after
184       * relocating will remove the reloc records with obj set to NULL and
185       * names with a reference count of 0.
186       */
187      rec->rec.reloc.obj = NULL;
188      if (rd->name_rec && rd->name_rec->rec.name.refs)
189        --rd->name_rec->rec.name.refs;
190    }
191  }
192  return false;
193}
194
195static bool
196rtems_rtl_unresolved_resolve_iterator (rtems_rtl_unresolv_rec* rec,
197                                       void*                   data)
198{
199  if (rec->type == rtems_rtl_unresolved_name)
200  {
201    rtems_rtl_unresolved_reloc_data* rd;
202    rd = (rtems_rtl_unresolved_reloc_data*) data;
203
204    ++rd->name;
205
206    if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED))
207      printf ("rtl: unresolv: lookup: %d: %s\n", rd->name, rec->rec.name.name);
208
209    rd->sym = rtems_rtl_symbol_global_find (rec->rec.name.name);
210
211    if (rd->sym)
212    {
213      if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED))
214        printf ("rtl: unresolv: found: %s\n", rec->rec.name.name);
215
216      rd->name_rec = rec;
217
218      rtems_rtl_unresolved_interate (rtems_rtl_unresolved_resolve_reloc, rd);
219
220      rd->name_rec = NULL;
221      rd->sym = NULL;
222    }
223  }
224
225  return false;
226}
227
228static void
229rtems_rtl_unresolved_clean_block (rtems_rtl_unresolv_block* block,
230                                  rtems_rtl_unresolv_rec*   rec,
231                                  size_t                    count,
232                                  size_t                    recs_per_block)
233{
234  size_t index = rtems_rtl_unresolved_rec_index (block, rec);
235  size_t bytes =
236    (block->recs - index - count) * sizeof (rtems_rtl_unresolv_rec);
237  if (bytes)
238    memmove (rec, rec + count, bytes);
239  block->recs -= count;
240  bytes = count * sizeof (rtems_rtl_unresolv_rec);
241  memset (&block->rec + block->recs, 0, bytes);
242}
243
244static void
245rtems_rtl_unresolved_compact (void)
246{
247  rtems_rtl_unresolved* unresolved = rtems_rtl_unresolved_unprotected ();
248  if (unresolved)
249  {
250    /*
251     * Iterate over the blocks removing any empty strings. If a string is removed
252     * update the indexes of all strings above this level.
253     */
254    rtems_chain_node* node = rtems_chain_first (&unresolved->blocks);
255    uint16_t          index = 0;
256    while (!rtems_chain_is_tail (&unresolved->blocks, node))
257    {
258      rtems_rtl_unresolv_block* block = (rtems_rtl_unresolv_block*) node;
259      rtems_rtl_unresolv_rec*   rec = rtems_rtl_unresolved_rec_first (block);
260
261      while (!rtems_rtl_unresolved_rec_is_last (block, rec))
262      {
263        bool next_rec = true;
264        if (rec->type == rtems_rtl_unresolved_name)
265        {
266          ++index;
267          if (rec->rec.name.refs == 0)
268          {
269            /*
270             * Iterate over the remainnig reloc records and update the index.
271             */
272            rtems_chain_node*       reindex_node;
273            rtems_rtl_unresolv_rec* reindex_first;
274            size_t                  name_recs;
275            if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED))
276              printf ("rtl: unresolv: remove name: %s\n", rec->rec.name.name);
277            reindex_node = node;
278            reindex_first = rtems_rtl_unresolved_rec_next (rec);
279            while (!rtems_chain_is_tail (&unresolved->blocks, reindex_node))
280            {
281              rtems_rtl_unresolv_rec*   reindex_rec;
282              rtems_rtl_unresolv_block* reindex_block;
283              reindex_block = (rtems_rtl_unresolv_block*) reindex_node;
284              if (reindex_first != NULL)
285              {
286                reindex_rec = reindex_first;
287                reindex_first = NULL;
288              }
289              else
290              {
291                reindex_rec = rtems_rtl_unresolved_rec_first (reindex_block);
292              }
293              while (!rtems_rtl_unresolved_rec_is_last (reindex_block,
294                                                        reindex_rec))
295              {
296                if (reindex_rec->type == rtems_rtl_unresolved_reloc)
297                {
298                  if (reindex_rec->rec.reloc.name >= index)
299                    --reindex_rec->rec.reloc.name;
300                }
301                reindex_rec = rtems_rtl_unresolved_rec_next (reindex_rec);
302              }
303              reindex_node = rtems_chain_next (reindex_node);
304            }
305            /*
306             * Compact the block removing the name record.
307             */
308            name_recs = rtems_rtl_unresolved_name_recs (rec->rec.name.name);
309            rtems_rtl_unresolved_clean_block (block, rec, name_recs,
310                                              unresolved->block_recs);
311            --index;
312            next_rec = false;
313          }
314        }
315        else if (rec->type == rtems_rtl_unresolved_reloc)
316        {
317          if (rec->rec.reloc.obj == NULL)
318          {
319            rtems_rtl_unresolved_clean_block (block, rec, 1,
320                                              unresolved->block_recs);
321            next_rec = false;
322          }
323        }
324
325        if (next_rec)
326          rec = rtems_rtl_unresolved_rec_next (rec);
327      }
328
329      if (block->recs == 0)
330      {
331        rtems_chain_node* next_node = rtems_chain_next (node);
332        if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED))
333          printf ("rtl: unresolv: block-del %p\n", block);
334        rtems_chain_extract (node);
335        rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_EXTERNAL, block);
336        node = next_node;
337      }
338      else
339      {
340        node = rtems_chain_next (node);
341      }
342    }
343  }
344}
345
346bool
347rtems_rtl_unresolved_table_open (rtems_rtl_unresolved* unresolved,
348                                 size_t                block_recs)
349{
350  unresolved->marker = 0xdeadf00d;
351  unresolved->block_recs = block_recs;
352  rtems_chain_initialize_empty (&unresolved->blocks);
353  return true;
354}
355
356void
357rtems_rtl_unresolved_table_close (rtems_rtl_unresolved* unresolved)
358{
359  rtems_chain_node* node = rtems_chain_first (&unresolved->blocks);
360  while (!rtems_chain_is_tail (&unresolved->blocks, node))
361  {
362    rtems_chain_node* next = rtems_chain_next (node);
363    free (node);
364    node = next;
365  }
366}
367
368bool
369rtems_rtl_unresolved_interate (rtems_rtl_unresolved_iterator iterator,
370                               void*                         data)
371{
372  rtems_rtl_unresolved* unresolved = rtems_rtl_unresolved_unprotected ();
373  if (unresolved)
374  {
375    rtems_chain_node* node = rtems_chain_first (&unresolved->blocks);
376    while (!rtems_chain_is_tail (&unresolved->blocks, node))
377    {
378      rtems_rtl_unresolv_block* block = (rtems_rtl_unresolv_block*) node;
379      rtems_rtl_unresolv_rec*   rec = rtems_rtl_unresolved_rec_first (block);
380
381      while (!rtems_rtl_unresolved_rec_is_last (block, rec))
382      {
383        if (iterator (rec, data))
384          return true;
385        rec = rtems_rtl_unresolved_rec_next (rec);
386      }
387
388      node = rtems_chain_next (node);
389    }
390  }
391  return false;
392}
393
394bool
395rtems_rtl_unresolved_add (rtems_rtl_obj*        obj,
396                          const uint16_t        flags,
397                          const char*           name,
398                          const uint16_t        sect,
399                          const rtems_rtl_word* rel)
400{
401  rtems_rtl_unresolved*     unresolved;
402  rtems_chain_node*         node;
403  rtems_rtl_unresolv_block* block;
404  rtems_rtl_unresolv_rec*   rec;
405  int                       name_index;
406  size_t                    name_recs;
407
408  if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED))
409    printf ("rtl: unresolv: add: %s(s:%d) -> %s\n",
410            rtems_rtl_obj_oname (obj), sect, name);
411
412  unresolved = rtems_rtl_unresolved_unprotected ();
413  if (!unresolved)
414    return false;
415
416  /*
417   * Find the first block with a spare record.
418   */
419  node = rtems_chain_first (&unresolved->blocks);
420  block = NULL;
421  while (!rtems_chain_is_tail (&unresolved->blocks, node))
422  {
423    block = (rtems_rtl_unresolv_block*) node;
424    if (block->recs < unresolved->block_recs)
425      break;
426    block = NULL;
427    node = rtems_chain_next (node);
428  }
429
430  /*
431   * No blocks with any spare records, allocate a new block.
432   */
433  if (!block)
434  {
435    block = rtems_rtl_unresolved_block_alloc (unresolved);
436    if (!block)
437      return false;
438  }
439
440  name_index = rtems_rtl_unresolved_find_name (unresolved, name, true);
441  name_recs = rtems_rtl_unresolved_name_recs (name);
442
443  /*
444   * An index less than 0 means the name is present and "0 - index" is the next
445   * index to use.
446   */
447  if (name_index < 0)
448  {
449    rtems_rtl_unresolv_block* name_block = block;
450
451    /*
452     * Is there enough room to fit the name ? It not add a new block.
453     */
454    if (name_recs > (unresolved->block_recs - block->recs))
455    {
456      name_block = rtems_rtl_unresolved_block_alloc (unresolved);
457      if (!name_block)
458        return false;
459    }
460
461    rec = rtems_rtl_unresolved_rec_first_free (name_block);
462    rec->type = rtems_rtl_unresolved_name;
463    rec->rec.name.refs = 1;
464    rec->rec.name.length = strlen (name) + 1;
465    memcpy ((void*) &rec->rec.name.name[0], name, rec->rec.name.length + 1);
466    block->recs += name_recs;
467    name_index = 0 - name_index;
468
469    /*
470     * If the name block is the reloc block and it is full allocate a new
471     * block for the relocation record.
472     */
473    if ((block == name_block) && (block->recs >= unresolved->block_recs))
474    {
475      block = rtems_rtl_unresolved_block_alloc (unresolved);
476      if (!block)
477        return false;
478    }
479  }
480
481  rec = rtems_rtl_unresolved_rec_first_free (block);
482  rec->type = rtems_rtl_unresolved_reloc;
483  rec->rec.reloc.obj = obj;
484  rec->rec.reloc.flags = flags;
485  rec->rec.reloc.name = name_index;
486  rec->rec.reloc.sect = sect;
487  rec->rec.reloc.rel[0] = rel[0];
488  rec->rec.reloc.rel[1] = rel[1];
489  rec->rec.reloc.rel[2] = rel[2];
490
491  ++block->recs;
492
493  return true;
494}
495
496void
497rtems_rtl_unresolved_resolve (void)
498{
499  rtems_rtl_unresolved_reloc_data rd;
500  if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED))
501    printf ("rtl: unresolv: global resolve\n");
502  rd.name = 0;
503  rd.name_rec = NULL;
504  rd.sym = NULL;
505  rtems_rtl_unresolved_interate (rtems_rtl_unresolved_resolve_iterator, &rd);
506  rtems_rtl_unresolved_compact ();
507  if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED))
508    rtems_rtl_unresolved_dump ();
509}
510
511bool
512rtems_rtl_unresolved_remove (rtems_rtl_obj*        obj,
513                             const char*           name,
514                             const uint16_t        sect,
515                             const rtems_rtl_word* rel)
516{
517  rtems_rtl_unresolved* unresolved;
518  unresolved = rtems_rtl_unresolved_unprotected ();
519  if (!unresolved)
520    return false;
521  return false;
522}
523
524/**
525 * Struct to pass relocation data in the iterator.
526 */
527typedef struct rtems_rtl_unresolved_dump_data
528{
529  size_t rec;
530  size_t names;
531} rtems_rtl_unresolved_dump_data;
532
533static bool
534rtems_rtl_unresolved_dump_iterator (rtems_rtl_unresolv_rec* rec,
535                                    void*                   data)
536{
537  rtems_rtl_unresolved_dump_data* dd;
538  dd = (rtems_rtl_unresolved_dump_data*) data;
539  switch (rec->type)
540  {
541  case rtems_rtl_unresolved_empty:
542    printf (" %03zu: 0: empty\n", dd->rec);
543    break;
544  case rtems_rtl_unresolved_name:
545    ++dd->names;
546    printf (" %3zu: 1:  name: %3d refs: %2d: %2d: %s\n",
547            dd->rec, dd->names,
548            rec->rec.name.refs, rec->rec.name.length, rec->rec.name.name);
549    break;
550  case rtems_rtl_unresolved_reloc:
551    printf (" %3zu: 2: reloc: obj:%s name:%2d: sect:%d\n",
552            dd->rec,
553            rec->rec.reloc.obj->oname,
554            rec->rec.reloc.name,
555            rec->rec.reloc.sect);
556    break;
557  default:
558    printf (" %03zu: %d: unknown\n", dd->rec, rec->type);
559    break;
560  }
561  ++dd->rec;
562  return false;
563}
564
565void
566rtems_rtl_unresolved_dump (void)
567{
568  rtems_rtl_unresolved_dump_data dd = { 0 };
569  printf ("RTL Unresolved data:\n");
570  rtems_rtl_unresolved_interate (rtems_rtl_unresolved_dump_iterator, &dd);
571}
Note: See TracBrowser for help on using the repository browser.