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

5
Last change on this file since c130387 was d4edbdbc, checked in by Sebastian Huber <sebastian.huber@…>, on 03/20/15 at 13:09:26

Replace www.rtems.com with www.rtems.org

  • Property mode set to 100644
File size: 12.8 KB
Line 
1/*
2 *  COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org>
3 *
4 *  The license and distribution terms for this file may be
5 *  found in the file LICENSE in this distribution or at
6 *  http://www.rtems.org/license/LICENSE.
7 */
8/**
9 * @file
10 *
11 * @ingroup rtems_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
25#include <rtems/rtl/rtl.h>
26#include "rtl-error.h"
27#include "rtl-unresolved.h"
28#include "rtl-trace.h"
29
30static rtems_rtl_unresolv_block_t*
31rtems_rtl_unresolved_block_alloc (rtems_rtl_unresolved_t* unresolved)
32{
33  /*
34   * The block header contains a record.
35   */
36  size_t size =
37    (sizeof(rtems_rtl_unresolv_block_t) +
38     (sizeof(rtems_rtl_unresolv_rec_t) * (unresolved->block_recs - 1)));
39  rtems_rtl_unresolv_block_t* block =
40    rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_EXTERNAL, size, true);
41  if (block)
42    rtems_chain_append (&unresolved->blocks, &block->link);
43  else
44    rtems_rtl_set_error (ENOMEM, "no memory for unresolved block");
45  return block;
46}
47
48static size_t
49rtems_rtl_unresolved_name_recs (const char* name)
50{
51  size_t length = strlen (name);
52  return ((length + sizeof(rtems_rtl_unresolv_name_t) - 1) /
53          sizeof(rtems_rtl_unresolv_name_t));
54}
55
56static int
57rtems_rtl_unresolved_rec_index (rtems_rtl_unresolv_block_t* block,
58                                rtems_rtl_unresolv_rec_t* rec)
59{
60  return (rec - &block->rec) / sizeof (rtems_rtl_unresolv_rec_t);
61}
62
63static rtems_rtl_unresolv_rec_t*
64rtems_rtl_unresolved_rec_first (rtems_rtl_unresolv_block_t* block)
65{
66  return &block->rec;
67}
68
69static rtems_rtl_unresolv_rec_t*
70rtems_rtl_unresolved_rec_next (rtems_rtl_unresolv_rec_t* rec)
71{
72
73  switch (rec->type)
74  {
75    case rtems_rtl_unresolved_empty:
76      /*
77       * Empty returns NULL. The end of the records in the block.
78       */
79      rec = NULL;
80      break;
81
82    case rtems_rtl_unresolved_name:
83      /*
84       * Determine how many records the name occupies. Round up.
85       */
86      rec += ((rec->rec.name.length + sizeof(rtems_rtl_unresolv_name_t) - 1) /
87              sizeof(rtems_rtl_unresolv_name_t));
88      break;
89
90    case rtems_rtl_unresolved_reloc:
91      ++rec;
92      break;
93
94    default:
95      break;
96  }
97
98  return rec;
99}
100
101static bool
102rtems_rtl_unresolved_rec_is_last (rtems_rtl_unresolv_block_t* block,
103                                  rtems_rtl_unresolv_rec_t*   rec)
104{
105  int index = (rec - &block->rec) / sizeof (rec);
106  return !rec || (index >= block->recs) || (rec->type == rtems_rtl_unresolved_empty);
107}
108
109static rtems_rtl_unresolv_rec_t*
110rtems_rtl_unresolved_rec_first_free (rtems_rtl_unresolv_block_t* block)
111{
112  return &block->rec + block->recs;
113}
114
115static int
116rtems_rtl_unresolved_find_name (rtems_rtl_unresolved_t* unresolved,
117                                const char*             name,
118                                bool                    update_refcount)
119{
120  size_t length = strlen (name);
121  int    index = 1;
122
123  rtems_chain_node* node = rtems_chain_first (&unresolved->blocks);
124  while (!rtems_chain_is_tail (&unresolved->blocks, node))
125  {
126    rtems_rtl_unresolv_block_t* block = (rtems_rtl_unresolv_block_t*) node;
127    rtems_rtl_unresolv_rec_t* rec = rtems_rtl_unresolved_rec_first (block);
128
129    while (!rtems_rtl_unresolved_rec_is_last (block, rec))
130    {
131      if (rec->type == rtems_rtl_unresolved_name)
132      {
133        if ((rec->rec.name.length == length)
134            && (strcmp (rec->rec.name.name, name)))
135        {
136          if (update_refcount)
137            ++rec->rec.name.refs;
138          return index;
139        }
140        ++index;
141      }
142      rec = rtems_rtl_unresolved_rec_next (rec);
143    }
144
145    node = rtems_chain_next (node);
146  }
147
148  return 0 - index;
149}
150
151/**
152 * Struct to pass relocation data in the interator.
153 */
154typedef struct rtems_rtl_unresolved_reloc_data_s
155{
156  uint16_t                  name;     /**< Name index. */
157  rtems_rtl_unresolv_rec_t* name_rec; /**< Name record. */
158  rtems_rtl_obj_sym_t*      sym;      /**< The symbol record. */
159} rtems_rtl_unresolved_reloc_data_t;
160
161static bool
162rtems_rtl_unresolved_resolve_reloc (rtems_rtl_unresolv_rec_t* rec,
163                                    void*                     data)
164{
165  if (rec->type == rtems_rtl_unresolved_reloc)
166  {
167    rtems_rtl_unresolved_reloc_data_t* rd;
168    rd = (rtems_rtl_unresolved_reloc_data_t*) data;
169
170    if (rec->rec.reloc.name == rd->name)
171    {
172      if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED))
173        printf ("rtl: unresolv: resolve reloc: %s\n", rd->name_rec->rec.name.name);
174
175      rtems_rtl_obj_relocate_unresolved (&rec->rec.reloc, rd->sym);
176
177      /*
178       * Set the object pointer to NULL to indicate the record is not used
179       * anymore. Update the reference count of the name. The sweep after
180       * relocating will remove the reloc records with obj set to NULL and
181       * names with a reference count of 0.
182       */
183      rec->rec.reloc.obj = NULL;
184      if (rd->name_rec && rd->name_rec->rec.name.refs)
185        --rd->name_rec->rec.name.refs;
186    }
187  }
188  return false;
189}
190
191static bool
192rtems_rtl_unresolved_resolve_iterator (rtems_rtl_unresolv_rec_t* rec,
193                                       void*                     data)
194{
195  if (rec->type == rtems_rtl_unresolved_name)
196  {
197    rtems_rtl_unresolved_reloc_data_t* rd;
198    rd = (rtems_rtl_unresolved_reloc_data_t*) data;
199
200    ++rd->name;
201
202    if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED))
203      printf ("rtl: unresolv: lookup: %d: %s\n", rd->name, rec->rec.name.name);
204
205    rd->sym = rtems_rtl_symbol_global_find (rec->rec.name.name);
206
207    if (rd->sym)
208    {
209      if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED))
210        printf ("rtl: unresolv: found: %s\n", rec->rec.name.name);
211
212      rd->name_rec = rec;
213
214      rtems_rtl_unresolved_interate (rtems_rtl_unresolved_resolve_reloc, rd);
215
216      rd->name_rec = NULL;
217      rd->sym = NULL;
218    }
219  }
220
221  return false;
222}
223
224static void
225rtems_rtl_unresolved_clean_block (rtems_rtl_unresolv_block_t* block,
226                                  rtems_rtl_unresolv_rec_t* rec,
227                                  size_t count,
228                                  size_t recs_per_block)
229{
230  size_t index = rtems_rtl_unresolved_rec_index (block, rec);
231  size_t bytes =
232    (block->recs - index - count) * sizeof (rtems_rtl_unresolv_rec_t);
233  if (bytes)
234    memmove (rec, rec + count, bytes);
235  --block->recs;
236  bytes = count * sizeof (rtems_rtl_unresolv_rec_t);
237  memset (&block->rec + block->recs, 0, bytes);
238}
239
240static void
241rtems_rtl_unresolved_compact (void)
242{
243  rtems_rtl_unresolved_t* unresolved = rtems_rtl_unresolved ();
244  if (unresolved)
245  {
246    /*
247     * Iterate backwards over the blocks removing any used records. A block is
248     * compacted moving up the block.
249     */
250    rtems_chain_node* node = rtems_chain_last (&unresolved->blocks);
251    while (!rtems_chain_is_head (&unresolved->blocks, node))
252    {
253      rtems_chain_node* prev = rtems_chain_previous (node);
254      rtems_rtl_unresolv_block_t* block = (rtems_rtl_unresolv_block_t*) node;
255      rtems_rtl_unresolv_rec_t* rec = rtems_rtl_unresolved_rec_first (block);
256
257      while (!rtems_rtl_unresolved_rec_is_last (block, rec))
258      {
259        bool next = true;
260
261        if (rec->type == rtems_rtl_unresolved_name)
262        {
263          if (rec->rec.name.refs == 0)
264          {
265            size_t name_recs = rtems_rtl_unresolved_name_recs (rec->rec.name.name);
266            rtems_rtl_unresolved_clean_block (block, rec, name_recs,
267                                              unresolved->block_recs);
268            next = false;
269          }
270        }
271        else if (rec->type == rtems_rtl_unresolved_reloc)
272        {
273          if (!rec->rec.reloc.obj)
274          {
275            rtems_rtl_unresolved_clean_block (block, rec, 1,
276                                              unresolved->block_recs);
277            next = false;
278          }
279        }
280
281        if (next)
282          rec = rtems_rtl_unresolved_rec_next (rec);
283      }
284
285      if (block->recs == 0)
286      {
287        rtems_chain_extract (node);
288        free (block);
289      }
290
291      node = prev;
292    }
293  }
294}
295
296bool
297rtems_rtl_unresolved_table_open (rtems_rtl_unresolved_t* unresolved,
298                                 size_t                  block_recs)
299{
300  unresolved->marker = 0xdeadf00d;
301  unresolved->block_recs = block_recs;
302  rtems_chain_initialize_empty (&unresolved->blocks);
303  return true;
304}
305
306void
307rtems_rtl_unresolved_table_close (rtems_rtl_unresolved_t* unresolved)
308{
309  rtems_chain_node* node = rtems_chain_first (&unresolved->blocks);
310  while (!rtems_chain_is_tail (&unresolved->blocks, node))
311  {
312    rtems_chain_node* next = rtems_chain_next (node);
313    free (node);
314    node = next;
315  }
316}
317
318bool
319rtems_rtl_unresolved_interate (rtems_rtl_unresolved_iterator_t iterator,
320                               void*                           data)
321{
322  rtems_rtl_unresolved_t* unresolved = rtems_rtl_unresolved ();
323  if (unresolved)
324  {
325    rtems_chain_node* node = rtems_chain_first (&unresolved->blocks);
326    while (!rtems_chain_is_tail (&unresolved->blocks, node))
327    {
328      rtems_rtl_unresolv_block_t* block = (rtems_rtl_unresolv_block_t*) node;
329      rtems_rtl_unresolv_rec_t* rec = rtems_rtl_unresolved_rec_first (block);
330
331      while (!rtems_rtl_unresolved_rec_is_last (block, rec))
332      {
333        if (iterator (rec, data))
334          return true;
335        rec = rtems_rtl_unresolved_rec_next (rec);
336      }
337
338      node = rtems_chain_next (node);
339    }
340  }
341  return false;
342}
343
344bool
345rtems_rtl_unresolved_add (rtems_rtl_obj_t*        obj,
346                          const uint16_t          flags,
347                          const char*             name,
348                          const uint16_t          sect,
349                          const rtems_rtl_word_t* rel)
350{
351  rtems_rtl_unresolved_t* unresolved;
352  rtems_chain_node* node;
353  rtems_rtl_unresolv_block_t* block;
354  rtems_rtl_unresolv_rec_t* rec;
355  int name_index;
356  size_t name_recs;
357
358  if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED))
359    printf ("rtl: unresolv: add: %s(s:%d) -> %s\n",
360            rtems_rtl_obj_oname (obj), sect, name);
361
362  unresolved = rtems_rtl_unresolved ();
363  if (!unresolved)
364    return false;
365
366  /*
367   * Find the first block with a spare record.
368   */
369  node = rtems_chain_first (&unresolved->blocks);
370  block = NULL;
371  while (!rtems_chain_is_tail (&unresolved->blocks, node))
372  {
373    block = (rtems_rtl_unresolv_block_t*) node;
374    if (block->recs < unresolved->block_recs)
375      break;
376    block = NULL;
377    node = rtems_chain_next (node);
378  }
379
380  /*
381   * No blocks with any spare records, allocate a new block.
382   */
383  if (!block)
384  {
385    block = rtems_rtl_unresolved_block_alloc (unresolved);
386    if (!block)
387      return false;
388  }
389
390  name_index = rtems_rtl_unresolved_find_name (unresolved, name, true);
391  name_recs = rtems_rtl_unresolved_name_recs (name);
392
393  /*
394   * An index less than 0 means the name is present and "0 - index" is the next
395   * index to use.
396   */
397  if (name_index < 0)
398  {
399    rtems_rtl_unresolv_block_t* name_block = block;
400
401    /*
402     * Is there enough room to fit the name ? It not add a new block.
403     */
404    if (name_recs > (unresolved->block_recs - block->recs))
405    {
406      name_block = rtems_rtl_unresolved_block_alloc (unresolved);
407      if (!name_block)
408        return false;
409    }
410
411    rec = rtems_rtl_unresolved_rec_first_free (name_block);
412    rec->type = rtems_rtl_unresolved_name;
413    rec->rec.name.refs = 1;
414    rec->rec.name.length = strlen (name) + 1;
415    memcpy ((void*) &rec->rec.name.name[0], name, rec->rec.name.length + 1);
416    block->recs += name_recs;
417    name_index = 0 - name_index;
418
419    /*
420     * If the name block is the reloc block and it is full allocate a new
421     * block for the relocation record.
422     */
423    if ((block == name_block) && (block->recs >= unresolved->block_recs))
424    {
425      block = rtems_rtl_unresolved_block_alloc (unresolved);
426      if (!block)
427        return false;
428    }
429  }
430
431  rec = rtems_rtl_unresolved_rec_first_free (block);
432  rec->type = rtems_rtl_unresolved_reloc;
433  rec->rec.reloc.obj = obj;
434  rec->rec.reloc.flags = flags;
435  rec->rec.reloc.name = name_index;
436  rec->rec.reloc.sect = sect;
437  rec->rec.reloc.rel[0] = rel[0];
438  rec->rec.reloc.rel[1] = rel[1];
439  rec->rec.reloc.rel[2] = rel[2];
440
441  ++block->recs;
442
443  return true;
444}
445
446void
447rtems_rtl_unresolved_resolve (void)
448{
449  rtems_rtl_unresolved_reloc_data_t rd;
450  if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED))
451    printf ("rtl: unresolv: global resolve\n");
452  rd.name = 0;
453  rd.name_rec = NULL;
454  rd.sym = NULL;
455  rtems_rtl_unresolved_interate (rtems_rtl_unresolved_resolve_iterator, &rd);
456  rtems_rtl_unresolved_compact ();
457}
458
459bool
460rtems_rtl_unresolved_remove (rtems_rtl_obj_t*        obj,
461                             const char*             name,
462                             const uint16_t          sect,
463                             const rtems_rtl_word_t* rel)
464{
465  rtems_rtl_unresolved_t* unresolved;
466  unresolved = rtems_rtl_unresolved ();
467  if (!unresolved)
468    return false;
469  return false;
470}
471
Note: See TracBrowser for help on using the repository browser.