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

5
Last change on this file since b2ed712 was b2ed712, checked in by Sebastian Huber <sebastian.huber@…>, on 08/25/17 at 08:58:58

Include missing <string.h>

Update #2133.

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