diff options
Diffstat (limited to 'cpukit/libdl/rtl-unresolved.c')
-rw-r--r-- | cpukit/libdl/rtl-unresolved.c | 388 |
1 files changed, 225 insertions, 163 deletions
diff --git a/cpukit/libdl/rtl-unresolved.c b/cpukit/libdl/rtl-unresolved.c index 7e2d920594..0e70c5dacf 100644 --- a/cpukit/libdl/rtl-unresolved.c +++ b/cpukit/libdl/rtl-unresolved.c @@ -36,13 +36,13 @@ rtems_rtl_unresolved_block_alloc (rtems_rtl_unresolved* unresolved) */ size_t size = (sizeof(rtems_rtl_unresolv_block) + - (sizeof(rtems_rtl_unresolv_rec) * (unresolved->block_recs - 1))); + (sizeof(rtems_rtl_unresolv_rec) * unresolved->block_recs)); rtems_rtl_unresolv_block* block = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_EXTERNAL, size, true); if (block) { if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED)) - printf ("rtl: unresolv: block-alloc %p\n", block); + printf ("rtl: unresolv: block-alloc %p (%p)\n", block, block + size); rtems_chain_append (&unresolved->blocks, &block->link); } else @@ -53,28 +53,31 @@ rtems_rtl_unresolved_block_alloc (rtems_rtl_unresolved* unresolved) static size_t rtems_rtl_unresolved_symbol_rec_count (size_t length) { - return ((length + sizeof(rtems_rtl_unresolv_symbol) - 1) / - sizeof(rtems_rtl_unresolv_symbol)); + const size_t rec_size = sizeof(rtems_rtl_unresolv_rec); + const size_t rec_name_header = offsetof(rtems_rtl_unresolv_rec, rec.name.name); + /* + * Add on the nul and rmeove 1 to be inside a record. + */ + return ((length + rec_name_header - 1) / rec_size) + 1; } - static size_t rtems_rtl_unresolved_symbol_recs (const char* name) { - return rtems_rtl_unresolved_symbol_rec_count (strlen (name)); + return rtems_rtl_unresolved_symbol_rec_count (strlen (name) + 1); } static int rtems_rtl_unresolved_rec_index (rtems_rtl_unresolv_block* block, rtems_rtl_unresolv_rec* rec) { - return (rec - &block->rec) / sizeof (rtems_rtl_unresolv_rec); + return rec - &block->rec[0]; } static rtems_rtl_unresolv_rec* rtems_rtl_unresolved_rec_first (rtems_rtl_unresolv_block* block) { - return &block->rec; + return &block->rec[0]; } static rtems_rtl_unresolv_rec* @@ -83,6 +86,7 @@ rtems_rtl_unresolved_rec_next (rtems_rtl_unresolv_rec* rec) switch (rec->type) { case rtems_rtl_unresolved_empty: + default: /* * Empty returns NULL. The end of the records in the block. */ @@ -99,9 +103,6 @@ rtems_rtl_unresolved_rec_next (rtems_rtl_unresolv_rec* rec) case rtems_rtl_unresolved_reloc: ++rec; break; - - default: - break; } return rec; @@ -111,50 +112,121 @@ static bool rtems_rtl_unresolved_rec_is_last (rtems_rtl_unresolv_block* block, rtems_rtl_unresolv_rec* rec) { - int index = (rec - &block->rec) / sizeof (rec); - return !rec || (index >= block->recs) || (rec->type == rtems_rtl_unresolved_empty); + int index = rtems_rtl_unresolved_rec_index (block, rec); + return (rec == NULL || + (index < 0) || + (index >= block->recs) || + (rec->type == rtems_rtl_unresolved_empty)); } static rtems_rtl_unresolv_rec* rtems_rtl_unresolved_rec_first_free (rtems_rtl_unresolv_block* block) { - return &block->rec + block->recs; + return &block->rec[0] + block->recs; } -static int -rtems_rtl_unresolved_find_name (rtems_rtl_unresolved* unresolved, - const char* name, - bool update_refcount) +/** + * Name management iterator data. + */ +typedef struct { - size_t length = strlen (name) + 1; - int index = 1; + const char* name; /**< The name being searched for. */ + size_t length; /**< The length of the name. */ + rtems_rtl_unresolv_rec* rec; /**< The record being searched for. */ + int index; /**< The name's index. */ + int offset; /**< The offset to move the index. */ +} rtl_unresolved_name_data; - rtems_chain_node* node = rtems_chain_first (&unresolved->blocks); - while (!rtems_chain_is_tail (&unresolved->blocks, node)) +static bool +rtems_rtl_unresolved_find_name_iterator (rtems_rtl_unresolv_rec* rec, + void* data) +{ + rtl_unresolved_name_data* nd = (rtl_unresolved_name_data*) data; + if (rec->type == rtems_rtl_unresolved_symbol) { - rtems_rtl_unresolv_block* block = (rtems_rtl_unresolv_block*) node; - rtems_rtl_unresolv_rec* rec = rtems_rtl_unresolved_rec_first (block); - - while (!rtems_rtl_unresolved_rec_is_last (block, rec)) + if ((rec->rec.name.length == nd->length) + && (strcmp (rec->rec.name.name, nd->name) == 0)) { - if (rec->type == rtems_rtl_unresolved_symbol) - { - if ((rec->rec.name.length == length) - && (strcmp (rec->rec.name.name, name) == 0)) - { - if (update_refcount) - ++rec->rec.name.refs; - return index; - } - ++index; - } - rec = rtems_rtl_unresolved_rec_next (rec); + ++rec->rec.name.refs; + return true; } + ++nd->index; + } + return false; +} - node = rtems_chain_next (node); +static int +rtems_rtl_unresolved_find_name (const char* name) +{ + rtl_unresolved_name_data nd = { + .name = name, + .length = strlen (name) + 1, + .rec = NULL, + .index = 1, + .offset = 0 + }; + if (rtems_rtl_unresolved_iterate (rtems_rtl_unresolved_find_name_iterator, + &nd)) + return nd.index; + return -1; +} + +static bool +rtems_rtl_unresolved_find_index_iterator (rtems_rtl_unresolv_rec* rec, + void* data) +{ + rtl_unresolved_name_data* nd = (rtl_unresolved_name_data*) data; + if (rec == nd->rec) + return true; + if (rec->type == rtems_rtl_unresolved_symbol) + ++nd->index; + return false; +} + +static int +rtems_rtl_unresolved_find_index (rtems_rtl_unresolv_rec* rec) +{ + rtl_unresolved_name_data nd = { + .name = NULL, + .length = 0, + .rec = rec, + .index = 1, + .offset = 0 + }; + if (rtems_rtl_unresolved_iterate (rtems_rtl_unresolved_find_index_iterator, + &nd)) + return nd.index; + return -1; +} + +static bool +rtems_rtl_unresolved_reindex_iterator (rtems_rtl_unresolv_rec* rec, + void* data) +{ + rtl_unresolved_name_data* nd = (rtl_unresolved_name_data*) data; + /* + * Reindexing only effects the reloc records. + */ + if (rec->type == rtems_rtl_unresolved_reloc) + { + if (rec->rec.reloc.name >= nd->index) + rec->rec.reloc.name += nd->offset; } + return false; +} - return 0 - index; +static void +rtems_rtl_unresolved_reindex_names (uint16_t index, int offset) +{ + rtl_unresolved_name_data nd = { + .name = NULL, + .length = 0, + .rec = NULL, + .index = index, + .offset = offset + }; + rtems_rtl_unresolved_iterate (rtems_rtl_unresolved_reindex_iterator, + &nd); } /** @@ -184,29 +256,31 @@ rtems_rtl_unresolved_resolve_reloc (rtems_rtl_unresolv_rec* rec, printf ("rtl: unresolv: resolve reloc: %s\n", rd->name_rec->rec.name.name); - rtems_rtl_obj_relocate_unresolved (&rec->rec.reloc, rd->sym); - - /* - * If all unresolved externals are resolved add the obj module - * to the pending queue. This will flush the object module's - * data from the cache and call it's constructors. - */ - if (rec->rec.reloc.obj->unresolved == 0) + if (rtems_rtl_obj_relocate_unresolved (&rec->rec.reloc, rd->sym)) { - pending = rtems_rtl_pending_unprotected (); - rtems_chain_extract (&rec->rec.reloc.obj->link); - rtems_chain_append (pending, &rec->rec.reloc.obj->link); - } + /* + * If all unresolved externals are resolved add the obj module + * to the pending queue. This will flush the object module's + * data from the cache and call it's constructors. + */ + if (rec->rec.reloc.obj->unresolved == 0) + { + pending = rtems_rtl_pending_unprotected (); + rtems_chain_extract (&rec->rec.reloc.obj->link); + rtems_chain_append (pending, &rec->rec.reloc.obj->link); + } - /* - * Check Set the object pointer to NULL to indicate the record is not used - * anymore. Update the reference count of the name. The sweep after - * relocating will remove the reloc records with obj set to NULL and - * names with a reference count of 0. - */ - rec->rec.reloc.obj = NULL; - if (rd->name_rec != NULL && rd->name_rec->rec.name.refs > 0) - --rd->name_rec->rec.name.refs; + /* + * Set the object pointer to NULL to indicate the record is + * not used anymore. Update the reference count of the name so + * it can garbage collected if not referenced. The sweep after + * relocating will remove the reloc records with obj set to + * NULL and names with a reference count of 0. + */ + rec->rec.reloc.obj = NULL; + if (rd->name_rec != NULL && rd->name_rec->rec.name.refs > 0) + --rd->name_rec->rec.name.refs; + } } } return false; @@ -250,9 +324,9 @@ rtems_rtl_unresolved_resolve_iterator (rtems_rtl_unresolv_rec* rec, */ typedef struct rtems_rtl_unresolved_archive_reloc_data { - uint16_t name; /**< Name index. */ - bool loaded; /**< Object file loaded. */ - rtems_rtl_archives* archives; /**< The archives to search. */ + uint16_t name; /**< Name index. */ + rtems_rtl_archive_search result; /**< The result of the load. */ + rtems_rtl_archives* archives; /**< The archives to search. */ } rtems_rtl_unresolved_archive_reloc_data; static bool @@ -268,17 +342,18 @@ rtems_rtl_unresolved_archive_iterator (rtems_rtl_unresolv_rec* rec, if ((rec->rec.name.flags & RTEMS_RTL_UNRESOLV_SYM_SEARCH_ARCHIVE) != 0) { - rtems_rtl_archive_search load; + rtems_rtl_archive_search result; if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED)) printf ("rtl: unresolv: archive lookup: %d: %s\n", ard->name, rec->rec.name.name); - load = rtems_rtl_archive_obj_load (ard->archives, - rec->rec.name.name, true); - if (load == rtems_rtl_archive_search_loaded) + result = rtems_rtl_archive_obj_load (ard->archives, + rec->rec.name.name, true); + if (result != rtems_rtl_archive_search_not_found) { - ard->loaded = true; + rec->rec.name.flags &= ~RTEMS_RTL_UNRESOLV_SYM_SEARCH_ARCHIVE; + ard->result = result; return true; } } @@ -292,10 +367,26 @@ rtems_rtl_unresolved_archive_search_iterator (rtems_rtl_unresolv_rec* rec, void* data) { if (rec->type == rtems_rtl_unresolved_symbol) - rec->rec.name.flags = RTEMS_RTL_UNRESOLV_SYM_SEARCH_ARCHIVE; + rec->rec.name.flags |= RTEMS_RTL_UNRESOLV_SYM_SEARCH_ARCHIVE; return false; } +static rtems_rtl_unresolv_block* +rtems_rtl_unresolved_alloc_recs (rtems_rtl_unresolved* unresolved, + size_t count) +{ + rtems_chain_node* node = rtems_chain_first (&unresolved->blocks); + while (!rtems_chain_is_tail (&unresolved->blocks, node)) + { + rtems_rtl_unresolv_block* block = (rtems_rtl_unresolv_block*) node; + + if (block->recs + count <= unresolved->block_recs) + return block; + node = rtems_chain_next (node); + } + return NULL; +} + static void rtems_rtl_unresolved_clean_block (rtems_rtl_unresolv_block* block, rtems_rtl_unresolv_rec* rec, @@ -309,7 +400,7 @@ rtems_rtl_unresolved_clean_block (rtems_rtl_unresolv_block* block, memmove (rec, rec + count, bytes); block->recs -= count; bytes = count * sizeof (rtems_rtl_unresolv_rec); - memset (&block->rec + block->recs, 0, bytes); + memset (&block->rec[block->recs], 0, bytes); } static void @@ -328,51 +419,19 @@ rtems_rtl_unresolved_compact (void) { rtems_rtl_unresolv_block* block = (rtems_rtl_unresolv_block*) node; rtems_rtl_unresolv_rec* rec = rtems_rtl_unresolved_rec_first (block); - while (!rtems_rtl_unresolved_rec_is_last (block, rec)) { bool next_rec = true; + if (rec->type == rtems_rtl_unresolved_symbol) { ++index; if (rec->rec.name.refs == 0) { - /* - * Iterate over the remaining reloc records and update the index. - */ - rtems_chain_node* reindex_node; - rtems_rtl_unresolv_rec* reindex_first; - size_t name_recs; + size_t name_recs; if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED)) printf ("rtl: unresolv: remove name: %s\n", rec->rec.name.name); - reindex_node = node; - reindex_first = rtems_rtl_unresolved_rec_next (rec); - while (!rtems_chain_is_tail (&unresolved->blocks, reindex_node)) - { - rtems_rtl_unresolv_rec* reindex_rec; - rtems_rtl_unresolv_block* reindex_block; - reindex_block = (rtems_rtl_unresolv_block*) reindex_node; - if (reindex_first != NULL) - { - reindex_rec = reindex_first; - reindex_first = NULL; - } - else - { - reindex_rec = rtems_rtl_unresolved_rec_first (reindex_block); - } - while (!rtems_rtl_unresolved_rec_is_last (reindex_block, - reindex_rec)) - { - if (reindex_rec->type == rtems_rtl_unresolved_reloc) - { - if (reindex_rec->rec.reloc.name >= index) - --reindex_rec->rec.reloc.name; - } - reindex_rec = rtems_rtl_unresolved_rec_next (reindex_rec); - } - reindex_node = rtems_chain_next (reindex_node); - } + rtems_rtl_unresolved_reindex_names (index, -1); /* * Compact the block removing the name record. */ @@ -470,11 +529,9 @@ rtems_rtl_unresolved_add (rtems_rtl_obj* obj, const rtems_rtl_word* rel) { rtems_rtl_unresolved* unresolved; - rtems_chain_node* node; rtems_rtl_unresolv_block* block; rtems_rtl_unresolv_rec* rec; int name_index; - size_t name_recs; if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED)) printf ("rtl: unresolv: add: %s(s:%d) -> %s\n", @@ -485,69 +542,69 @@ rtems_rtl_unresolved_add (rtems_rtl_obj* obj, return false; /* - * Find the first block with a spare record. - */ - node = rtems_chain_first (&unresolved->blocks); - block = NULL; - while (!rtems_chain_is_tail (&unresolved->blocks, node)) - { - block = (rtems_rtl_unresolv_block*) node; - if (block->recs < unresolved->block_recs) - break; - block = NULL; - node = rtems_chain_next (node); - } - - /* - * No blocks with any spare records, allocate a new block. + * Is the name present? */ - if (!block) - { - block = rtems_rtl_unresolved_block_alloc (unresolved); - if (!block) - return false; - } - - name_index = rtems_rtl_unresolved_find_name (unresolved, name, true); - name_recs = rtems_rtl_unresolved_symbol_recs (name); + name_index = rtems_rtl_unresolved_find_name (name); /* - * An index less than 0 means the name is present and "0 - index" is the next - * index to use. + * An index less than 0 means the name was not found. */ if (name_index < 0) { - rtems_rtl_unresolv_block* name_block = block; + size_t name_recs; + + name_recs = rtems_rtl_unresolved_symbol_recs (name); /* * Is there enough room to fit the name ? It not add a new block. */ - if (name_recs > (unresolved->block_recs - block->recs)) + block = rtems_rtl_unresolved_alloc_recs (unresolved, name_recs); + if (block == NULL) { - name_block = rtems_rtl_unresolved_block_alloc (unresolved); - if (!name_block) + block = rtems_rtl_unresolved_block_alloc (unresolved); + if (!block) return false; } - rec = rtems_rtl_unresolved_rec_first_free (name_block); + /* + * Find the record in the block. + */ + rec = rtems_rtl_unresolved_rec_first_free (block); + + /* + * Enter the new record before reindexing so the iterator can see + * it and the iterator is called. + */ rec->type = rtems_rtl_unresolved_symbol; rec->rec.name.refs = 1; rec->rec.name.flags = RTEMS_RTL_UNRESOLV_SYM_SEARCH_ARCHIVE; rec->rec.name.length = strlen (name) + 1; - memcpy ((void*) &rec->rec.name.name[0], name, rec->rec.name.length + 1); + memcpy ((void*) &rec->rec.name.name[0], name, rec->rec.name.length); block->recs += name_recs; - name_index = 0 - name_index; /* - * If the name block is the reloc block and it is full allocate a new - * block for the relocation record. + * Find the name index for the name and then reindex the names which + * are moved up because of the insertion. */ - if ((block == name_block) && (block->recs >= unresolved->block_recs)) + name_index = rtems_rtl_unresolved_find_index (rec); + if (name_index < 0) { - block = rtems_rtl_unresolved_block_alloc (unresolved); - if (!block) - return false; + rtems_rtl_set_error (ENOMEM, "internal unresolved block error"); + return false; } + + rtems_rtl_unresolved_reindex_names (name_index, 1); + } + + /* + * Find the first block with a spare record. + */ + block = rtems_rtl_unresolved_alloc_recs (unresolved, 1); + if (block == NULL) + { + block = rtems_rtl_unresolved_block_alloc (unresolved); + if (!block) + return false; } rec = rtems_rtl_unresolved_rec_first_free (block); @@ -592,7 +649,7 @@ rtems_rtl_unresolved_resolve (void) }; rtems_rtl_unresolved_archive_reloc_data ard = { .name = 0, - .loaded = false, + .result = rtems_rtl_archive_search_not_found, .archives = rtems_rtl_archives_unprotected () }; @@ -600,7 +657,7 @@ rtems_rtl_unresolved_resolve (void) rtems_rtl_unresolved_compact (); rtems_rtl_unresolved_iterate (rtems_rtl_unresolved_archive_iterator, &ard); - resolving = ard.loaded; + resolving = ard.result == rtems_rtl_archive_search_loaded; } if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED)) @@ -627,6 +684,7 @@ typedef struct rtems_rtl_unresolved_dump_data { size_t rec; size_t names; + bool show_relocs; } rtems_rtl_unresolved_dump_data; static bool @@ -642,16 +700,20 @@ rtems_rtl_unresolved_dump_iterator (rtems_rtl_unresolv_rec* rec, break; case rtems_rtl_unresolved_symbol: ++dd->names; - printf (" %3zu: 1: name: %3d refs: %2d: %2d: %s\n", + printf (" %3zu: 1: name: %3d refs:%4d: flags:%04x %s (%d)\n", dd->rec, dd->names, - rec->rec.name.refs, rec->rec.name.length, rec->rec.name.name); + rec->rec.name.refs, + rec->rec.name.flags, + rec->rec.name.name, + rec->rec.name.length); break; case rtems_rtl_unresolved_reloc: - printf (" %3zu: 2: reloc: obj:%s name:%2d: sect:%d\n", - dd->rec, - rec->rec.reloc.obj->oname, - rec->rec.reloc.name, - rec->rec.reloc.sect); + if (dd->show_relocs) + printf (" %3zu: 2: reloc: obj:%s name:%2d: sect:%d\n", + dd->rec, + rec->rec.reloc.obj == NULL ? "resolved" : rec->rec.reloc.obj->oname, + rec->rec.reloc.name, + rec->rec.reloc.sect); break; default: printf (" %03zu: %d: unknown\n", dd->rec, rec->type); @@ -662,16 +724,16 @@ rtems_rtl_unresolved_dump_iterator (rtems_rtl_unresolv_rec* rec, } void -rtems_rtl_unresolved_set_archive_search (void) -{ - rtems_rtl_unresolved_iterate (rtems_rtl_unresolved_archive_search_iterator, - NULL); -} - -void rtems_rtl_unresolved_dump (void) { rtems_rtl_unresolved_dump_data dd = { 0 }; printf ("RTL Unresolved data:\n"); rtems_rtl_unresolved_iterate (rtems_rtl_unresolved_dump_iterator, &dd); } + +void +rtems_rtl_unresolved_set_archive_search (void) +{ + rtems_rtl_unresolved_iterate (rtems_rtl_unresolved_archive_search_iterator, + NULL); +} |