diff options
Diffstat (limited to 'cpukit/libdl/rtl-unresolved.c')
-rw-r--r-- | cpukit/libdl/rtl-unresolved.c | 160 |
1 files changed, 132 insertions, 28 deletions
diff --git a/cpukit/libdl/rtl-unresolved.c b/cpukit/libdl/rtl-unresolved.c index f42fc7d03d..4e81c3c64e 100644 --- a/cpukit/libdl/rtl-unresolved.c +++ b/cpukit/libdl/rtl-unresolved.c @@ -51,11 +51,17 @@ rtems_rtl_unresolved_block_alloc (rtems_rtl_unresolved* unresolved) } static size_t -rtems_rtl_unresolved_name_recs (const char* name) +rtems_rtl_unresolved_symbol_rec_count (size_t length) { - size_t length = strlen (name); - return ((length + sizeof(rtems_rtl_unresolv_name) - 1) / - sizeof(rtems_rtl_unresolv_name)); + return ((length + sizeof(rtems_rtl_unresolv_symbol) - 1) / + sizeof(rtems_rtl_unresolv_symbol)); +} + + +static size_t +rtems_rtl_unresolved_symbol_recs (const char* name) +{ + return rtems_rtl_unresolved_symbol_rec_count (strlen (name)); } static int @@ -83,12 +89,11 @@ rtems_rtl_unresolved_rec_next (rtems_rtl_unresolv_rec* rec) rec = NULL; break; - case rtems_rtl_unresolved_name: + case rtems_rtl_unresolved_symbol: /* * Determine how many records the name occupies. Round up. */ - rec += ((rec->rec.name.length + sizeof(rtems_rtl_unresolv_name) - 1) / - sizeof(rtems_rtl_unresolv_name)); + rec += rtems_rtl_unresolved_symbol_rec_count (rec->rec.name.length); break; case rtems_rtl_unresolved_reloc: @@ -132,7 +137,7 @@ rtems_rtl_unresolved_find_name (rtems_rtl_unresolved* unresolved, while (!rtems_rtl_unresolved_rec_is_last (block, rec)) { - if (rec->type == rtems_rtl_unresolved_name) + if (rec->type == rtems_rtl_unresolved_symbol) { if ((rec->rec.name.length == length) && (strcmp (rec->rec.name.name, name) == 0)) @@ -168,7 +173,9 @@ rtems_rtl_unresolved_resolve_reloc (rtems_rtl_unresolv_rec* rec, { if (rec->type == rtems_rtl_unresolved_reloc) { + rtems_chain_control* pending; rtems_rtl_unresolved_reloc_data* rd; + rd = (rtems_rtl_unresolved_reloc_data*) data; if (rec->rec.reloc.name == rd->name && rec->rec.reloc.obj != NULL) @@ -179,7 +186,18 @@ rtems_rtl_unresolved_resolve_reloc (rtems_rtl_unresolv_rec* rec, rtems_rtl_obj_relocate_unresolved (&rec->rec.reloc, rd->sym); /* - * Set the object pointer to NULL to indicate the record is not used + * 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_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. @@ -196,7 +214,7 @@ static bool rtems_rtl_unresolved_resolve_iterator (rtems_rtl_unresolv_rec* rec, void* data) { - if (rec->type == rtems_rtl_unresolved_name) + if (rec->type == rtems_rtl_unresolved_symbol) { rtems_rtl_unresolved_reloc_data* rd; rd = (rtems_rtl_unresolved_reloc_data*) data; @@ -215,7 +233,7 @@ rtems_rtl_unresolved_resolve_iterator (rtems_rtl_unresolv_rec* rec, rd->name_rec = rec; - rtems_rtl_unresolved_interate (rtems_rtl_unresolved_resolve_reloc, rd); + rtems_rtl_unresolved_iterate (rtems_rtl_unresolved_resolve_reloc, rd); rd->name_rec = NULL; rd->sym = NULL; @@ -225,6 +243,57 @@ rtems_rtl_unresolved_resolve_iterator (rtems_rtl_unresolv_rec* rec, return false; } +/** + * Struct to pass archive relocation data in the iterator. + */ +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. */ +} rtems_rtl_unresolved_archive_reloc_data; + +static bool +rtems_rtl_unresolved_archive_iterator (rtems_rtl_unresolv_rec* rec, + void* data) +{ + if (rec->type == rtems_rtl_unresolved_symbol) + { + rtems_rtl_unresolved_archive_reloc_data* ard; + ard = (rtems_rtl_unresolved_archive_reloc_data*) data; + + ++ard->name; + + if ((rec->rec.name.flags & RTEMS_RTL_UNRESOLV_SYM_SEARCH_ARCHIVE) != 0) + { + rtems_rtl_archive_search load; + + 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) + { + ard->loaded = true; + return true; + } + } + } + + return false; +} + +static bool +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; + return false; +} + static void rtems_rtl_unresolved_clean_block (rtems_rtl_unresolv_block* block, rtems_rtl_unresolv_rec* rec, @@ -248,8 +317,8 @@ rtems_rtl_unresolved_compact (void) if (unresolved) { /* - * Iterate over the blocks removing any empty strings. If a string is removed - * update the indexes of all strings above this level. + * Iterate over the blocks removing any empty strings. If a string is + * removed update the indexes of all strings above this level. */ rtems_chain_node* node = rtems_chain_first (&unresolved->blocks); uint16_t index = 0; @@ -261,7 +330,7 @@ rtems_rtl_unresolved_compact (void) while (!rtems_rtl_unresolved_rec_is_last (block, rec)) { bool next_rec = true; - if (rec->type == rtems_rtl_unresolved_name) + if (rec->type == rtems_rtl_unresolved_symbol) { ++index; if (rec->rec.name.refs == 0) @@ -305,7 +374,7 @@ rtems_rtl_unresolved_compact (void) /* * Compact the block removing the name record. */ - name_recs = rtems_rtl_unresolved_name_recs (rec->rec.name.name); + name_recs = rtems_rtl_unresolved_symbol_recs (rec->rec.name.name); rtems_rtl_unresolved_clean_block (block, rec, name_recs, unresolved->block_recs); --index; @@ -360,14 +429,14 @@ rtems_rtl_unresolved_table_close (rtems_rtl_unresolved* unresolved) while (!rtems_chain_is_tail (&unresolved->blocks, node)) { rtems_chain_node* next = rtems_chain_next (node); - free (node); + rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_EXTERNAL, node); node = next; } } bool -rtems_rtl_unresolved_interate (rtems_rtl_unresolved_iterator iterator, - void* data) +rtems_rtl_unresolved_iterate (rtems_rtl_unresolved_iterator iterator, + void* data) { rtems_rtl_unresolved* unresolved = rtems_rtl_unresolved_unprotected (); if (unresolved) @@ -438,7 +507,7 @@ rtems_rtl_unresolved_add (rtems_rtl_obj* obj, } name_index = rtems_rtl_unresolved_find_name (unresolved, name, true); - name_recs = rtems_rtl_unresolved_name_recs (name); + name_recs = rtems_rtl_unresolved_symbol_recs (name); /* * An index less than 0 means the name is present and "0 - index" is the next @@ -459,8 +528,9 @@ rtems_rtl_unresolved_add (rtems_rtl_obj* obj, } rec = rtems_rtl_unresolved_rec_first_free (name_block); - rec->type = rtems_rtl_unresolved_name; + 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); block->recs += name_recs; @@ -496,14 +566,41 @@ rtems_rtl_unresolved_add (rtems_rtl_obj* obj, void rtems_rtl_unresolved_resolve (void) { - rtems_rtl_unresolved_reloc_data rd; + bool resolving = true; + if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED)) printf ("rtl: unresolv: global resolve\n"); - rd.name = 0; - rd.name_rec = NULL; - rd.sym = NULL; - rtems_rtl_unresolved_interate (rtems_rtl_unresolved_resolve_iterator, &rd); - rtems_rtl_unresolved_compact (); + + /* + * The resolving process is two separate stages, The first stage is to + * iterate over the unresolved symbols search the global symbol table. If a + * symbol is found iterate over the unresolved relocation records for the + * symbol fixing up the relocations. The second stage is to search the + * archives for symbols we have not been search before and if a symbol if + * found in an archve loaded the object file. Loading an object file stops + * the search of the archives for symbols and stage one is performed + * again. The process repeats until no more symbols are resolved. + */ + while (resolving) + { + rtems_rtl_unresolved_reloc_data rd = { + .name = 0, + .name_rec = NULL, + .sym = NULL + }; + rtems_rtl_unresolved_archive_reloc_data ard = { + .name = 0, + .loaded = false, + .archives = rtems_rtl_archives_unprotected () + }; + + rtems_rtl_unresolved_iterate (rtems_rtl_unresolved_resolve_iterator, &rd); + rtems_rtl_unresolved_compact (); + rtems_rtl_unresolved_iterate (rtems_rtl_unresolved_archive_iterator, &ard); + + resolving = ard.loaded; + } + if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED)) rtems_rtl_unresolved_dump (); } @@ -541,7 +638,7 @@ rtems_rtl_unresolved_dump_iterator (rtems_rtl_unresolv_rec* rec, case rtems_rtl_unresolved_empty: printf (" %03zu: 0: empty\n", dd->rec); break; - case rtems_rtl_unresolved_name: + case rtems_rtl_unresolved_symbol: ++dd->names; printf (" %3zu: 1: name: %3d refs: %2d: %2d: %s\n", dd->rec, dd->names, @@ -563,9 +660,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_interate (rtems_rtl_unresolved_dump_iterator, &dd); + rtems_rtl_unresolved_iterate (rtems_rtl_unresolved_dump_iterator, &dd); } |