Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:16

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup rtems_rtl
0007  *
0008  * @brief RTEMS Run-Time Linker Object File Unresolved Relocations Table.
0009  */
0010 
0011 /*
0012  *  COPYRIGHT (c) 2012, 2018 Chris Johns <chrisj@rtems.org>
0013  *
0014  * Redistribution and use in source and binary forms, with or without
0015  * modification, are permitted provided that the following conditions
0016  * are met:
0017  * 1. Redistributions of source code must retain the above copyright
0018  *    notice, this list of conditions and the following disclaimer.
0019  * 2. Redistributions in binary form must reproduce the above copyright
0020  *    notice, this list of conditions and the following disclaimer in the
0021  *    documentation and/or other materials provided with the distribution.
0022  *
0023  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0024  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0025  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0026  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0027  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0028  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0029  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0030  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0031  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0032  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0033  * POSSIBILITY OF SUCH DAMAGE.
0034  */
0035 
0036 #ifdef HAVE_CONFIG_H
0037 #include "config.h"
0038 #endif
0039 
0040 #include <errno.h>
0041 #include <inttypes.h>
0042 #include <stdlib.h>
0043 #include <stdio.h>
0044 #include <string.h>
0045 
0046 #include <rtems/rtl/rtl.h>
0047 #include "rtl-error.h"
0048 #include <rtems/rtl/rtl-unresolved.h>
0049 #include <rtems/rtl/rtl-trace.h>
0050 #include "rtl-trampoline.h"
0051 
0052 static rtems_rtl_unresolv_block*
0053 rtems_rtl_unresolved_block_alloc (rtems_rtl_unresolved* unresolved)
0054 {
0055   /*
0056    * The block header contains a record.
0057    */
0058   size_t size =
0059     (sizeof(rtems_rtl_unresolv_block) +
0060      (sizeof(rtems_rtl_unresolv_rec) * unresolved->block_recs));
0061   rtems_rtl_unresolv_block* block =
0062     rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_EXTERNAL, size, true);
0063   if (block)
0064   {
0065     if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED))
0066       printf ("rtl: unresolv: block-alloc %p (%p)\n", block, block + size);
0067     rtems_chain_append (&unresolved->blocks, &block->link);
0068   }
0069   else
0070     rtems_rtl_set_error (ENOMEM, "no memory for unresolved block");
0071   return block;
0072 }
0073 
0074 static size_t
0075 rtems_rtl_unresolved_symbol_rec_count (size_t length)
0076 {
0077   const size_t rec_size = sizeof(rtems_rtl_unresolv_rec);
0078   const size_t rec_name_header = offsetof(rtems_rtl_unresolv_rec, rec.name.name);
0079   /*
0080    * Add on the nul and rmeove 1 to be inside a record.
0081    */
0082   return ((length + rec_name_header - 1) / rec_size) + 1;
0083 }
0084 
0085 static size_t
0086 rtems_rtl_unresolved_symbol_recs (const char* name)
0087 {
0088   return rtems_rtl_unresolved_symbol_rec_count (strlen (name) + 1);
0089 }
0090 
0091 static int
0092 rtems_rtl_unresolved_rec_index (rtems_rtl_unresolv_block* block,
0093                                 rtems_rtl_unresolv_rec*   rec)
0094 {
0095   return rec - &block->rec[0];
0096 }
0097 
0098 static rtems_rtl_unresolv_rec*
0099 rtems_rtl_unresolved_rec_first (rtems_rtl_unresolv_block* block)
0100 {
0101   return &block->rec[0];
0102 }
0103 
0104 static rtems_rtl_unresolv_rec*
0105 rtems_rtl_unresolved_rec_next (rtems_rtl_unresolv_rec* rec)
0106 {
0107   switch (rec->type)
0108   {
0109     case rtems_rtl_unresolved_empty:
0110     default:
0111       /*
0112        * Empty returns NULL. The end of the records in the block.
0113        */
0114       rec = NULL;
0115       break;
0116 
0117     case rtems_rtl_unresolved_symbol:
0118       /*
0119        * Determine how many records the name occupies. Round up.
0120        */
0121       rec += rtems_rtl_unresolved_symbol_rec_count (rec->rec.name.length);
0122       break;
0123 
0124     case rtems_rtl_unresolved_reloc:
0125     case rtems_rtl_trampoline_reloc:
0126       ++rec;
0127       break;
0128   }
0129 
0130   return rec;
0131 }
0132 
0133 static bool
0134 rtems_rtl_unresolved_rec_is_last (rtems_rtl_unresolv_block* block,
0135                                   rtems_rtl_unresolv_rec*   rec)
0136 {
0137   int index = rtems_rtl_unresolved_rec_index (block, rec);
0138   return (rec == NULL ||
0139           (index < 0) ||
0140           (index >= block->recs) ||
0141           (rec->type == rtems_rtl_unresolved_empty));
0142 }
0143 
0144 static rtems_rtl_unresolv_rec*
0145 rtems_rtl_unresolved_rec_first_free (rtems_rtl_unresolv_block* block)
0146 {
0147   return &block->rec[0] + block->recs;
0148 }
0149 
0150 /**
0151  * Name management iterator data.
0152  */
0153 typedef struct
0154 {
0155   const char*             name;   /**< The name being searched for. */
0156   size_t                  length; /**< The length of the name. */
0157   rtems_rtl_unresolv_rec* rec;    /**< The record being searched for. */
0158   int                     index;  /**< The name's index. */
0159   int                     offset; /**< The offset to move the index. */
0160 } rtl_unresolved_name_data;
0161 
0162 static bool
0163 rtems_rtl_unresolved_find_name_iterator (rtems_rtl_unresolv_rec* rec,
0164                                          void*                   data)
0165 {
0166   rtl_unresolved_name_data* nd = (rtl_unresolved_name_data*) data;
0167   if (rec->type == rtems_rtl_unresolved_symbol)
0168   {
0169     if ((rec->rec.name.length == nd->length)
0170         && (strcmp (rec->rec.name.name, nd->name) == 0))
0171     {
0172       ++rec->rec.name.refs;
0173       return true;
0174     }
0175     ++nd->index;
0176   }
0177   return false;
0178 }
0179 
0180 static int
0181 rtems_rtl_unresolved_find_name (const char* name)
0182 {
0183   rtl_unresolved_name_data nd = {
0184     .name = name,
0185     .length = strlen (name) + 1,
0186     .rec = NULL,
0187     .index = 1,
0188     .offset = 0
0189   };
0190   if (rtems_rtl_unresolved_iterate (rtems_rtl_unresolved_find_name_iterator,
0191                                     &nd))
0192     return nd.index;
0193   return -1;
0194 }
0195 
0196 static bool
0197 rtems_rtl_unresolved_find_index_iterator (rtems_rtl_unresolv_rec* rec,
0198                                           void*                   data)
0199 {
0200   rtl_unresolved_name_data* nd = (rtl_unresolved_name_data*) data;
0201   if (rec == nd->rec)
0202     return true;
0203   if (rec->type == rtems_rtl_unresolved_symbol)
0204     ++nd->index;
0205   return false;
0206 }
0207 
0208 static int
0209 rtems_rtl_unresolved_find_index (rtems_rtl_unresolv_rec* rec)
0210 {
0211   rtl_unresolved_name_data nd = {
0212     .name = NULL,
0213     .length = 0,
0214     .rec = rec,
0215     .index = 1,
0216     .offset = 0
0217   };
0218   if (rtems_rtl_unresolved_iterate (rtems_rtl_unresolved_find_index_iterator,
0219                                     &nd))
0220     return nd.index;
0221   return -1;
0222 }
0223 
0224 static bool
0225 rtems_rtl_unresolved_reindex_iterator (rtems_rtl_unresolv_rec* rec,
0226                                        void*                   data)
0227 {
0228   rtl_unresolved_name_data* nd = (rtl_unresolved_name_data*) data;
0229   /*
0230    * Reindexing only effects the reloc records.
0231    */
0232   if (rec->type == rtems_rtl_unresolved_reloc)
0233   {
0234     if (rec->rec.reloc.name >= nd->index)
0235       rec->rec.reloc.name += nd->offset;
0236   }
0237   return false;
0238 }
0239 
0240 static void
0241 rtems_rtl_unresolved_reindex_names (uint16_t index, int offset)
0242 {
0243   rtl_unresolved_name_data nd = {
0244     .name = NULL,
0245     .length = 0,
0246     .rec = NULL,
0247     .index = index,
0248     .offset = offset
0249   };
0250   rtems_rtl_unresolved_iterate (rtems_rtl_unresolved_reindex_iterator,
0251                                 &nd);
0252 }
0253 
0254 /**
0255  * Struct to pass relocation data in the iterator.
0256  */
0257 typedef struct rtems_rtl_unresolved_reloc_data
0258 {
0259   uint16_t                name;     /**< Name index. */
0260   rtems_rtl_unresolv_rec* name_rec; /**< Name record. */
0261   rtems_rtl_obj_sym*      sym;      /**< The symbol record. */
0262 } rtems_rtl_unresolved_reloc_data;
0263 
0264 static bool
0265 rtems_rtl_unresolved_resolve_reloc (rtems_rtl_unresolv_rec* rec,
0266                                     void*                   data)
0267 {
0268   if (rec->type == rtems_rtl_unresolved_reloc)
0269   {
0270     rtems_chain_control*             pending;
0271     rtems_rtl_unresolved_reloc_data* rd;
0272 
0273     rd = (rtems_rtl_unresolved_reloc_data*) data;
0274 
0275     if (rec->rec.reloc.name == rd->name && rec->rec.reloc.obj != NULL)
0276     {
0277       if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED))
0278         printf ("rtl: unresolv: resolve reloc: %s\n",
0279                 rd->name_rec->rec.name.name);
0280 
0281       if (rtems_rtl_obj_relocate_unresolved (&rec->rec.reloc, rd->sym))
0282       {
0283         /*
0284          * If all unresolved externals are resolved add the obj module
0285          * to the pending queue. This will flush the object module's
0286          * data from the cache and call it's constructors.
0287          */
0288         if (rec->rec.reloc.obj->unresolved == 0)
0289         {
0290           pending = rtems_rtl_pending_unprotected ();
0291           rtems_chain_extract (&rec->rec.reloc.obj->link);
0292           rtems_chain_append (pending, &rec->rec.reloc.obj->link);
0293         }
0294 
0295         /*
0296          * Set the object pointer to NULL to indicate the record is
0297          * not used anymore. Update the reference count of the name so
0298          * it can garbage collected if not referenced. The sweep after
0299          * relocating will remove the reloc records with obj set to
0300          * NULL and names with a reference count of 0.
0301          */
0302         rec->rec.reloc.obj = NULL;
0303         if (rd->name_rec != NULL && rd->name_rec->rec.name.refs > 0)
0304           --rd->name_rec->rec.name.refs;
0305       }
0306     }
0307   }
0308   return false;
0309 }
0310 
0311 static bool
0312 rtems_rtl_unresolved_resolve_iterator (rtems_rtl_unresolv_rec* rec,
0313                                        void*                   data)
0314 {
0315   if (rec->type == rtems_rtl_unresolved_symbol)
0316   {
0317     rtems_rtl_unresolved_reloc_data* rd;
0318     rd = (rtems_rtl_unresolved_reloc_data*) data;
0319 
0320     ++rd->name;
0321 
0322     if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED))
0323       printf ("rtl: unresolv: lookup: %d: %s\n", rd->name, rec->rec.name.name);
0324 
0325     rd->sym = rtems_rtl_symbol_global_find (rec->rec.name.name);
0326 
0327     if (rd->sym)
0328     {
0329       if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED))
0330         printf ("rtl: unresolv: found: %s\n", rec->rec.name.name);
0331 
0332       rd->name_rec = rec;
0333 
0334       rtems_rtl_unresolved_iterate (rtems_rtl_unresolved_resolve_reloc, rd);
0335 
0336       rd->name_rec = NULL;
0337       rd->sym = NULL;
0338     }
0339   }
0340 
0341   return false;
0342 }
0343 
0344 /**
0345  * Struct to pass archive relocation data in the iterator.
0346  */
0347 typedef struct rtems_rtl_unresolved_archive_reloc_data
0348 {
0349   uint16_t                 name;     /**< Name index. */
0350   rtems_rtl_archive_search result;   /**< The result of the load. */
0351   rtems_rtl_archives*      archives; /**< The archives to search. */
0352 } rtems_rtl_unresolved_archive_reloc_data;
0353 
0354 static bool
0355 rtems_rtl_unresolved_archive_iterator (rtems_rtl_unresolv_rec* rec,
0356                                        void*                   data)
0357 {
0358   if (rec->type == rtems_rtl_unresolved_symbol)
0359   {
0360     rtems_rtl_unresolved_archive_reloc_data* ard;
0361     ard = (rtems_rtl_unresolved_archive_reloc_data*) data;
0362 
0363     ++ard->name;
0364 
0365     if ((rec->rec.name.flags & RTEMS_RTL_UNRESOLV_SYM_SEARCH_ARCHIVE) != 0)
0366     {
0367       rtems_rtl_archive_search result;
0368 
0369       if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED))
0370         printf ("rtl: unresolv: archive lookup: %d: %s\n",
0371                 ard->name, rec->rec.name.name);
0372 
0373       result = rtems_rtl_archive_obj_load (ard->archives,
0374                                            rec->rec.name.name, true);
0375       if (result != rtems_rtl_archive_search_not_found)
0376       {
0377         rec->rec.name.flags &= ~RTEMS_RTL_UNRESOLV_SYM_SEARCH_ARCHIVE;
0378         ard->result = result;
0379         return true;
0380       }
0381     }
0382   }
0383 
0384   return false;
0385 }
0386 
0387 static bool
0388 rtems_rtl_unresolved_archive_search_iterator (rtems_rtl_unresolv_rec* rec,
0389                                               void*                   data)
0390 {
0391   if (rec->type == rtems_rtl_unresolved_symbol)
0392     rec->rec.name.flags |= RTEMS_RTL_UNRESOLV_SYM_SEARCH_ARCHIVE;
0393   return false;
0394 }
0395 
0396 static rtems_rtl_unresolv_block*
0397 rtems_rtl_unresolved_alloc_recs (rtems_rtl_unresolved* unresolved,
0398                                  size_t                count)
0399 {
0400   rtems_chain_node* node = rtems_chain_first (&unresolved->blocks);
0401   while (!rtems_chain_is_tail (&unresolved->blocks, node))
0402   {
0403     rtems_rtl_unresolv_block* block = (rtems_rtl_unresolv_block*) node;
0404 
0405     if (block->recs + count <= unresolved->block_recs)
0406       return block;
0407     node = rtems_chain_next (node);
0408   }
0409   return NULL;
0410 }
0411 
0412 static void
0413 rtems_rtl_unresolved_clean_block (rtems_rtl_unresolv_block* block,
0414                                   rtems_rtl_unresolv_rec*   rec,
0415                                   size_t                    count,
0416                                   size_t                    recs_per_block)
0417 {
0418   size_t index = rtems_rtl_unresolved_rec_index (block, rec);
0419   size_t bytes =
0420     (block->recs - index - count) * sizeof (rtems_rtl_unresolv_rec);
0421   if (bytes)
0422     memmove (rec, rec + count, bytes);
0423   block->recs -= count;
0424   bytes = count * sizeof (rtems_rtl_unresolv_rec);
0425   memset (&block->rec[block->recs], 0, bytes);
0426 }
0427 
0428 static rtems_chain_node*
0429 rtems_rtl_unresolved_delete_block_if_empty (rtems_chain_control*      blocks,
0430                                             rtems_rtl_unresolv_block* block)
0431 {
0432   rtems_chain_node* node = &block->link;
0433   rtems_chain_node* next_node = rtems_chain_next (node);
0434   /*
0435    * Always leave a single block allocated. Eases possible heap fragmentation.
0436    */
0437   if (block->recs == 0 && !rtems_chain_has_only_one_node (blocks))
0438   {
0439     if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED))
0440       printf ("rtl: unresolv: block-del %p\n", block);
0441     rtems_chain_extract (node);
0442     rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_EXTERNAL, block);
0443   }
0444   return next_node;
0445 }
0446 
0447 static void
0448 rtems_rtl_unresolved_compact (void)
0449 {
0450   rtems_rtl_unresolved* unresolved = rtems_rtl_unresolved_unprotected ();
0451   if (unresolved)
0452   {
0453     /*
0454      * Iterate over the blocks removing any empty strings. If a string is
0455      * removed update the indexes of all strings above this level.
0456      */
0457     rtems_chain_node* node = rtems_chain_first (&unresolved->blocks);
0458     uint16_t          index = 0;
0459     while (!rtems_chain_is_tail (&unresolved->blocks, node))
0460     {
0461       rtems_rtl_unresolv_block* block = (rtems_rtl_unresolv_block*) node;
0462       rtems_rtl_unresolv_rec*   rec = rtems_rtl_unresolved_rec_first (block);
0463       while (!rtems_rtl_unresolved_rec_is_last (block, rec))
0464       {
0465         bool next_rec = true;
0466 
0467         if (rec->type == rtems_rtl_unresolved_symbol)
0468         {
0469           ++index;
0470           if (rec->rec.name.refs == 0)
0471           {
0472             size_t name_recs;
0473             if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED))
0474               printf ("rtl: unresolv: remove name: %s\n", rec->rec.name.name);
0475             rtems_rtl_unresolved_reindex_names (index, -1);
0476             /*
0477              * Compact the block removing the name record.
0478              */
0479             name_recs = rtems_rtl_unresolved_symbol_recs (rec->rec.name.name);
0480             rtems_rtl_unresolved_clean_block (block, rec, name_recs,
0481                                               unresolved->block_recs);
0482             --index;
0483             next_rec = false;
0484           }
0485         }
0486         else if (rec->type == rtems_rtl_unresolved_reloc)
0487         {
0488           if (rec->rec.reloc.obj == NULL)
0489           {
0490             rtems_rtl_unresolved_clean_block (block, rec, 1,
0491                                               unresolved->block_recs);
0492             next_rec = false;
0493           }
0494         }
0495 
0496         if (next_rec)
0497           rec = rtems_rtl_unresolved_rec_next (rec);
0498       }
0499 
0500       node = rtems_rtl_unresolved_delete_block_if_empty (&unresolved->blocks,
0501                                                          block);
0502     }
0503   }
0504 }
0505 
0506 bool
0507 rtems_rtl_unresolved_table_open (rtems_rtl_unresolved* unresolved,
0508                                  size_t                block_recs)
0509 {
0510   unresolved->marker = 0xdeadf00d;
0511   unresolved->block_recs = block_recs;
0512   rtems_chain_initialize_empty (&unresolved->blocks);
0513   return rtems_rtl_unresolved_block_alloc (unresolved);
0514 }
0515 
0516 void
0517 rtems_rtl_unresolved_table_close (rtems_rtl_unresolved* unresolved)
0518 {
0519   rtems_chain_node* node = rtems_chain_first (&unresolved->blocks);
0520   while (!rtems_chain_is_tail (&unresolved->blocks, node))
0521   {
0522     rtems_chain_node* next = rtems_chain_next (node);
0523     rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_EXTERNAL, node);
0524     node = next;
0525   }
0526 }
0527 
0528 bool
0529 rtems_rtl_unresolved_iterate (rtems_rtl_unresolved_iterator iterator,
0530                               void*                         data)
0531 {
0532   rtems_rtl_unresolved* unresolved = rtems_rtl_unresolved_unprotected ();
0533   if (unresolved)
0534   {
0535     rtems_chain_node* node = rtems_chain_first (&unresolved->blocks);
0536     while (!rtems_chain_is_tail (&unresolved->blocks, node))
0537     {
0538       rtems_rtl_unresolv_block* block = (rtems_rtl_unresolv_block*) node;
0539       rtems_rtl_unresolv_rec*   rec = rtems_rtl_unresolved_rec_first (block);
0540 
0541       while (!rtems_rtl_unresolved_rec_is_last (block, rec))
0542       {
0543         if (iterator (rec, data))
0544           return true;
0545         rec = rtems_rtl_unresolved_rec_next (rec);
0546       }
0547 
0548       node = rtems_chain_next (node);
0549     }
0550   }
0551   return false;
0552 }
0553 
0554 bool
0555 rtems_rtl_unresolved_add (rtems_rtl_obj*        obj,
0556                           const uint16_t        flags,
0557                           const char*           name,
0558                           const uint16_t        sect,
0559                           const rtems_rtl_word* rel)
0560 {
0561   rtems_rtl_unresolved*     unresolved;
0562   rtems_rtl_unresolv_block* block;
0563   rtems_rtl_unresolv_rec*   rec;
0564   int                       name_index;
0565 
0566   if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED))
0567     printf ("rtl: unresolv: add: %s(s:%d) -> %s\n",
0568             rtems_rtl_obj_oname (obj), sect, name);
0569 
0570   unresolved = rtems_rtl_unresolved_unprotected ();
0571   if (!unresolved)
0572     return false;
0573 
0574   /*
0575    * Is the name present?
0576    */
0577   name_index = rtems_rtl_unresolved_find_name (name);
0578 
0579   /*
0580    * An index less than 0 means the name was not found.
0581    */
0582   if (name_index < 0)
0583   {
0584     size_t name_recs;
0585 
0586     name_recs = rtems_rtl_unresolved_symbol_recs (name);
0587 
0588     /*
0589      * Is there enough room to fit the name ? It not add a new block.
0590      */
0591     block = rtems_rtl_unresolved_alloc_recs (unresolved, name_recs);
0592     if (block == NULL)
0593     {
0594       block = rtems_rtl_unresolved_block_alloc (unresolved);
0595       if (!block)
0596         return false;
0597     }
0598 
0599     /*
0600      * Find the record in the block.
0601      */
0602     rec = rtems_rtl_unresolved_rec_first_free (block);
0603 
0604     /*
0605      * Enter the new record before reindexing so the iterator can see
0606      * it and the iterator is called.
0607      */
0608     rec->type = rtems_rtl_unresolved_symbol;
0609     rec->rec.name.refs = 1;
0610     rec->rec.name.flags = RTEMS_RTL_UNRESOLV_SYM_SEARCH_ARCHIVE;
0611     rec->rec.name.length = strlen (name) + 1;
0612     memcpy ((void*) &rec->rec.name.name[0], name, rec->rec.name.length);
0613     block->recs += name_recs;
0614 
0615     /*
0616      * Find the name index for the name and then reindex the names which
0617      * are moved up because of the insertion.
0618      */
0619     name_index = rtems_rtl_unresolved_find_index (rec);
0620     if (name_index < 0)
0621     {
0622       rtems_rtl_set_error (ENOMEM, "internal unresolved block error");
0623       return false;
0624     }
0625 
0626     rtems_rtl_unresolved_reindex_names (name_index, 1);
0627   }
0628 
0629   /*
0630    * Find the first block with a spare record.
0631    */
0632   block = rtems_rtl_unresolved_alloc_recs (unresolved, 1);
0633   if (block == NULL)
0634   {
0635     block = rtems_rtl_unresolved_block_alloc (unresolved);
0636     if (!block)
0637       return false;
0638   }
0639 
0640   rec = rtems_rtl_unresolved_rec_first_free (block);
0641   rec->type = rtems_rtl_unresolved_reloc;
0642   rec->rec.reloc.obj = obj;
0643   rec->rec.reloc.flags = flags;
0644   rec->rec.reloc.name = name_index;
0645   rec->rec.reloc.sect = sect;
0646   rec->rec.reloc.rel[0] = rel[0];
0647   rec->rec.reloc.rel[1] = rel[1];
0648   rec->rec.reloc.rel[2] = rel[2];
0649 
0650   ++block->recs;
0651 
0652   return true;
0653 }
0654 
0655 void
0656 rtems_rtl_unresolved_resolve (void)
0657 {
0658   bool resolving = true;
0659 
0660   if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED))
0661     printf ("rtl: unresolv: global resolve\n");
0662 
0663   /*
0664    * The resolving process is two separate stages, The first stage is to
0665    * iterate over the unresolved symbols searching the global symbol table. If
0666    * a symbol is found iterate over the unresolved relocation records for the
0667    * symbol fixing up the relocations. The second stage is to search the
0668    * archives for symbols we have not searched before and if a symbol is found
0669    * in an archve load the object file. Loading an object file stops the
0670    * search of the archives for symbols and stage one is performed again. The
0671    * process repeats until no more symbols are resolved or there is an error.
0672    */
0673   while (resolving)
0674   {
0675     rtems_rtl_unresolved_reloc_data rd = {
0676       .name = 0,
0677       .name_rec = NULL,
0678       .sym = NULL
0679     };
0680     rtems_rtl_unresolved_archive_reloc_data ard = {
0681       .name = 0,
0682       .result = rtems_rtl_archive_search_not_found,
0683       .archives = rtems_rtl_archives_unprotected ()
0684     };
0685 
0686     rtems_rtl_unresolved_iterate (rtems_rtl_unresolved_resolve_iterator, &rd);
0687     rtems_rtl_unresolved_compact ();
0688     rtems_rtl_unresolved_iterate (rtems_rtl_unresolved_archive_iterator, &ard);
0689 
0690     resolving = ard.result == rtems_rtl_archive_search_loaded;
0691   }
0692 
0693   if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED))
0694     rtems_rtl_unresolved_dump ();
0695 }
0696 
0697 bool
0698 rtems_rtl_trampoline_add (rtems_rtl_obj*        obj,
0699                           const uint16_t        flags,
0700                           const uint16_t        sect,
0701                           const rtems_rtl_word  symvalue,
0702                           const rtems_rtl_word* rel)
0703 {
0704   rtems_rtl_unresolved*     unresolved;
0705   rtems_rtl_unresolv_block* block;
0706   rtems_rtl_unresolv_rec*   rec;
0707 
0708   if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED))
0709     printf ("rtl: tramp: add: %s sect:%d flags:%04x\n",
0710             rtems_rtl_obj_oname (obj), sect, flags);
0711 
0712   unresolved = rtems_rtl_unresolved_unprotected ();
0713   if (!unresolved)
0714     return false;
0715 
0716   block = rtems_rtl_unresolved_alloc_recs (unresolved, 1);
0717   if (block == NULL)
0718   {
0719     block = rtems_rtl_unresolved_block_alloc (unresolved);
0720     if (!block)
0721       return false;
0722   }
0723 
0724   rec = rtems_rtl_unresolved_rec_first_free (block);
0725   rec->type = rtems_rtl_trampoline_reloc;
0726   rec->rec.tramp.obj = obj;
0727   rec->rec.tramp.flags = flags;
0728   rec->rec.tramp.sect = sect;
0729   rec->rec.tramp.symvalue = symvalue;
0730   rec->rec.tramp.rel[0] = rel[0];
0731   rec->rec.tramp.rel[1] = rel[1];
0732   rec->rec.tramp.rel[2] = rel[2];
0733 
0734   ++block->recs;
0735 
0736   return true;
0737 }
0738 
0739 void
0740 rtems_rtl_trampoline_remove (rtems_rtl_obj* obj)
0741 {
0742   rtems_rtl_unresolved* unresolved = rtems_rtl_unresolved_unprotected ();
0743   if (unresolved)
0744   {
0745     /*
0746      * Iterate over the blocks clearing any trampoline records.
0747      */
0748     rtems_chain_node* node = rtems_chain_first (&unresolved->blocks);
0749     while (!rtems_chain_is_tail (&unresolved->blocks, node))
0750     {
0751       rtems_rtl_unresolv_block* block = (rtems_rtl_unresolv_block*) node;
0752       rtems_rtl_unresolv_rec*   rec = rtems_rtl_unresolved_rec_first (block);
0753 
0754       /*
0755        * Search the table for a trampoline record and if found clean the
0756        * record moving the remaining records down the block.
0757        */
0758       while (!rtems_rtl_unresolved_rec_is_last (block, rec))
0759       {
0760         bool next_rec = true;
0761 
0762         if (rec->type == rtems_rtl_trampoline_reloc && rec->rec.tramp.obj == obj)
0763         {
0764             rtems_rtl_unresolved_clean_block (block, rec, 1,
0765                                               unresolved->block_recs);
0766             next_rec = false;
0767         }
0768 
0769         if (next_rec)
0770           rec = rtems_rtl_unresolved_rec_next (rec);
0771       }
0772 
0773       node = rtems_rtl_unresolved_delete_block_if_empty (&unresolved->blocks,
0774                                                          block);
0775     }
0776   }
0777 }
0778 
0779 /**
0780  * Struct to pass relocation data in the iterator.
0781  */
0782 typedef struct rtems_rtl_unresolved_dump_data
0783 {
0784   size_t rec;
0785   size_t names;
0786   bool   show_relocs;
0787 } rtems_rtl_unresolved_dump_data;
0788 
0789 static bool
0790 rtems_rtl_unresolved_dump_iterator (rtems_rtl_unresolv_rec* rec,
0791                                     void*                   data)
0792 {
0793   rtems_rtl_unresolved_dump_data* dd;
0794   dd = (rtems_rtl_unresolved_dump_data*) data;
0795   switch (rec->type)
0796   {
0797   case rtems_rtl_unresolved_empty:
0798     printf (" %03zu: 0: empty\n", dd->rec);
0799     break;
0800   case rtems_rtl_unresolved_symbol:
0801     ++dd->names;
0802     printf (" %3zu: 1:  name: %3zu refs:%4d: flags:%04x %s (%d)\n",
0803             dd->rec, dd->names,
0804             rec->rec.name.refs,
0805             rec->rec.name.flags,
0806             rec->rec.name.name,
0807             rec->rec.name.length);
0808     break;
0809   case rtems_rtl_unresolved_reloc:
0810   case rtems_rtl_trampoline_reloc:
0811     if (dd->show_relocs)
0812       printf (" %3zu: 2:reloc%c: obj:%s name:%2d: sect:%d\n",
0813               dd->rec,
0814               rec->type == rtems_rtl_unresolved_reloc ? 'R' : 'T',
0815               rec->rec.reloc.obj == NULL ? "resolved" : rec->rec.reloc.obj->oname,
0816               rec->rec.reloc.name,
0817               rec->rec.reloc.sect);
0818     break;
0819   default:
0820     printf (" %03zu: %d: unknown\n", dd->rec, rec->type);
0821     break;
0822   }
0823   ++dd->rec;
0824   return false;
0825 }
0826 
0827 void
0828 rtems_rtl_unresolved_dump (void)
0829 {
0830   rtems_rtl_unresolved_dump_data dd = { 0 };
0831   printf ("RTL Unresolved data:\n");
0832   rtems_rtl_unresolved_iterate (rtems_rtl_unresolved_dump_iterator, &dd);
0833 }
0834 
0835 void
0836 rtems_rtl_unresolved_set_archive_search (void)
0837 {
0838   rtems_rtl_unresolved_iterate (rtems_rtl_unresolved_archive_search_iterator,
0839                                 NULL);
0840 }