From 194eb403c39f5ad346e63dc3352e29570857fd93 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Tue, 22 Jan 2019 08:48:19 +1100 Subject: libdl: Add support for large memory programs - Add trampolines to support relocs that are out of range on support architectures. - Support not loading separate text/data sections in an object file if the symbol provided in the section is a duplicate. A base image may have pulled in part of an object and another part needs to be dynamically loaded. - Refactor the unresolved handling to scale to hundreds of unresolved symbols when loading large number of files. Updates #3685 --- cpukit/libdl/rtl-archive.c | 125 ++++++------- cpukit/libdl/rtl-elf.c | 349 ++++++++++++++++++++++-------------- cpukit/libdl/rtl-mdreloc-arm.c | 36 +++- cpukit/libdl/rtl-mdreloc-i386.c | 9 +- cpukit/libdl/rtl-obj.c | 88 ++++++--- cpukit/libdl/rtl-shell.c | 17 +- cpukit/libdl/rtl-unresolved.c | 388 +++++++++++++++++++++++----------------- cpukit/libdl/rtl.c | 10 +- 8 files changed, 609 insertions(+), 413 deletions(-) (limited to 'cpukit/libdl') diff --git a/cpukit/libdl/rtl-archive.c b/cpukit/libdl/rtl-archive.c index 786c9c6f1d..be1199f62f 100644 --- a/cpukit/libdl/rtl-archive.c +++ b/cpukit/libdl/rtl-archive.c @@ -293,32 +293,22 @@ rtems_rtl_archive_obj_finder (rtems_rtl_archive* archive, void* data) } else { - ssize_t entry = symbols->entries / 2; - ssize_t offset = entry; - ssize_t last_entry = -1; - while (entry >= 0 && - entry < symbols->entries && - entry != last_entry && - offset > 0) + rtems_rtl_archive_symbol* match; + const rtems_rtl_archive_symbol key = { + .entry = -1, + .label = search->symbol + }; + match = bsearch (&key, + symbols->symbols, + symbols->entries, + sizeof (symbols->symbols[0]), + rtems_rtl_archive_symbol_compare); + if (match != NULL) { - int cmp = strcmp (search->symbol, symbols->symbols[entry].label); - if (cmp == 0) - { - entry = symbols->symbols[entry].entry; search->archive = archive; search->offset = - rtems_rtl_archive_read_32 (symbols->base + (entry * 4)); + rtems_rtl_archive_read_32 (symbols->base + (match->entry * 4)); return false; - } - last_entry = entry; - if (offset == 1) - offset = 0; - else - offset = ((offset - 1) / 2) + 1; - if (cmp < 0) - entry -= offset; - else - entry += offset; } } } @@ -452,7 +442,7 @@ rtems_rtl_archives_load_config (rtems_rtl_archives* archives) rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, (void*) archives->config); archives->config_length = 0; archives->config = - rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, sb.st_size, false); + rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, sb.st_size + 1, true); if (archives->config == NULL) { if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES)) @@ -519,45 +509,29 @@ rtems_rtl_archives_load_config (rtems_rtl_archives* archives) * Remove leading and trailing white space. */ s = (char*) archives->config; - for (r = 0; r < archives->config_length; ++r) + r = 0; + while (r < archives->config_length) { - if (s[r] != '\0') + if (s[r] == '\0') + { + ++r; + } + else { size_t ls = strlen (&s[r]); size_t b = 0; while (b < ls && isspace (s[r + b])) { + s[r + b] = '\0'; ++b; } - if (b > 0) - memmove (&s[r], &s[r + b], ls - b); b = ls - 1; - while (b > 0 && isspace (s[r + b])) + while (b > 0 && isspace (s[b])) { - s[r + b] = '\0'; + s[b] = '\0'; --b; } - } - } - - /* - * Compact the lines so there is only a single nul separator. - */ - s = (char*) archives->config; - for (r = 0; r < archives->config_length; ++r) - { - if (s[r] == '\0') - { - size_t e = r + 1; - while (e < archives->config_length) - { - if (s[e] != '\0') - { - if (archives->config_length - e - 1 > 0) - memmove (&s[r + 1], &s[e], archives->config_length - e - 1); - break; - } - } + r += ls; } } @@ -565,13 +539,17 @@ rtems_rtl_archives_load_config (rtems_rtl_archives* archives) { int line = 1; printf ("rtl: archive: config:\n"); - s = (char*) archives->config; - for (r = 0; r < archives->config_length; ++r, ++line) + r = 0; + while (r < archives->config_length) { - size_t len = strlen (s); - printf (" %3d: %s\n", line, s); - s += len + 2; - r += len; + const char* cs = &archives->config[r]; + size_t len = strlen (cs); + if (len > 0) + { + printf (" %3d: %s\n", line, cs); + ++line; + } + r += len + 1; } } } @@ -740,6 +718,19 @@ rtems_rtl_archive_loader (rtems_rtl_archive* archive, void* data) archive->symbols.names, (archive->symbols.entries + 1) * 4, archive->symbols.symbols); + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVE_SYMS) && + archive->symbols.entries > 0) + { + size_t e; + printf ("rtl: archive: symbols: %s\n", archive->name ); + for (e = 0; e < archive->symbols.entries; ++e) + { + printf(" %6zu: %6zu %s\n", e + 1, + archive->symbols.symbols[e].entry, + archive->symbols.symbols[e].label); + } + } } close (fd); @@ -851,19 +842,16 @@ rtems_rtl_archives_refresh (rtems_rtl_archives* archives) break; if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES)) - printf ("rtl: archive: refresh: checking: %s\n", entry.d_name); + printf ("rtl: archive: refresh: checking: %s (pattern: %s)\n", + entry.d_name, basename); if (fnmatch (basename, entry.d_name, 0) == 0) { - struct stat sb; - if (stat (entry.d_name, &sb) == 0) - { - rtems_rtl_archive* archive; - archive = rtems_rtl_archive_get (archives, dirname, entry.d_name); - if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES)) - printf ("rtl: archive: refresh: %s: %sfound\n", - entry.d_name, archive == NULL ? ": not " : ""); - } + rtems_rtl_archive* archive; + archive = rtems_rtl_archive_get (archives, dirname, entry.d_name); + if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES)) + printf ("rtl: archive: refresh: %s: %sfound\n", + entry.d_name, archive == NULL ? ": not " : ""); } } closedir (dir); @@ -1028,8 +1016,9 @@ rtems_rtl_archive_obj_load (rtems_rtl_archives* archives, if (!rtems_rtl_obj_load (obj)) { if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES)) - printf ("rtl: archive: loading: error: %s:%s@0x%08jx\n", - obj->aname, obj->oname, obj->ooffset); + printf ("rtl: archive: loading: error: %s:%s@0x%08jx: %s\n", + obj->aname, obj->oname, obj->ooffset, + rtems_rtl_last_error_unprotected ()); rtems_chain_extract (&obj->link); rtems_rtl_obj_free (obj); rtems_rtl_obj_caches_flush (); diff --git a/cpukit/libdl/rtl-elf.c b/cpukit/libdl/rtl-elf.c index 96af16cb52..e65c70308d 100644 --- a/cpukit/libdl/rtl-elf.c +++ b/cpukit/libdl/rtl-elf.c @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -64,6 +65,31 @@ rtems_rtl_elf_machine_check (Elf_Ehdr* ehdr) return true; } +static const char* +rtems_rtl_elf_separated_section (const char* name) +{ + struct { + const char* label; + size_t len; + } prefix[] = { + #define SEPARATED_PREFIX(_p) { _p, sizeof (_p) - 1 } + SEPARATED_PREFIX (".text."), + SEPARATED_PREFIX (".rel.text."), + SEPARATED_PREFIX (".data."), + SEPARATED_PREFIX (".rel.data."), + SEPARATED_PREFIX (".rodata."), + SEPARATED_PREFIX (".rel.rodata.") + }; + const size_t prefixes = sizeof (prefix) / sizeof (prefix[0]); + size_t p; + for (p = 0; p < prefixes; ++p) + { + if (strncmp (name, prefix[p].label, prefix[p].len) == 0) + return name + prefix[p].len; + } + return NULL; +} + static bool rtems_rtl_elf_find_symbol (rtems_rtl_obj* obj, const Elf_Sym* sym, @@ -100,6 +126,7 @@ rtems_rtl_elf_find_symbol (rtems_rtl_obj* obj, return false; *value = sym->st_value + (Elf_Addr) sect->base; + return true; } @@ -141,62 +168,68 @@ rtems_rtl_elf_reloc_parser (rtems_rtl_obj* obj, rtems_rtl_elf_reloc_data* rd = (rtems_rtl_elf_reloc_data*) data; /* - * Check the reloc record to see if a trampoline is needed. - */ - if (is_rela) - { - const Elf_Rela* rela = (const Elf_Rela*) relbuf; - if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) - printf ("rtl: rela tramp: sym:%s(%d)=%08jx type:%d off:%08jx addend:%d\n", - symname, (int) ELF_R_SYM (rela->r_info), - (uintmax_t) symvalue, (int) ELF_R_TYPE (rela->r_info), - (uintmax_t) rela->r_offset, (int) rela->r_addend); - if (!rtems_rtl_elf_relocate_rela_tramp (obj, rela, targetsect, - symname, sym->st_info, symvalue)) - return false; - } - else - { - const Elf_Rel* rel = (const Elf_Rel*) relbuf; - if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) - printf ("rtl: rel tramp: sym:%s(%d)=%08jx type:%d off:%08jx\n", - symname, (int) ELF_R_SYM (rel->r_info), - (uintmax_t) symvalue, (int) ELF_R_TYPE (rel->r_info), - (uintmax_t) rel->r_offset); - if (!rtems_rtl_elf_relocate_rel_tramp (obj, rel, targetsect, - symname, sym->st_info, symvalue)) - return false; - } - - /* - * If the symbol has been resolved and there is a symbol name it is a global - * symbol and from another object file so add it as a dependency. + * The symbol has to have been resolved to parse the reloc record. Unresolved + * symbols are handled in the relocator but we need to count them here so a + * trampoline is accounted for. We have to assume the unresolved may be out of + * of range. */ if (!resolved) { ++rd->unresolved; } - else if (symname != NULL) + else { /* - * Find the symbol's object file. It cannot be NULL so ignore that result - * if returned, it means something is corrupted. We are in an iterator. + * Check the reloc record to see if a trampoline is needed. */ - rtems_rtl_obj* sobj = rtems_rtl_find_obj_with_symbol (symbol); - if (sobj != NULL) + if (is_rela) + { + const Elf_Rela* rela = (const Elf_Rela*) relbuf; + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: rela tramp: sym:%s(%d)=%08jx type:%d off:%08jx addend:%d\n", + symname, (int) ELF_R_SYM (rela->r_info), + (uintmax_t) symvalue, (int) ELF_R_TYPE (rela->r_info), + (uintmax_t) rela->r_offset, (int) rela->r_addend); + if (!rtems_rtl_elf_relocate_rela_tramp (obj, rela, targetsect, + symname, sym->st_info, symvalue)) + return false; + } + else + { + const Elf_Rel* rel = (const Elf_Rel*) relbuf; + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: rel tramp: sym:%s(%d)=%08jx type:%d off:%08jx\n", + symname, (int) ELF_R_SYM (rel->r_info), + (uintmax_t) symvalue, (int) ELF_R_TYPE (rel->r_info), + (uintmax_t) rel->r_offset); + if (!rtems_rtl_elf_relocate_rel_tramp (obj, rel, targetsect, + symname, sym->st_info, symvalue)) + return false; + } + + if (symname != NULL) { /* - * A dependency is not the base kernel image or itself. Tag the object as - * having been visited so we count it only once. + * Find the symbol's object file. It cannot be NULL so ignore that result + * if returned, it means something is corrupted. We are in an iterator. */ - if (sobj != rtems_rtl_baseimage () && obj != sobj && - (sobj->flags & RTEMS_RTL_OBJ_RELOC_TAG) == 0) + rtems_rtl_obj* sobj = rtems_rtl_find_obj_with_symbol (symbol); + if (sobj != NULL) { - sobj->flags |= RTEMS_RTL_OBJ_RELOC_TAG; - ++rd->dependents; + /* + * A dependency is not the base kernel image or itself. Tag the object as + * having been visited so we count it only once. + */ + if (sobj != rtems_rtl_baseimage () && obj != sobj && + (sobj->flags & RTEMS_RTL_OBJ_RELOC_TAG) == 0) + { + sobj->flags |= RTEMS_RTL_OBJ_RELOC_TAG; + ++rd->dependents; + } } } } + return true; } @@ -313,6 +346,14 @@ rtems_rtl_elf_relocate_worker (rtems_rtl_obj* obj, if (!targetsect) return true; + /* + * The section muct has been loaded. It could be a separate section in an + * archive and not loaded. + */ + if ((targetsect->flags & RTEMS_RTL_OBJ_SECT_LOAD) == 0) + return true; + + rtems_rtl_obj_caches (&symbols, &strings, &relocs); if (!symbols || !strings || !relocs) @@ -379,6 +420,7 @@ rtems_rtl_elf_relocate_worker (rtems_rtl_obj* obj, * Only need the name of the symbol if global or a common symbol. */ if (ELF_ST_TYPE (sym.st_info) == STT_NOTYPE || + ELF_ST_TYPE (sym.st_info) == STT_TLS || sym.st_shndx == SHN_COMMON) { size_t len; @@ -686,6 +728,12 @@ rtems_rtl_elf_symbols (rtems_rtl_obj* obj, symbol.st_shndx, (int) symbol.st_size); + /* + * If a duplicate forget it. + */ + if (rtems_rtl_symbol_global_find (name)) + continue; + if ((symbol.st_shndx != 0) && ((ELF_ST_TYPE (symbol.st_info) == STT_OBJECT) || (ELF_ST_TYPE (symbol.st_info) == STT_COMMON) || @@ -705,16 +753,24 @@ rtems_rtl_elf_symbols (rtems_rtl_obj* obj, { /* * If there is a globally exported symbol already present and this - * symbol is not weak raise an error. If the symbol is weak and - * present globally ignore this symbol and use the global one and if - * it is not present take this symbol global or weak. We accept the - * first weak symbol we find and make it globally exported. + * symbol is not weak raise check if the object file being loaded is + * from an archive. If the base image is built with text sections a + * symbol with it's section will be linked into the base image and not + * another symbol. If not an archive rause an error. + * + * If the symbol is weak and present globally ignore this symbol and + * use the global one and if it is not present take this symbol global + * or weak. We accept the first weak symbol we find and make it + * globally exported. */ if (rtems_rtl_symbol_global_find (name) && (ELF_ST_BIND (symbol.st_info) != STB_WEAK)) { - rtems_rtl_set_error (ENOMEM, "duplicate global symbol: %s", name); - return false; + if (!rtems_rtl_obj_aname_valid (obj)) + { + rtems_rtl_set_error (ENOMEM, "duplicate global symbol: %s", name); + return false; + } } else { @@ -784,10 +840,9 @@ rtems_rtl_elf_symbols (rtems_rtl_obj* obj, for (sym = 0; sym < (sect->size / sizeof (Elf_Sym)); ++sym) { - Elf_Sym symbol; - off_t off; - const char* name; - size_t len; + Elf_Sym symbol; + off_t off; + size_t len; off = obj->ooffset + sect->offset + (sym * sizeof (symbol)); @@ -811,12 +866,6 @@ rtems_rtl_elf_symbols (rtems_rtl_obj* obj, return false; } - off = obj->ooffset + strtab->offset + symbol.st_name; - len = RTEMS_RTL_ELF_STRING_MAX; - - if (!rtems_rtl_obj_cache_read (strings, fd, off, (void**) &name, &len)) - return false; - if ((symbol.st_shndx != 0) && ((ELF_ST_TYPE (symbol.st_info) == STT_OBJECT) || (ELF_ST_TYPE (symbol.st_info) == STT_COMMON) || @@ -825,62 +874,76 @@ rtems_rtl_elf_symbols (rtems_rtl_obj* obj, ((ELF_ST_BIND (symbol.st_info) == STB_GLOBAL) || (ELF_ST_BIND (symbol.st_info) == STB_WEAK) || (ELF_ST_BIND (symbol.st_info) == STB_LOCAL))) + { + rtems_rtl_obj_sect* symsect; + rtems_rtl_obj_sym* osym; + char* string; + Elf_Word value; + + symsect = rtems_rtl_obj_find_section_by_index (obj, symbol.st_shndx); + if (symsect) { - rtems_rtl_obj_sect* symsect; - rtems_rtl_obj_sym* osym; - char* string; - Elf_Word value; + const char* name; - symsect = rtems_rtl_obj_find_section_by_index (obj, symbol.st_shndx); - if (symsect) - { - if ((ELF_ST_BIND (symbol.st_info) == STB_GLOBAL) || - (ELF_ST_BIND (symbol.st_info) == STB_WEAK)) - { - osym = gsym; - string = gstring; - gstring += strlen (name) + 1; - ++gsym; - } - else - { - osym = lsym; - string = lstring; - lstring += strlen (name) + 1; - ++lsym; - } + off = obj->ooffset + strtab->offset + symbol.st_name; + len = RTEMS_RTL_ELF_STRING_MAX; - /* - * Allocate any common symbols in the common section. - */ - if (symbol.st_shndx == SHN_COMMON) - { - size_t value_off = rtems_rtl_obj_align (common_offset, - symbol.st_value); - common_offset = value_off + symbol.st_size; - value = value_off; - } - else - { - value = symbol.st_value; - } + if (!rtems_rtl_obj_cache_read (strings, fd, off, (void**) &name, &len)) + return false; - rtems_chain_set_off_chain (&osym->node); - memcpy (string, name, strlen (name) + 1); - osym->name = string; - osym->value = value + (uint8_t*) symsect->base; - osym->data = symbol.st_info; + /* + * If a duplicate forget it. + */ + if (rtems_rtl_symbol_global_find (name)) + continue; - if (rtems_rtl_trace (RTEMS_RTL_TRACE_SYMBOL)) - printf ("rtl: sym:add:%-2d name:%-2d:%-20s bind:%-2d " \ - "type:%-2d val:%8p sect:%d size:%d\n", - sym, (int) symbol.st_name, osym->name, - (int) ELF_ST_BIND (symbol.st_info), - (int) ELF_ST_TYPE (symbol.st_info), - osym->value, symbol.st_shndx, - (int) symbol.st_size); + if ((ELF_ST_BIND (symbol.st_info) == STB_GLOBAL) || + (ELF_ST_BIND (symbol.st_info) == STB_WEAK)) + { + osym = gsym; + string = gstring; + gstring += strlen (name) + 1; + ++gsym; + } + else + { + osym = lsym; + string = lstring; + lstring += strlen (name) + 1; + ++lsym; + } + + /* + * Allocate any common symbols in the common section. + */ + if (symbol.st_shndx == SHN_COMMON) + { + size_t value_off = rtems_rtl_obj_align (common_offset, + symbol.st_value); + common_offset = value_off + symbol.st_size; + value = value_off; + } + else + { + value = symbol.st_value; } + + rtems_chain_set_off_chain (&osym->node); + memcpy (string, name, strlen (name) + 1); + osym->name = string; + osym->value = value + (uint8_t*) symsect->base; + osym->data = symbol.st_info; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_SYMBOL)) + printf ("rtl: sym:add:%-2d name:%-2d:%-20s bind:%-2d " \ + "type:%-2d val:%8p sect:%d size:%d\n", + sym, (int) symbol.st_name, osym->name, + (int) ELF_ST_BIND (symbol.st_info), + (int) ELF_ST_TYPE (symbol.st_info), + osym->value, symbol.st_shndx, + (int) symbol.st_size); } + } } if (globals) @@ -955,6 +1018,8 @@ rtems_rtl_elf_parse_sections (rtems_rtl_obj* obj, int fd, Elf_Ehdr* ehdr) for (section = 0; section < ehdr->e_shnum; ++section) { + char* name; + size_t len; uint32_t flags; /* @@ -968,9 +1033,15 @@ rtems_rtl_elf_parse_sections (rtems_rtl_obj* obj, int fd, Elf_Ehdr* ehdr) if (!rtems_rtl_obj_cache_read_byval (sects, fd, off, &shdr, sizeof (shdr))) return false; + len = RTEMS_RTL_ELF_STRING_MAX; + if (!rtems_rtl_obj_cache_read (strings, fd, + sectstroff + shdr.sh_name, + (void**) &name, &len)) + return false; + if (rtems_rtl_trace (RTEMS_RTL_TRACE_DETAIL)) - printf ("rtl: section: %2d: type=%d flags=%08x link=%d info=%d\n", - section, (int) shdr.sh_type, (unsigned int) shdr.sh_flags, + printf ("rtl: section: %2d: name=%s type=%d flags=%08x link=%d info=%d\n", + section, name, (int) shdr.sh_type, (unsigned int) shdr.sh_flags, (int) shdr.sh_link, (int) shdr.sh_info); flags = 0; @@ -1010,7 +1081,7 @@ rtems_rtl_elf_parse_sections (rtems_rtl_obj* obj, int fd, Elf_Ehdr* ehdr) break; case SHT_RELA: - flags = RTEMS_RTL_OBJ_SECT_RELA; + flags = RTEMS_RTL_OBJ_SECT_RELA | RTEMS_RTL_OBJ_SECT_LOAD; break; case SHT_REL: @@ -1018,7 +1089,7 @@ rtems_rtl_elf_parse_sections (rtems_rtl_obj* obj, int fd, Elf_Ehdr* ehdr) * The sh_link holds the section index for the symbol table. The sh_info * holds the section index the relocations apply to. */ - flags = RTEMS_RTL_OBJ_SECT_REL; + flags = RTEMS_RTL_OBJ_SECT_REL | RTEMS_RTL_OBJ_SECT_LOAD; break; case SHT_SYMTAB: @@ -1063,8 +1134,18 @@ rtems_rtl_elf_parse_sections (rtems_rtl_obj* obj, int fd, Elf_Ehdr* ehdr) if (flags != 0) { - char* name; - size_t len; + /* + * If the object file is part of a library check the section's name. If it + * starts with '.text.*' see if the last part is a global symbol. If a + * global symbol exists we have to assume the symbol in the archive is a + * duplicate can can be ignored. + */ + if (rtems_rtl_obj_aname_valid (obj)) + { + const char* symname = rtems_rtl_elf_separated_section (name); + if (symname != NULL && rtems_rtl_symbol_global_find (symname)) + flags &= ~RTEMS_RTL_OBJ_SECT_LOAD; + } /* * If link ordering this section must appear in the same order in memory @@ -1074,14 +1155,8 @@ rtems_rtl_elf_parse_sections (rtems_rtl_obj* obj, int fd, Elf_Ehdr* ehdr) flags |= RTEMS_RTL_OBJ_SECT_LINK; /* - * Some architexctures support a named PROGBIT section for INIT/FINI. + * Some architexctures have a named PROGBIT section for INIT/FINI. */ - len = RTEMS_RTL_ELF_STRING_MAX; - if (!rtems_rtl_obj_cache_read (strings, fd, - sectstroff + shdr.sh_name, - (void**) &name, &len)) - return false; - if (strcmp (".ctors", name) == 0) flags |= RTEMS_RTL_OBJ_SECT_CTOR; if (strcmp (".dtors", name) == 0) @@ -1153,25 +1228,34 @@ rtems_rtl_elf_load_linkmap (rtems_rtl_obj* obj) { rtems_chain_control* sections = NULL; rtems_chain_node* node = NULL; - size_t mask = 0; int sec_num = 0; section_detail* sd; int i = 0; + size_t m; /* - * Caculate the size of sections' name. + * The section masks to add to the linkmap. */ + const uint32_t sect_mask[] = { + RTEMS_RTL_OBJ_SECT_TEXT | RTEMS_RTL_OBJ_SECT_LOAD, + RTEMS_RTL_OBJ_SECT_CONST | RTEMS_RTL_OBJ_SECT_LOAD, + RTEMS_RTL_OBJ_SECT_DATA | RTEMS_RTL_OBJ_SECT_LOAD, + RTEMS_RTL_OBJ_SECT_BSS + }; + const size_t sect_masks = sizeof (sect_mask) / sizeof (sect_mask[0]); - for (mask = RTEMS_RTL_OBJ_SECT_TEXT; - mask <= RTEMS_RTL_OBJ_SECT_BSS; - mask <<= 1) + /* + * Caculate the size of sections' name. + */ + for (m = 0; m < sect_masks; ++m) { sections = &obj->sections; node = rtems_chain_first (sections); while (!rtems_chain_is_tail (sections, node)) { rtems_rtl_obj_sect* sect = (rtems_rtl_obj_sect*) node; - if ((sect->size != 0) && ((sect->flags & mask) != 0)) + const uint32_t mask = sect_mask[m]; + if ((sect->size != 0) && ((sect->flags & mask) == mask)) { ++sec_num; } @@ -1205,36 +1289,35 @@ rtems_rtl_elf_load_linkmap (rtems_rtl_obj* obj) sections = &obj->sections; node = rtems_chain_first (sections); - for (mask = RTEMS_RTL_OBJ_SECT_TEXT; - mask <= RTEMS_RTL_OBJ_SECT_BSS; - mask <<= 1) + for (m = 0; m < sect_masks; ++m) { sections = &obj->sections; node = rtems_chain_first (sections); while (!rtems_chain_is_tail (sections, node)) { rtems_rtl_obj_sect* sect = (rtems_rtl_obj_sect*) node; + const uint32_t mask = sect_mask[m]; - if ((sect->size != 0) && ((sect->flags & mask) != 0)) + if ((sect->size != 0) && ((sect->flags & mask) == mask)) { sd[i].name = sect->name; sd[i].size = sect->size; - if (mask == RTEMS_RTL_OBJ_SECT_TEXT) + if ((mask & RTEMS_RTL_OBJ_SECT_TEXT) != 0) { sd[i].rap_id = rap_text; sd[i].offset = sect->base - obj->text_base; } - if (mask == RTEMS_RTL_OBJ_SECT_CONST) + if ((mask & RTEMS_RTL_OBJ_SECT_CONST) != 0) { sd[i].rap_id = rap_const; sd[i].offset = sect->base - obj->const_base; } - if (mask == RTEMS_RTL_OBJ_SECT_DATA) + if ((mask & RTEMS_RTL_OBJ_SECT_DATA) != 0) { sd[i].rap_id = rap_data; sd[i].offset = sect->base - obj->data_base; } - if (mask == RTEMS_RTL_OBJ_SECT_BSS) + if ((mask & RTEMS_RTL_OBJ_SECT_BSS) != 0) { sd[i].rap_id = rap_bss; sd[i].offset = sect->base - obj->bss_base; diff --git a/cpukit/libdl/rtl-mdreloc-arm.c b/cpukit/libdl/rtl-mdreloc-arm.c index a00f0f8825..19a5904a25 100644 --- a/cpukit/libdl/rtl-mdreloc-arm.c +++ b/cpukit/libdl/rtl-mdreloc-arm.c @@ -21,6 +21,12 @@ #include #include "rtl-unwind.h" +/* + * Set to 1 to allow untested relocations. If you tested one and it + * works or you fixed the relocation please remove the guard. + */ +#define ALLOW_UNTESTED_RELOCS 1 + /* * It is possible for the compiler to emit relocations for unaligned data. * We handle this situation with these inlines. @@ -341,8 +347,10 @@ rtems_rtl_elf_relor_rel (rtems_rtl_obj* obj, else { if (ELF_R_TYPE(rel->r_info) == R_TYPE(THM_JUMP24)) { tmp = (tmp + 2) & ~3; /* aligned to 4 bytes only for JUMP24 */ +#if !ALLOW_UNTESTED_RELOCS printf("THM_JUMP24 to arm not supported\n"); return false; +#endif } else { /* THM_CALL bl-->blx */ @@ -440,11 +448,33 @@ rtems_rtl_elf_relor_rel (rtems_rtl_obj* obj, (void *)*where, where, rtems_rtl_obj_oname (obj)); break; + case R_TYPE(TLS_LE32): +#if ALLOW_UNTESTED_RELOCS + if (!parsing) { + addend = *where; + *where = symvalue + addend; + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: TLS_LE32 %p @ %p in %s\n", + (void *)*where, where, rtems_rtl_obj_oname (obj)); + } + break; +#endif + case R_TYPE(TLS_GD32): + case R_TYPE(TLS_LDM32): + case R_TYPE(TLS_LDO32): + case R_TYPE(TLS_IE32): + case R_TYPE(TLS_LDO12): + case R_TYPE(TLS_LE12): + case R_TYPE(TLS_IE12GP): + printf("TSL relocations not supported\n"); + default: - printf ("rtl: reloc unknown: sym = %" PRIu32 ", type = %" PRIu32 ", offset = %p, " - "contents = %p\n", + printf ("rtl: reloc unknown: sym = %" PRIu32 ", type = %" PRIu32 ", offset = %p", ELF_R_SYM(rel->r_info), (uint32_t) ELF_R_TYPE(rel->r_info), - (void *)rel->r_offset, (void *)*where); + (void *)rel->r_offset); + if (!parsing) + printf("contents = %p", (void *)*where); + printf("\n"); rtems_rtl_set_error (EINVAL, "%s: Unsupported relocation type %" PRIu32 " " "in non-PLT relocations", diff --git a/cpukit/libdl/rtl-mdreloc-i386.c b/cpukit/libdl/rtl-mdreloc-i386.c index 773ef8e916..016f99f379 100644 --- a/cpukit/libdl/rtl-mdreloc-i386.c +++ b/cpukit/libdl/rtl-mdreloc-i386.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -67,7 +68,7 @@ rtems_rtl_elf_relocate_rela (rtems_rtl_obj* obj, const Elf_Word symvalue) { (void) obj; - (void) rela; + (void) rel; (void) sect; (void) symname; (void) syminfo; @@ -147,12 +148,12 @@ rtems_rtl_elf_relocate_rel (rtems_rtl_obj* obj, break; default: - printf ("rtl: reloc unknown: sym = %lu, type = %lu, offset = %p, " + printf ("rtl: reloc unknown: sym = %i, type = %" PRIu32 ", offset = %p, " "contents = %p\n", - ELF_R_SYM(rel->r_info), (uint32_t) ELF_R_TYPE(rel->r_info), + (int) ELF_R_SYM(rel->r_info), (uint32_t) ELF_R_TYPE(rel->r_info), (void *)rel->r_offset, (void *)*where); rtems_rtl_set_error (EINVAL, - "%s: Unsupported relocation type %ld " + "%s: Unsupported relocation type %" PRIu32 " " "in non-PLT relocations", sect->name, (uint32_t) ELF_R_TYPE(rel->r_info)); return false; diff --git a/cpukit/libdl/rtl-obj.c b/cpukit/libdl/rtl-obj.c index 6f1f2e4916..0a7763b3b2 100644 --- a/cpukit/libdl/rtl-obj.c +++ b/cpukit/libdl/rtl-obj.c @@ -158,6 +158,16 @@ rtems_rtl_obj_unresolved_dependent (rtems_rtl_obj* obj, return ud->has_unresolved; } +static bool +rtems_rtl_obj_unresolved_object (rtems_chain_node* node, void* data) +{ + rtems_rtl_obj* obj = (rtems_rtl_obj*) node; + rtems_rtl_obj_unresolved_data* ud; + ud = (rtems_rtl_obj_unresolved_data*) data; + ud->has_unresolved = (obj->flags & RTEMS_RTL_OBJ_UNRESOLVED) != 0; + return !ud->has_unresolved; +} + bool rtems_rtl_obj_unresolved (rtems_rtl_obj* obj) { @@ -169,12 +179,22 @@ rtems_rtl_obj_unresolved (rtems_rtl_obj* obj) obj->oname, ud.has_unresolved ? "unresolved" : "resolved"); if (!ud.has_unresolved) { - rtems_rtl_obj_update_flags (RTEMS_RTL_OBJ_DEP_VISITED, 0); - obj->flags |= RTEMS_RTL_OBJ_DEP_VISITED; - rtems_rtl_obj_iterate_dependents (obj, - rtems_rtl_obj_unresolved_dependent, - &ud); - rtems_rtl_obj_update_flags (RTEMS_RTL_OBJ_DEP_VISITED, 0); + if ((obj->flags & RTEMS_RTL_OBJ_BASE) != 0) + { + rtems_rtl_data* rtl = rtems_rtl_data_unprotected (); + rtems_rtl_chain_iterate (&rtl->objects, + rtems_rtl_obj_unresolved_object, + &ud); + } + else + { + rtems_rtl_obj_update_flags (RTEMS_RTL_OBJ_DEP_VISITED, 0); + obj->flags |= RTEMS_RTL_OBJ_DEP_VISITED; + rtems_rtl_obj_iterate_dependents (obj, + rtems_rtl_obj_unresolved_dependent, + &ud); + rtems_rtl_obj_update_flags (RTEMS_RTL_OBJ_DEP_VISITED, 0); + } } return ud.has_unresolved; } @@ -727,49 +747,57 @@ rtems_rtl_obj_iterate_dependents (rtems_rtl_obj* obj, size_t rtems_rtl_obj_text_size (const rtems_rtl_obj* obj) { - return rtems_rtl_obj_section_size (obj, RTEMS_RTL_OBJ_SECT_TEXT); + const uint32_t flags = RTEMS_RTL_OBJ_SECT_LOAD | RTEMS_RTL_OBJ_SECT_TEXT; + return rtems_rtl_obj_section_size (obj, flags); } uint32_t rtems_rtl_obj_text_alignment (const rtems_rtl_obj* obj) { - return rtems_rtl_obj_section_alignment (obj, RTEMS_RTL_OBJ_SECT_TEXT); + const uint32_t flags = RTEMS_RTL_OBJ_SECT_LOAD | RTEMS_RTL_OBJ_SECT_TEXT; + return rtems_rtl_obj_section_alignment (obj, flags); } size_t rtems_rtl_obj_const_size (const rtems_rtl_obj* obj) { - return rtems_rtl_obj_section_size (obj, RTEMS_RTL_OBJ_SECT_CONST); + const uint32_t flags = RTEMS_RTL_OBJ_SECT_LOAD | RTEMS_RTL_OBJ_SECT_CONST; + return rtems_rtl_obj_section_size (obj, flags); } uint32_t -rtems_rtl_obj_eh_alignment (const rtems_rtl_obj* obj) +rtems_rtl_obj_const_alignment (const rtems_rtl_obj* obj) { - return rtems_rtl_obj_section_alignment (obj, RTEMS_RTL_OBJ_SECT_EH); + const uint32_t flags = RTEMS_RTL_OBJ_SECT_LOAD | RTEMS_RTL_OBJ_SECT_CONST; + return rtems_rtl_obj_section_alignment (obj, flags); } -size_t -rtems_rtl_obj_eh_size (const rtems_rtl_obj* obj) +uint32_t +rtems_rtl_obj_eh_alignment (const rtems_rtl_obj* obj) { - return rtems_rtl_obj_section_size (obj, RTEMS_RTL_OBJ_SECT_EH); + const uint32_t flags = RTEMS_RTL_OBJ_SECT_LOAD | RTEMS_RTL_OBJ_SECT_EH; + return rtems_rtl_obj_section_alignment (obj, flags); } -uint32_t -rtems_rtl_obj_const_alignment (const rtems_rtl_obj* obj) +size_t +rtems_rtl_obj_eh_size (const rtems_rtl_obj* obj) { - return rtems_rtl_obj_section_alignment (obj, RTEMS_RTL_OBJ_SECT_CONST); + const uint32_t flags = RTEMS_RTL_OBJ_SECT_LOAD | RTEMS_RTL_OBJ_SECT_EH; + return rtems_rtl_obj_section_size (obj, flags); } size_t rtems_rtl_obj_data_size (const rtems_rtl_obj* obj) { - return rtems_rtl_obj_section_size (obj, RTEMS_RTL_OBJ_SECT_DATA); + const uint32_t flags = RTEMS_RTL_OBJ_SECT_LOAD | RTEMS_RTL_OBJ_SECT_DATA; + return rtems_rtl_obj_section_size (obj, flags); } uint32_t rtems_rtl_obj_data_alignment (const rtems_rtl_obj* obj) { - return rtems_rtl_obj_section_alignment (obj, RTEMS_RTL_OBJ_SECT_DATA); + const uint32_t flags = RTEMS_RTL_OBJ_SECT_LOAD | RTEMS_RTL_OBJ_SECT_DATA; + return rtems_rtl_obj_section_alignment (obj, flags); } size_t @@ -790,8 +818,10 @@ rtems_rtl_obj_relocate (rtems_rtl_obj* obj, rtems_rtl_obj_sect_handler handler, void* data) { - uint32_t mask = RTEMS_RTL_OBJ_SECT_REL | RTEMS_RTL_OBJ_SECT_RELA; - return rtems_rtl_obj_section_handler (mask, obj, fd, handler, data); + const uint32_t flags = (RTEMS_RTL_OBJ_SECT_LOAD | + RTEMS_RTL_OBJ_SECT_REL | + RTEMS_RTL_OBJ_SECT_RELA); + return rtems_rtl_obj_section_handler (flags, obj, fd, handler, data); } /** @@ -1012,12 +1042,14 @@ rtems_rtl_obj_sections_loader (uint32_t mask, } else { + /* + * This section is not to be loaded, clear the base. + */ sect->base = 0; - rtems_rtl_set_error (errno, "section has no load/clear op"); - return false; } - base_offset += sect->size; + if (sect->base) + base_offset += sect->size; ++order; @@ -1053,9 +1085,11 @@ rtems_rtl_obj_load_sections (rtems_rtl_obj* obj, /* * Set the sizes held in the object data. We need this for a fast reference. */ - obj->text_size = text_size; - obj->eh_size = eh_size; - obj->bss_size = bss_size; + obj->text_size = text_size; + obj->const_size = const_size; + obj->data_size = data_size; + obj->eh_size = eh_size; + obj->bss_size = bss_size; /* * Let the allocator manage the actual allocation. The user can use the diff --git a/cpukit/libdl/rtl-shell.c b/cpukit/libdl/rtl-shell.c index c2a1af5ddd..ab5553174b 100644 --- a/cpukit/libdl/rtl-shell.c +++ b/cpukit/libdl/rtl-shell.c @@ -128,17 +128,6 @@ typedef struct bool base; /**< Include the base object file. */ } rtems_rtl_obj_print; -/** - * Return the different between 2 void*. - */ -static size_t -rtems_rtl_delta_voids (void* higher, void* lower) -{ - char* ch = higher; - char* cl = lower; - return ch - cl; -} - /** * Parse an argument. */ @@ -235,11 +224,11 @@ rtems_rtl_obj_printer (rtems_rtl_obj_print* print, rtems_rtl_obj* obj) { printf ("%-*cexec size : %zi\n", print->indent, ' ', obj->exec_size); printf ("%-*ctext base : %p (%zi)\n", print->indent, ' ', - obj->text_base, rtems_rtl_delta_voids (obj->const_base, obj->text_base)); + obj->text_base, obj->text_size); printf ("%-*cconst base : %p (%zi)\n", print->indent, ' ', - obj->const_base, rtems_rtl_delta_voids (obj->data_base, obj->const_base)); + obj->const_base, obj->const_size); printf ("%-*cdata base : %p (%zi)\n", print->indent, ' ', - obj->data_base, rtems_rtl_delta_voids (obj->bss_base, obj->data_base)); + obj->data_base, obj->data_size); printf ("%-*cbss base : %p (%zi)\n", print->indent, ' ', obj->bss_base, obj->bss_size); } 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); @@ -661,13 +723,6 @@ rtems_rtl_unresolved_dump_iterator (rtems_rtl_unresolv_rec* rec, return false; } -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) { @@ -675,3 +730,10 @@ rtems_rtl_unresolved_dump (void) 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); +} diff --git a/cpukit/libdl/rtl.c b/cpukit/libdl/rtl.c index a3664c7e34..e3dba5a206 100644 --- a/cpukit/libdl/rtl.c +++ b/cpukit/libdl/rtl.c @@ -144,7 +144,7 @@ rtems_rtl_data_init (void) /* * Open the archives. */ - rtems_rtl_archives_open (&rtl->archives, "/etc/rtl-libs.conf"); + rtems_rtl_archives_open (&rtl->archives, "/etc/libdl.conf"); /* * Open the unresolved table. @@ -265,6 +265,14 @@ rtems_rtl_global_symbols (void) return &rtl->globals; } +const char* +rtems_rtl_last_error_unprotected (void) +{ + if (!rtl) + return NULL; + return rtl->last_error; +} + rtems_chain_control* rtems_rtl_objects_unprotected (void) { -- cgit v1.2.3