summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Johns <chrisj@rtems.org>2012-07-16 15:07:54 +1000
committerChris Johns <chrisj@rtems.org>2012-07-16 15:07:54 +1000
commit5d126da01db7c0e140ca35389dfe8f7227f10622 (patch)
treeec501af328f2fd23a4ae7cdd53991fb8743b831d
parent8f06d01b2c6e051d9b6f733f6673b796490983f9 (diff)
Resolve unresolved externals when loading object files.
Object files that depend on each other will cause an unresolved external. The change lets object files load with unresolved externals and will resolve them when the object file with the external is loaded. A common table of symbol strings and relocation records is maintained. The symbol string is shared by each object file that is unresolved. Each relocation record that references the symbol is held. The table is a series of small blocks that compact as symbols are resolved. The number of symbols left unresolved is typically small this design avoids fragmentation of the heap memory.
-rw-r--r--mksyms.awk33
-rw-r--r--rtl-allocator.h8
-rw-r--r--rtl-elf.c167
-rw-r--r--rtl-elf.h4
-rw-r--r--rtl-indirect-ptr.h26
-rw-r--r--rtl-obj.c63
-rw-r--r--rtl-obj.h19
-rw-r--r--rtl-shell.c86
-rw-r--r--rtl-sym.c31
-rw-r--r--rtl-sym.h9
-rw-r--r--rtl-trace.h1
-rw-r--r--rtl-unresolved.c447
-rw-r--r--rtl-unresolved.h212
-rw-r--r--rtl.c77
-rw-r--r--rtl.h36
-rw-r--r--shell-init4
-rw-r--r--wscript42
-rw-r--r--x-long-name-to-create-gnu-extension-in-archive.c4
18 files changed, 1095 insertions, 174 deletions
diff --git a/mksyms.awk b/mksyms.awk
index f4e1a53..99bce48 100644
--- a/mksyms.awk
+++ b/mksyms.awk
@@ -54,6 +54,7 @@ function c_constructor_trailer()
function c_embedded_trailer()
{
c_trailer();
+ print ("void rtems_rtl_base_global_syms_init(void);");
print ("void rtems_rtl_base_global_syms_init(void)");
c_rtl_call_body();
}
@@ -61,6 +62,7 @@ function c_embedded_trailer()
BEGIN {
FS = "[ \t\n]";
OFS = " ";
+ started = 0
embed = 0
for (a = 0; a < ARGC; ++a)
{
@@ -69,26 +71,35 @@ BEGIN {
embed = 1
delete ARGV[a];
}
+ else if (ARGV[a] != "-" && ARGV[a] != "awk")
+ {
+ print ("invalid option:", ARGV[a]);
+ exit 2
+ }
}
c_header();
syms = 0
+ started = 1
}
-END {
- for (s = 0; s < syms; ++s)
+END {
+ if (started)
{
- printf ("asm(\" .asciz \\\"%s\\\"\");\n", symbols[s]);
- if (embed)
+ for (s = 0; s < syms; ++s)
{
- printf ("asm(\" .align 0\");\n");
- printf ("asm(\" .long %s\");\n", symbols[s]);
+ printf ("asm(\" .asciz \\\"%s\\\"\");\n", symbols[s]);
+ if (embed)
+ {
+ printf ("asm(\" .align 0\");\n");
+ printf ("asm(\" .long %s\");\n", symbols[s]);
+ }
+ else
+ printf ("asm(\" .long 0x%s\");\n", addresses[s]);
}
+ if (embed)
+ c_embedded_trailer();
else
- printf ("asm(\" .long 0x%s\");\n", addresses[s]);
+ c_constructor_trailer();
}
- if (embed)
- c_embedded_trailer();
- else
- c_constructor_trailer();
}
#
diff --git a/rtl-allocator.h b/rtl-allocator.h
index 47e896f..8e90b7b 100644
--- a/rtl-allocator.h
+++ b/rtl-allocator.h
@@ -28,7 +28,7 @@ extern "C" {
* Define the types of allocation the loader requires.
*
* @note It is best to use the object tag for general memory allocation and to
- * leave the tags with specific access properties to the module data
+ * leave the tags with specific access properties to the module data
*/
enum rtems_rtl_alloc_tags_e {
RTEMS_RTL_ALLOC_OBJECT, /**< A generic memory object. */
@@ -96,7 +96,7 @@ void rtems_rtl_alloc_initialise (rtems_rtl_alloc_data_t* data);
* @param zero If true the memory is cleared.
* @return void* The memory address or NULL is not memory available.
*/
-void* rtems_rtl_alloc_new(rtems_rtl_alloc_tag_t tag, size_t size, bool zero);
+void* rtems_rtl_alloc_new (rtems_rtl_alloc_tag_t tag, size_t size, bool zero);
/**
* The Runtime Loader allocator delete deletes allocated memory.
@@ -104,7 +104,7 @@ void* rtems_rtl_alloc_new(rtems_rtl_alloc_tag_t tag, size_t size, bool zero);
* @param tag The type of allocation request.
* @param address The memory address to delete. A NULL is ignored.
*/
-void rtems_rtl_alloc_del(rtems_rtl_alloc_tag_t tag, void* address);
+void rtems_rtl_alloc_del (rtems_rtl_alloc_tag_t tag, void* address);
/**
* Hook the Runtime Loader allocatior. A handler can call the previous handler
@@ -115,7 +115,7 @@ void rtems_rtl_alloc_del(rtems_rtl_alloc_tag_t tag, void* address);
* @param handler The handler to use as the allocator.
* @return rtems_rtl_alloc_handler_t The previous handler.
*/
-rtems_rtl_allocator_t rtems_rtl_alloc_hook(rtems_rtl_allocator_t handler);
+rtems_rtl_allocator_t rtems_rtl_alloc_hook (rtems_rtl_allocator_t handler);
/**
* Allocate memory to an indirect handle.
diff --git a/rtl-elf.c b/rtl-elf.c
index acf7893..cd96192 100644
--- a/rtl-elf.c
+++ b/rtl-elf.c
@@ -12,7 +12,7 @@
*
* @brief RTEMS Run-Time Link Editor
*
- * This is the RTL implementation.
+ * This is the RTL implementation.
*/
#if HAVE_CONFIG_H
@@ -30,6 +30,14 @@
#include "rtl-elf.h"
#include "rtl-error.h"
#include "rtl-trace.h"
+#include "rtl-unresolved.h"
+
+/**
+ * The offsets in the unresolved array.
+ */
+#define REL_R_OFFSET (0)
+#define REL_R_INFO (1)
+#define REL_R_ADDEND (2)
static bool
rtems_rtl_elf_machine_check (Elf_Ehdr* ehdr)
@@ -93,7 +101,6 @@ rtems_rtl_elf_relocator (rtems_rtl_obj_t* obj,
bool is_rela;
size_t reloc_size;
int reloc;
- int unresolved;
/*
* First check if the section the relocations are for exists. If it does not
@@ -102,12 +109,12 @@ rtems_rtl_elf_relocator (rtems_rtl_obj_t* obj,
targetsect = rtems_rtl_obj_find_section_by_index (obj, sect->info);
if (!targetsect)
return true;
-
+
rtems_rtl_obj_caches (&symbols, &strings, &relocs);
if (!symbols || !strings || !relocs)
return false;
-
+
symsect = rtems_rtl_obj_find_section (obj, ".symtab");
if (!symsect)
{
@@ -121,7 +128,7 @@ rtems_rtl_elf_relocator (rtems_rtl_obj_t* obj,
rtems_rtl_set_error (EINVAL, "no .strtab section");
return false;
}
-
+
if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
printf ("rtl: relocation: %s, syms:%s\n", sect->name, symsect->name);
@@ -132,8 +139,8 @@ rtems_rtl_elf_relocator (rtems_rtl_obj_t* obj,
RTEMS_RTL_OBJ_SECT_RELA) ? true : false;
reloc_size = is_rela ? sizeof (Elf_Rela) : sizeof (Elf_Rel);
- unresolved = 0;
-
+ obj->unresolved = 0;
+
for (reloc = 0; reloc < (sect->size / reloc_size); ++reloc)
{
uint8_t relbuf[reloc_size];
@@ -171,7 +178,7 @@ rtems_rtl_elf_relocator (rtems_rtl_obj_t* obj,
size_t len;
off = obj->ooffset + strtab->offset + sym.st_name;
len = RTEMS_RTL_ELF_STRING_MAX;
-
+
if (!rtems_rtl_obj_cache_read (strings, fd, off,
(void**) &symname, &len))
return false;
@@ -180,7 +187,8 @@ rtems_rtl_elf_relocator (rtems_rtl_obj_t* obj,
/*
* See if the record references an external symbol. If it does find the
* symbol value. If the symbol cannot be found flag the object file as
- * having unresolved externals.
+ * having unresolved externals and store the externals. The load of an
+ * object after this one may provide the unresolved externals.
*/
if (is_rela)
type = ELF_R_TYPE(rela->r_info);
@@ -188,13 +196,38 @@ rtems_rtl_elf_relocator (rtems_rtl_obj_t* obj,
type = ELF_R_TYPE(rel->r_info);
relocate = true;
-
+
if (rtems_rtl_elf_rel_resolve_sym (type))
{
if (!rtems_rtl_elf_find_symbol (obj, &sym, symname, &symvalue))
{
- ++unresolved;
+ uint16_t flags = 0;
+ rtems_rtl_word_t rel_words[3];
+
+ ++obj->unresolved;
relocate = false;
+
+ if (is_rela)
+ {
+ flags = 1;
+ rel_words[REL_R_OFFSET] = rela->r_offset;
+ rel_words[REL_R_INFO] = rela->r_info;
+ rel_words[REL_R_ADDEND] = rela->r_addend;
+ }
+ else
+ {
+ rel_words[REL_R_OFFSET] = rel->r_offset;
+ rel_words[REL_R_INFO] = rel->r_info;
+ rel_words[REL_R_ADDEND] = 0;
+ }
+
+ if (!rtems_rtl_unresolved_add (obj,
+ flags,
+ symname,
+ targetsect->section,
+ rel_words))
+ {
+ }
}
}
@@ -212,9 +245,9 @@ rtems_rtl_elf_relocator (rtems_rtl_obj_t* obj,
else
{
if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
- printf ("rtl: rel: sym:%-2d type:%-2d off:%08lx\n",
- (int) ELF_R_SYM (rel->r_info), (int) ELF_R_TYPE (rel->r_info),
- rel->r_offset);
+ printf ("rtl: rel: sym:%-2d type:%-2d off:%08lx\n",
+ (int) ELF_R_SYM (rel->r_info), (int) ELF_R_TYPE (rel->r_info),
+ rel->r_offset);
if (!rtems_rtl_elf_relocate_rel (obj, rel, targetsect, symvalue))
return false;
}
@@ -224,12 +257,63 @@ rtems_rtl_elf_relocator (rtems_rtl_obj_t* obj,
/*
* Set the unresolved externals status if there are unresolved externals.
*/
- if (unresolved)
+ if (obj->unresolved)
obj->flags |= RTEMS_RTL_OBJ_UNRESOLVED;
return true;
}
+bool
+rtems_rtl_obj_relocate_unresolved (rtems_rtl_unresolv_reloc_t* reloc,
+ rtems_rtl_obj_sym_t* sym)
+{
+ rtems_rtl_obj_sect_t* sect;
+ bool is_rela;
+ Elf_Word symvalue;
+
+ is_rela =reloc->flags & 1;
+
+ sect = rtems_rtl_obj_find_section_by_index (reloc->obj, reloc->sect);
+ if (!sect)
+ return false;
+
+ symvalue = (Elf_Word) (intptr_t) sym->value;
+ if (is_rela)
+ {
+ Elf_Rela rela;
+ rela.r_offset = reloc->rel[REL_R_OFFSET];
+ rela.r_info = reloc->rel[REL_R_INFO];
+ rela.r_addend = reloc->rel[REL_R_ADDEND];
+ if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
+ printf ("rtl: rela: sym:%-2d type:%-2d off:%08lx addend:%d\n",
+ (int) ELF_R_SYM (rela.r_info), (int) ELF_R_TYPE (rela.r_info),
+ rela.r_offset, (int) rela.r_addend);
+ if (!rtems_rtl_elf_relocate_rela (reloc->obj, &rela, sect, symvalue))
+ return false;
+ }
+ else
+ {
+ Elf_Rel rel;
+ rel.r_offset = reloc->rel[REL_R_OFFSET];
+ rel.r_info = reloc->rel[REL_R_INFO];
+ if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
+ printf ("rtl: rel: sym:%-2d type:%-2d off:%08lx\n",
+ (int) ELF_R_SYM (rel.r_info), (int) ELF_R_TYPE (rel.r_info),
+ rel.r_offset);
+ if (!rtems_rtl_elf_relocate_rel (reloc->obj, &rel, sect, symvalue))
+ return false;
+ }
+
+ if (reloc->obj->unresolved)
+ {
+ --reloc->obj->unresolved;
+ if (!reloc->obj->unresolved)
+ reloc->obj->flags &= ~RTEMS_RTL_OBJ_UNRESOLVED;
+ }
+
+ return true;
+}
+
static bool
rtems_rtl_elf_symbols (rtems_rtl_obj_t* obj,
int fd,
@@ -276,10 +360,10 @@ rtems_rtl_elf_symbols (rtems_rtl_obj_t* obj,
if (!rtems_rtl_obj_cache_read_byval (symbols, fd, off,
&symbol, sizeof (symbol)))
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;
@@ -317,7 +401,7 @@ rtems_rtl_elf_symbols (rtems_rtl_obj_t* obj,
if (globals)
{
rtems_rtl_obj_sym_t* gsym;
-
+
obj->global_size = globals * sizeof (rtems_rtl_obj_sym_t) + string_space;
obj->global_table = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_SYMBOL,
obj->global_size, true);
@@ -356,7 +440,7 @@ rtems_rtl_elf_symbols (rtems_rtl_obj_t* obj,
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;
@@ -376,24 +460,29 @@ rtems_rtl_elf_symbols (rtems_rtl_obj_t* obj,
rtems_rtl_set_error (EINVAL, "sym section not found");
return false;
}
+
+ rtems_chain_set_off_chain (&gsym->node);
+
memcpy (string, name, strlen (name) + 1);
gsym->name = string;
string += strlen (name) + 1;
gsym->value = symbol.st_value + (uint8_t*) symsect->base;
if (rtems_rtl_trace (RTEMS_RTL_TRACE_SYMBOL))
- printf ("rtl: sym:%-2d name:%-2d:%-20s bind:%-2d type:%-2d val:%8p sect:%d size:%d\n",
+ printf ("rtl: sym:add:%-2d name:%-2d:%-20s bind:%-2d type:%-2d val:%8p sect:%d size:%d\n",
sym, (int) symbol.st_name, gsym->name,
(int) ELF_ST_BIND (symbol.st_info),
(int) ELF_ST_TYPE (symbol.st_info),
gsym->value, symbol.st_shndx,
(int) symbol.st_size);
-
+
++gsym;
}
}
+
+ rtems_rtl_symbol_obj_add (obj);
}
-
+
return true;
}
@@ -406,17 +495,17 @@ rtems_rtl_elf_parse_sections (rtems_rtl_obj_t* obj, int fd, Elf_Ehdr* ehdr)
off_t sectstroff;
off_t off;
Elf_Shdr shdr;
-
+
rtems_rtl_obj_caches (&sects, &strings, NULL);
if (!sects || !strings)
return false;
-
+
/*
* Get the offset to the section string table.
*/
off = obj->ooffset + ehdr->e_shoff + (ehdr->e_shstrndx * ehdr->e_shentsize);
-
+
if (!rtems_rtl_obj_cache_read_byval (sects, fd, off, &shdr, sizeof (shdr)))
return false;
@@ -438,7 +527,7 @@ rtems_rtl_elf_parse_sections (rtems_rtl_obj_t* obj, int fd, Elf_Ehdr* ehdr)
return false;
flags = 0;
-
+
switch (shdr.sh_type)
{
case SHT_NULL:
@@ -476,7 +565,7 @@ rtems_rtl_elf_parse_sections (rtems_rtl_obj_t* obj, int fd, Elf_Ehdr* ehdr)
case SHT_RELA:
flags = RTEMS_RTL_OBJ_SECT_RELA;
break;
-
+
case SHT_REL:
/*
* The sh_link holds the section index for the symbol table. The sh_info
@@ -498,7 +587,7 @@ rtems_rtl_elf_parse_sections (rtems_rtl_obj_t* obj, int fd, Elf_Ehdr* ehdr)
section, (int) shdr.sh_type, (int) shdr.sh_flags);
break;
}
-
+
if (flags != 0)
{
char* name;
@@ -514,7 +603,7 @@ rtems_rtl_elf_parse_sections (rtems_rtl_obj_t* obj, int fd, Elf_Ehdr* ehdr)
flags |= RTEMS_RTL_OBJ_SECT_CTOR;
if (strcmp (".dtors", name) == 0)
flags |= RTEMS_RTL_OBJ_SECT_DTOR;
-
+
if (!rtems_rtl_obj_add_section (obj, section, name,
shdr.sh_size, shdr.sh_offset,
shdr.sh_addralign, shdr.sh_link,
@@ -531,9 +620,9 @@ rtems_rtl_obj_file_load (rtems_rtl_obj_t* obj, int fd)
{
rtems_rtl_obj_cache_t* header;
Elf_Ehdr ehdr;
-
+
rtems_rtl_obj_caches (&header, NULL, NULL);
-
+
if (!rtems_rtl_obj_cache_read_byval (header, fd, obj->ooffset,
&ehdr, sizeof (ehdr)))
return false;
@@ -541,7 +630,7 @@ rtems_rtl_obj_file_load (rtems_rtl_obj_t* obj, int fd)
/*
* Check we have a valid ELF file.
*/
- if ((memcmp (ELFMAG, ehdr.e_ident, SELFMAG) != 0)
+ if ((memcmp (ELFMAG, ehdr.e_ident, SELFMAG) != 0)
|| ehdr.e_ident[EI_CLASS] != ELFCLASS)
{
rtems_rtl_set_error (EINVAL, "invalid ELF file format");
@@ -555,7 +644,7 @@ rtems_rtl_obj_file_load (rtems_rtl_obj_t* obj, int fd)
rtems_rtl_set_error (EINVAL, "unsupported ELF file version");
return false;
}
-
+
if (!rtems_rtl_elf_machine_check (&ehdr))
{
rtems_rtl_set_error (EINVAL, "unsupported machine type");
@@ -573,7 +662,7 @@ rtems_rtl_obj_file_load (rtems_rtl_obj_t* obj, int fd)
rtems_rtl_set_error (EINVAL, "ELF file contains program headers");
return false;
}
-
+
if (ehdr.e_shentsize != sizeof (Elf_Shdr))
{
rtems_rtl_set_error (EINVAL, "invalid ELF section header size");
@@ -584,10 +673,10 @@ rtems_rtl_obj_file_load (rtems_rtl_obj_t* obj, int fd)
* Parse the section information first so we have the memory map of the object
* file and the memory allocated. Any further allocations we make to complete
* the load will not fragment the memory.
- */
+ */
if (!rtems_rtl_elf_parse_sections (obj, fd, &ehdr))
return false;
-
+
obj->entry = (void*)(uintptr_t) ehdr.e_entry;
if (!rtems_rtl_obj_load_sections (obj, fd))
@@ -595,10 +684,10 @@ rtems_rtl_obj_file_load (rtems_rtl_obj_t* obj, int fd)
if (!rtems_rtl_obj_load_symbols (obj, fd, rtems_rtl_elf_symbols, &ehdr))
return false;
-
+
if (!rtems_rtl_obj_relocate (obj, fd, rtems_rtl_elf_relocator, &ehdr))
return false;
-
+
return true;
-}
+}
diff --git a/rtl-elf.h b/rtl-elf.h
index 9f7f88c..a07c848 100644
--- a/rtl-elf.h
+++ b/rtl-elf.h
@@ -74,7 +74,7 @@ bool rtems_rtl_elf_rel_resolve_sym (Elf_Word type);
* @param sect The section of the object file the relocation is for.
* @param symvalue If a symbol is referenced, this is the symbols value.
* @retval bool The relocation has been applied.
- * @retval bool The relocation could not be applied.
+ * @retval bool The relocation could not be applied.
*/
bool rtems_rtl_elf_relocate_rel (rtems_rtl_obj_t* obj,
const Elf_Rel* rel,
@@ -91,7 +91,7 @@ bool rtems_rtl_elf_relocate_rel (rtems_rtl_obj_t* obj,
* @param sect The section of the object file the relocation is for.
* @param symvalue If a symbol is referenced, this is the symbols value.
* @retval bool The relocation has been applied.
- * @retval bool The relocation could not be applied.
+ * @retval bool The relocation could not be applied.
*/
bool rtems_rtl_elf_relocate_rela (rtems_rtl_obj_t* obj,
const Elf_Rela* rela,
diff --git a/rtl-indirect-ptr.h b/rtl-indirect-ptr.h
index 2c4843f..5a5b43b 100644
--- a/rtl-indirect-ptr.h
+++ b/rtl-indirect-ptr.h
@@ -44,6 +44,32 @@ struct rtems_rtl_sptr_s {
typedef struct rtems_rtl_sptr_s rtems_rtl_sptr_t;
/**
+ * A chain of indirect pointers for users to chain in applications.
+ *
+ * @note The chain the pointer is on is internal to the allocator and cannot be
+ * used by applications.
+ */
+struct rtems_rtl_ptr_chain_s {
+ rtems_chain_node node; /**< Chain of indirect pointers. */
+ rtems_rtl_ptr_t ptr; /**< The indirect pointer. */
+};
+
+typedef struct rtems_rtl_ptr_chain_s rtems_rtl_ptr_chain_t;
+
+/**
+ * A chain of indirect sized pointers for users to chain in applications.
+ *
+ * @note The chain the pointer is on is internal to the allocator and cannot be
+ * used by applications.
+ */
+struct rtems_rtl_sptr_chain_s {
+ rtems_chain_node node; /**< Chain of indirect pointers. */
+ rtems_rtl_sptr_t ptr; /**< The indirect pointer. */
+};
+
+typedef struct rtems_rtl_sptr_chain_s rtems_rtl_sptr_chain_t;
+
+/**
* Get the pointer given an indirect handle.
*
* @param handle The handle the pointer is returned from.
diff --git a/rtl-obj.c b/rtl-obj.c
index 1e71b74..01568c9 100644
--- a/rtl-obj.c
+++ b/rtl-obj.c
@@ -72,7 +72,7 @@ rtems_rtl_obj_free (rtems_rtl_obj_t* obj)
rtems_chain_extract (&obj->link);
rtems_rtl_alloc_module_del (&obj->text_base, &obj->const_base,
&obj->data_base, &obj->bss_base);
- rtems_rtl_obj_symbol_erase (obj);
+ rtems_rtl_symbol_obj_erase (obj);
rtems_rtl_obj_free_names (obj);
rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, obj);
return true;
@@ -81,7 +81,7 @@ rtems_rtl_obj_free (rtems_rtl_obj_t* obj)
bool
rtems_rtl_obj_unresolved (rtems_rtl_obj_t* obj)
{
- return (obj->flags & RTEMS_RTL_OBJ_UNRESOLVED) != 0 ? true : false;
+ return (obj->flags & RTEMS_RTL_OBJ_UNRESOLVED) != 0 ? true : false;
}
static bool
@@ -91,7 +91,7 @@ rtems_rtl_obj_parse_name (rtems_rtl_obj_t* obj, const char* name)
const char* oname = NULL;
const char* colon;
const char* end;
-
+
/*
* Parse the name to determine if the object file is part of an archive or it
* is an object file. If an archive check the name for a '@' to see if the
@@ -117,7 +117,7 @@ rtems_rtl_obj_parse_name (rtems_rtl_obj_t* obj, const char* name)
if (colon != end)
{
const char* at;
-
+
/*
* The file name is an archive and the object file name is next after the
* delimiter. Move the pointer to the archive name.
@@ -133,7 +133,7 @@ rtems_rtl_obj_parse_name (rtems_rtl_obj_t* obj, const char* name)
if (at == NULL)
at = end;
-
+
oname = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, at - colon + 1, true);
if (!oname)
@@ -158,7 +158,7 @@ rtems_rtl_obj_parse_name (rtems_rtl_obj_t* obj, const char* name)
obj->oname = oname;
obj->aname = aname;
-
+
return true;
}
@@ -336,7 +336,7 @@ rtems_rtl_obj_find_file (rtems_rtl_obj_t* obj, const char* name)
pname = rtems_rtl_obj_aname (obj);
else
pname = rtems_rtl_obj_oname (obj);
-
+
if (rtems_filesystem_is_delimiter (pname[0]))
{
if (stat (pname, &sb) == 0)
@@ -351,7 +351,7 @@ rtems_rtl_obj_find_file (rtems_rtl_obj_t* obj, const char* name)
char* fname;
rtl = rtems_rtl_lock ();
-
+
start = rtl->paths;
end = start + strlen (rtl->paths);
len = strlen (pname);
@@ -359,7 +359,7 @@ rtems_rtl_obj_find_file (rtems_rtl_obj_t* obj, const char* name)
while (!obj->fname && (start != end))
{
const char* delimiter = strchr (start, ':');
-
+
if (delimiter == NULL)
delimiter = end;
@@ -367,7 +367,7 @@ rtems_rtl_obj_find_file (rtems_rtl_obj_t* obj, const char* name)
* Allocate the path fragment, separator, name, terminating nul. Form the
* path then see if the stat call works.
*/
-
+
fname = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT,
(delimiter - start) + 1 + len + 1, true);
if (!fname)
@@ -383,7 +383,7 @@ rtems_rtl_obj_find_file (rtems_rtl_obj_t* obj, const char* name)
if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD))
printf ("rtl: loading: find-path: %s\n", fname);
-
+
if (stat (fname, &sb) < 0)
rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, fname);
else
@@ -439,7 +439,7 @@ rtems_rtl_obj_add_section (rtems_rtl_obj_t* obj,
if (rtems_rtl_trace (RTEMS_RTL_TRACE_SECTION))
printf ("rtl: sect: %-2d: %s\n", section, name);
-
+
return true;
}
@@ -599,22 +599,22 @@ rtems_rtl_obj_sections_loader (rtems_chain_control* sections,
while (!rtems_chain_is_tail (sections, node))
{
rtems_rtl_obj_sect_t* sect = (rtems_rtl_obj_sect_t*) node;
-
+
if ((sect->size != 0) && ((sect->flags & mask) != 0))
{
uint8_t* sect_base = base + base_offset;
-
+
if (!first)
base_offset = rtems_rtl_sect_align (base_offset, sect->alignment);
if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD_SECT))
printf ("rtl: loading: %s -> %8p (%zi)\n",
sect->name, base + base_offset, sect->size);
-
+
if ((sect->flags & RTEMS_RTL_OBJ_SECT_LOAD) == RTEMS_RTL_OBJ_SECT_LOAD)
{
size_t len;
-
+
if (lseek (fd, offset + sect->offset, SEEK_SET) < 0)
{
rtems_rtl_set_error (errno, "section load seek failed");
@@ -644,14 +644,14 @@ rtems_rtl_obj_sections_loader (rtems_chain_control* sections,
rtems_rtl_set_error (errno, "section has no load op");
return false;
}
-
+
sect->base = sect_base;
first = false;
}
-
+
node = rtems_chain_next (node);
}
-
+
return true;
}
@@ -667,7 +667,7 @@ rtems_rtl_obj_load_sections (rtems_rtl_obj_t* obj, int fd)
const_size = rtems_rtl_obj_const_size (obj) + rtems_rtl_obj_data_alignment (obj);
data_size = rtems_rtl_obj_data_size (obj) + rtems_rtl_obj_bss_alignment (obj);
bss_size = rtems_rtl_obj_bss_size (obj);
-
+
/*
* Let the allocator manage the actual allocation. The user can use the
* standard heap or provide a specific allocator with memory protection.
@@ -695,7 +695,7 @@ rtems_rtl_obj_load_sections (rtems_rtl_obj_t* obj, int fd)
printf ("rtl: load sect: bss - b:%p s:%zi a:%" PRIu32 "\n",
obj->bss_base, bss_size, rtems_rtl_obj_bss_alignment (obj));
}
-
+
/*
* Load all text then data then bss sections in seperate operations so each
* type of section is grouped together.
@@ -772,7 +772,7 @@ rtems_rtl_obj_archive_find (rtems_rtl_obj_t* obj, int fd)
off_t extended_file_names;
uint8_t header[RTEMS_RTL_AR_FHDR_SIZE];
bool scanning;
-
+
if (read (fd, &header[0], RTEMS_RTL_AR_IDENT_SIZE) != RTEMS_RTL_AR_IDENT_SIZE)
{
rtems_rtl_set_error (errno, "reading archive identifer");
@@ -815,14 +815,14 @@ rtems_rtl_obj_archive_find (rtems_rtl_obj_t* obj, int fd)
}
extended_file_names = 0;
-
+
while (obj->ooffset < fsize)
{
/*
* Clean up any existing data.
*/
memset (header, 0, sizeof (header));
-
+
if (!rtems_rtl_seek_read (fd, obj->ooffset, RTEMS_RTL_AR_FHDR_SIZE, &header[0]))
{
rtems_rtl_set_error (errno, "seek/read archive file header");
@@ -852,14 +852,14 @@ rtems_rtl_obj_archive_find (rtems_rtl_obj_t* obj, int fd)
*/
obj->fsize = (rtems_rtl_scan_decimal (&header[RTEMS_RTL_AR_SIZE],
RTEMS_RTL_AR_SIZE_SIZE) + 1) & ~1;
-
+
/*
* Check for the GNU extensions.
*/
if (header[0] == '/')
{
off_t extended_off;
-
+
switch (header[1])
{
case ' ':
@@ -889,7 +889,7 @@ rtems_rtl_obj_archive_find (rtems_rtl_obj_t* obj, int fd)
*/
extended_off =
rtems_rtl_scan_decimal (&header[1], RTEMS_RTL_AR_FNAME_SIZE);
-
+
if (extended_file_names == 0)
{
off_t off = obj->ooffset;
@@ -899,7 +899,7 @@ rtems_rtl_obj_archive_find (rtems_rtl_obj_t* obj, int fd)
(rtems_rtl_scan_decimal (&header[RTEMS_RTL_AR_SIZE],
RTEMS_RTL_AR_SIZE_SIZE) + 1) & ~1;
off += esize + RTEMS_RTL_AR_FHDR_SIZE;
-
+
if (!rtems_rtl_seek_read (fd, off,
RTEMS_RTL_AR_FHDR_SIZE, &header[0]))
{
@@ -918,7 +918,7 @@ rtems_rtl_obj_archive_find (rtems_rtl_obj_t* obj, int fd)
obj->fsize = 0;
return false;
}
-
+
if ((header[0] == '/') && (header[1] == '/'))
{
extended_file_names = off + RTEMS_RTL_AR_FHDR_SIZE;
@@ -970,7 +970,6 @@ rtems_rtl_obj_archive_find (rtems_rtl_obj_t* obj, int fd)
}
obj->ooffset += obj->fsize + RTEMS_RTL_AR_FHDR_SIZE;
-
}
rtems_rtl_set_error (ENOENT, "object file not found");
@@ -989,7 +988,7 @@ rtems_rtl_obj_load (rtems_rtl_obj_t* obj)
rtems_rtl_set_error (ENOMEM, "invalid object file name path");
return false;
}
-
+
fd = open (rtems_rtl_obj_fname (obj), O_RDONLY);
if (fd < 0)
{
@@ -1033,6 +1032,6 @@ rtems_rtl_obj_load (rtems_rtl_obj_t* obj)
bool
rtems_rtl_obj_unload (rtems_rtl_obj_t* obj)
{
- rtems_rtl_obj_symbol_erase (obj);
+ rtems_rtl_symbol_obj_erase (obj);
return rtems_rtl_obj_free (obj);
}
diff --git a/rtl-obj.h b/rtl-obj.h
index 8440078..00803c5 100644
--- a/rtl-obj.h
+++ b/rtl-obj.h
@@ -18,8 +18,8 @@
#include <rtems.h>
#include <rtems/chain.h>
-#include <rtl-indirect-ptr.h>
#include <rtl-sym.h>
+#include <rtl-unresolved.h>
#ifdef __cplusplus
extern "C" {
@@ -96,6 +96,8 @@ struct rtems_rtl_obj_s
rtems_rtl_obj_sym_t* global_table; /**< Global symbol table. */
size_t global_syms; /**< Global symbol count. */
size_t global_size; /**< Global symbol memory usage. */
+ rtems_chain_control externals; /**< Unresolved externals. */
+ uint32_t unresolved; /**< The number of unresolved relocations. */
void* text_base; /**< The base address of the text section
* in memory. */
void* const_base; /**< The base address of the const section
@@ -265,7 +267,7 @@ bool rtems_rtl_obj_find_file (rtems_rtl_obj_t* obj, const char* name);
* @param info The section's info field (from the ELF format).
* @param flags The section's flags.
* @retval true The section has been added.
- * @retval false The section has not been added. See the RTL error.
+ * @retval false The section has not been added. See the RTL error.
*/
bool rtems_rtl_obj_add_section (rtems_rtl_obj_t* obj,
int section,
@@ -384,7 +386,7 @@ uint32_t rtems_rtl_obj_data_alignment (rtems_rtl_obj_t* obj);
* @return size_t The size of the bss area of the object file.
*/
size_t rtems_rtl_obj_bss_size (rtems_rtl_obj_t* obj);
-
+
/**
* The bss section alignment of the object file. Only use once all the
* sections has been added. The section alignment is the alignment of the first
@@ -415,6 +417,17 @@ bool rtems_rtl_obj_relocate (rtems_rtl_obj_t* obj,
void* data);
/**
+ * Relocate an object file's unresolved reference.
+ *
+ * @param rec The unresolved relocation record.
+ * @param sym The unresolved relocation's referenced symbol.
+ * @retval true The object file record was relocated.
+ * @retval false The relocation failed. The RTL error is set.
+ */
+bool rtems_rtl_obj_relocate_unresolved (rtems_rtl_unresolv_reloc_t* reloc,
+ rtems_rtl_obj_sym_t* sym);
+
+/**
* Load the symbols from the object file. Only the exported or public symbols
* are read into memory and held in the global symbol table.
*
diff --git a/rtl-shell.c b/rtl-shell.c
index 69ce24f..728633b 100644
--- a/rtl-shell.c
+++ b/rtl-shell.c
@@ -94,7 +94,7 @@ rtems_rtl_shell_status (rtems_rtl_data_t* rtl, int argc, char *argv[])
{
rtems_rtl_obj_summary_t summary;
size_t total_memory;
-
+
summary.count = 0;
summary.exec = 0;
summary.symbols = 0;
@@ -107,7 +107,7 @@ rtems_rtl_shell_status (rtems_rtl_data_t* rtl, int argc, char *argv[])
total_memory =
sizeof (*rtl) + (summary.count * sizeof (rtems_rtl_obj_t)) +
summary.exec + summary.symbols;
-
+
printf ("Runtime Linker Status:\n");
printf (" paths: %s\n", rtl->paths);
printf (" objects: %d\n", summary.count);
@@ -115,7 +115,7 @@ rtems_rtl_shell_status (rtems_rtl_data_t* rtl, int argc, char *argv[])
printf (" exec memory: %zi\n", summary.exec);
printf (" sym memory: %zi\n", summary.symbols);
printf (" symbols: %d\n", rtems_rtl_count_symbols (rtl));
-
+
return 0;
}
@@ -126,6 +126,7 @@ typedef struct
{
rtems_rtl_data_t* rtl; /**< The RTL data. */
int indent; /**< Spaces to indent. */
+ bool oname; /**< Print object names. */
bool names; /**< Print details of all names. */
bool memory_map; /**< Print the memory map. */
bool symbols; /**< Print the global symbols. */
@@ -144,23 +145,37 @@ rtems_rtl_delta_voids (void* higher, void* lower)
}
/**
- * Object print iterator.
+ * See if -b for base is set.
*/
static bool
-rtems_rtl_obj_print_iterator (rtems_chain_node* node, void* data)
+rtems_rtl_base_arg (int argc, char *argv[])
{
- rtems_rtl_obj_print_t* print = data;
- rtems_rtl_obj_t* obj = (rtems_rtl_obj_t*) node;
- char flags_str[33];
+ int arg;
+ for (arg = 0; arg < argc; ++arg)
+ if (strncmp ("-b", argv[arg], 2) == 0)
+ return true;
+ return false;
+}
+
+/**
+ * Object printer.
+ */
+static bool
+rtems_rtl_obj_printer (rtems_rtl_obj_print_t* print, rtems_rtl_obj_t* obj)
+{
+ char flags_str[33];
/*
* Skip the base module unless asked to show it.
*/
if (!print->base && (obj == print->rtl->base))
return true;
-
- printf ("%-*cobject name : %s\n",
- print->indent, ' ', rtems_rtl_obj_oname (obj));
+
+ if (print->oname)
+ {
+ printf ("%-*cobject name : %s\n",
+ print->indent, ' ', rtems_rtl_obj_oname (obj));
+ }
if (print->names)
{
printf ("%-*cfile name : %s\n",
@@ -176,9 +191,9 @@ rtems_rtl_obj_print_iterator (rtems_chain_node* node, void* data)
printf ("%-*cfile offset : %" PRIdoff_t "\n", print->indent, ' ', obj->ooffset);
printf ("%-*cfile size : %zi\n", print->indent, ' ', obj->fsize);
}
- printf ("%-*cexec size : %zi\n", print->indent, ' ', obj->exec_size);
if (print->memory_map)
{
+ 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));
printf ("%-*cconst base : %p (%zi)\n", print->indent, ' ',
@@ -188,6 +203,7 @@ rtems_rtl_obj_print_iterator (rtems_chain_node* node, void* data)
printf ("%-*cbss base : %p (%zi)\n", print->indent, ' ',
obj->bss_base, obj->bss_size);
}
+ printf ("%-*cunresolved : %lu\n", print->indent, ' ', obj->unresolved);
printf ("%-*csymbols : %zi\n", print->indent, ' ', obj->global_syms);
printf ("%-*csymbol memory : %zi\n", print->indent, ' ', obj->global_size);
if (print->symbols)
@@ -204,15 +220,41 @@ rtems_rtl_obj_print_iterator (rtems_chain_node* node, void* data)
printf ("%-*c%-*s = %p\n", print->indent + 2, ' ',
max_len, obj->global_table[s].name, obj->global_table[s].value);
}
+ printf ("\n");
return true;
}
+/**
+ * Object unresolved symbols printer.
+ */
+static bool
+rtems_rtl_unresolved_printer (rtems_rtl_unresolv_rec_t* rec,
+ void* data)
+{
+ rtems_rtl_obj_print_t* print = (rtems_rtl_obj_print_t*) data;
+ if (rec->type == rtems_rtl_unresolved_name)
+ printf ("%-*c%s\n", print->indent + 2, ' ', rec->rec.name.name);
+ return false;
+}
+
+/**
+ * Object print iterator.
+ */
+static bool
+rtems_rtl_obj_print_iterator (rtems_chain_node* node, void* data)
+{
+ rtems_rtl_obj_print_t* print = data;
+ rtems_rtl_obj_t* obj = (rtems_rtl_obj_t*) node;
+ return rtems_rtl_obj_printer (print, obj);
+}
+
static int
rtems_rtl_shell_list (rtems_rtl_data_t* rtl, int argc, char *argv[])
{
rtems_rtl_obj_print_t print;
print.rtl = rtl;
print.indent = 1;
+ print.oname = true;
print.names = true;
print.memory_map = true;
print.symbols = true;
@@ -226,6 +268,22 @@ rtems_rtl_shell_list (rtems_rtl_data_t* rtl, int argc, char *argv[])
static int
rtems_rtl_shell_sym (rtems_rtl_data_t* rtl, int argc, char *argv[])
{
+ rtems_rtl_obj_print_t print;
+
+
+
+ print.rtl = rtl;
+ print.indent = 1;
+ print.oname = true;
+ print.names = false;
+ print.memory_map = false;
+ print.symbols = true;
+ print.base = rtems_rtl_base_arg (argc, argv);
+ rtems_rtl_chain_iterate (&rtl->objects,
+ rtems_rtl_obj_print_iterator,
+ &print);
+ printf ("Unresolved:\n");
+ rtems_rtl_unresolved_interate (rtems_rtl_unresolved_printer, &print);
return 0;
}
@@ -263,7 +321,7 @@ rtems_rtl_shell_command (int argc, char* argv[])
int arg;
int t;
-
+
for (arg = 1; arg < argc; arg++)
{
if (argv[arg][0] != '-')
@@ -311,6 +369,6 @@ rtems_rtl_shell_command (int argc, char* argv[])
}
printf ("error: command not found: %s (try -h)\n", argv[arg]);
}
-
+
return 1;
}
diff --git a/rtl-sym.c b/rtl-sym.c
index 7e5eb03..0e29693 100644
--- a/rtl-sym.c
+++ b/rtl-sym.c
@@ -60,7 +60,9 @@ bool
rtems_rtl_symbol_table_open (rtems_rtl_symbols_t* symbols,
size_t buckets)
{
- symbols->buckets = calloc (buckets, sizeof (rtems_chain_control));
+ symbols->buckets = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_SYMBOL,
+ buckets * sizeof (rtems_chain_control),
+ true);
if (!symbols->buckets)
{
rtems_rtl_set_error (ENOMEM, "no memory for global symbol table");
@@ -76,7 +78,7 @@ rtems_rtl_symbol_table_open (rtems_rtl_symbols_t* symbols,
void
rtems_rtl_symbol_table_close (rtems_rtl_symbols_t* symbols)
{
- free (symbols->buckets);
+ rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, symbols->buckets);
}
bool
@@ -123,7 +125,7 @@ rtems_rtl_symbol_global_add (rtems_rtl_obj_t* obj,
if (rtems_rtl_trace (RTEMS_RTL_TRACE_GLOBAL_SYM))
printf ("rtl: global symbol add: %zi\n", count);
-
+
obj->global_size = count * sizeof (rtems_rtl_obj_sym_t);
obj->global_table = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_SYMBOL,
obj->global_size, true);
@@ -133,7 +135,7 @@ rtems_rtl_symbol_global_add (rtems_rtl_obj_t* obj,
rtems_rtl_set_error (ENOMEM, "no memory for global symbols");
return false;
}
-
+
symbols = rtems_rtl_global_symbols ();
s = 0;
@@ -151,7 +153,7 @@ rtems_rtl_symbol_global_add (rtems_rtl_obj_t* obj,
void* value;
} copy_voidp;
int b;
-
+
sym->name = (const char*) &esyms[s];
s += strlen (sym->name) + 1;
for (b = 0; b < sizeof (void*); ++b, ++s)
@@ -187,13 +189,13 @@ rtems_rtl_symbol_global_find (const char* name)
{
rtems_rtl_obj_sym_t* sym = (rtems_rtl_obj_sym_t*) node;
/*
- * Use the hash. I could add this to the symbol but it uses more memory..
+ * Use the hash. I could add this to the symbol but it uses more memory.
*/
if (strcmp (name, sym->name) == 0)
return sym;
node = rtems_chain_next (node);
}
-
+
return NULL;
}
@@ -213,7 +215,20 @@ rtems_rtl_symbol_obj_find (rtems_rtl_obj_t* obj, const char* name)
}
void
-rtems_rtl_obj_symbol_erase (rtems_rtl_obj_t* obj)
+rtems_rtl_symbol_obj_add (rtems_rtl_obj_t* obj)
+{
+ rtems_rtl_symbols_t* symbols;
+ rtems_rtl_obj_sym_t* sym;
+ size_t s;
+
+ symbols = rtems_rtl_global_symbols ();
+
+ for (s = 0, sym = obj->global_table; s < obj->global_syms; ++s, ++sym)
+ rtems_rtl_symbol_global_insert (symbols, sym);
+}
+
+void
+rtems_rtl_symbol_obj_erase (rtems_rtl_obj_t* obj)
{
if (obj->global_table)
{
diff --git a/rtl-sym.h b/rtl-sym.h
index 3dc7503..26e6902 100644
--- a/rtl-sym.h
+++ b/rtl-sym.h
@@ -107,11 +107,18 @@ rtems_rtl_obj_sym_t* rtems_rtl_symbol_obj_find (rtems_rtl_obj_t* obj,
const char* name);
/**
+ * Add the object file's symbols to the global table.
+ *
+ * @param obj The object file the symbols are to be added.
+ */
+void rtems_rtl_symbol_obj_add (rtems_rtl_obj_t* obj);
+
+/**
* Erase the object file's symbols.
*
* @param obj The object file the symbols are to be erased from.
*/
-void rtems_rtl_obj_symbol_erase (rtems_rtl_obj_t* obj);
+void rtems_rtl_symbol_obj_erase (rtems_rtl_obj_t* obj);
#ifdef __cplusplus
}
diff --git a/rtl-trace.h b/rtl-trace.h
index 0dc96ab..fea8122 100644
--- a/rtl-trace.h
+++ b/rtl-trace.h
@@ -45,6 +45,7 @@ typedef uint32_t rtems_rtl_trace_mask;
#define RTEMS_RTL_TRACE_GLOBAL_SYM (1UL << 5)
#define RTEMS_RTL_TRACE_LOAD_SECT (1UL << 6)
#define RTEMS_RTL_TRACE_ALLOCATOR (1UL << 7)
+#define RTEMS_RTL_TRACE_UNRESOLVED (1UL << 8)
/**
* Call to check if this part is bring traced. If RTEMS_RTL_TRACE is defined to
diff --git a/rtl-unresolved.c b/rtl-unresolved.c
new file mode 100644
index 0000000..11ba0f4
--- /dev/null
+++ b/rtl-unresolved.c
@@ -0,0 +1,447 @@
+/*
+ * COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems_rtl
+ *
+ * @brief RTEMS Run-Time Linker Object File Unresolved Relocations Table.
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <errno.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <rtl.h>
+#include <rtl-error.h>
+#include <rtl-unresolved.h>
+#include <rtl-trace.h>
+
+static rtems_rtl_unresolv_block_t*
+rtems_rtl_unresolved_block_alloc (rtems_rtl_unresolved_t* unresolved)
+{
+ /*
+ * The block header contains a record.
+ */
+ size_t size =
+ (sizeof(rtems_rtl_unresolv_block_t) +
+ (sizeof(rtems_rtl_unresolv_rec_t) * (unresolved->block_recs - 1)));
+ rtems_rtl_unresolv_block_t* block =
+ rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_EXTERNAL, size, true);
+ if (block)
+ rtems_chain_append (&unresolved->blocks, &block->link);
+ return block;
+}
+
+static size_t
+rtems_rtl_unresolved_name_recs (const char* name)
+{
+ size_t length = strlen (name);
+ return ((length + sizeof(rtems_rtl_unresolv_name_t) - 1) /
+ sizeof(rtems_rtl_unresolv_name_t));
+}
+
+static int
+rtems_rtl_unresolved_rec_index (rtems_rtl_unresolv_block_t* block,
+ rtems_rtl_unresolv_rec_t* rec)
+{
+ return (rec - &block->rec) / sizeof (rtems_rtl_unresolv_rec_t);
+}
+
+static rtems_rtl_unresolv_rec_t*
+rtems_rtl_unresolved_rec_first (rtems_rtl_unresolv_block_t* block)
+{
+ return &block->rec;
+}
+
+static rtems_rtl_unresolv_rec_t*
+rtems_rtl_unresolved_rec_next (rtems_rtl_unresolv_rec_t* rec)
+{
+
+ switch (rec->type)
+ {
+ case rtems_rtl_unresolved_empty:
+ /*
+ * Empty returns NULL. The end of the records in the block.
+ */
+ rec = NULL;
+ break;
+
+ case rtems_rtl_unresolved_name:
+ /*
+ * Determine how many records the name occupies. Round up.
+ */
+ rec += ((rec->rec.name.length + sizeof(rtems_rtl_unresolv_name_t) - 1) /
+ sizeof(rtems_rtl_unresolv_name_t));
+ break;
+
+ case rtems_rtl_unresolved_reloc:
+ ++rec;
+ break;
+
+ default:
+ break;
+ }
+
+ return rec;
+}
+
+static bool
+rtems_rtl_unresolved_rec_is_last (rtems_rtl_unresolv_block_t* block,
+ rtems_rtl_unresolv_rec_t* rec)
+{
+ int index = (rec - &block->rec) / sizeof (rec);
+ return !rec || (index >= block->recs) || (rec->type == rtems_rtl_unresolved_empty);
+}
+
+static rtems_rtl_unresolv_rec_t*
+rtems_rtl_unresolved_rec_first_free (rtems_rtl_unresolv_block_t* block)
+{
+ return &block->rec + block->recs;
+}
+
+static int
+rtems_rtl_unresolved_find_name (rtems_rtl_unresolved_t* unresolved,
+ const char* name,
+ bool update_refcount)
+{
+ size_t length = strlen (name);
+ int index = 1;
+
+ rtems_chain_node* node = rtems_chain_first (&unresolved->blocks);
+ while (!rtems_chain_is_tail (&unresolved->blocks, node))
+ {
+ rtems_rtl_unresolv_block_t* block = (rtems_rtl_unresolv_block_t*) node;
+ rtems_rtl_unresolv_rec_t* rec = rtems_rtl_unresolved_rec_first (block);
+
+ while (!rtems_rtl_unresolved_rec_is_last (block, rec))
+ {
+ if (rec->type == rtems_rtl_unresolved_name)
+ {
+ if ((rec->rec.name.length == length)
+ && (strcmp (rec->rec.name.name, name)))
+ {
+ if (update_refcount)
+ ++rec->rec.name.refs;
+ return index;
+ }
+ ++index;
+ }
+ rec = rtems_rtl_unresolved_rec_next (rec);
+ }
+
+ node = rtems_chain_next (node);
+ }
+
+ return 0 - index;
+}
+
+/**
+ * Struct to pass relocation data in the interator.
+ */
+typedef struct rtems_rtl_unresolved_reloc_data_s
+{
+ uint16_t name; /**< Name index. */
+ rtems_rtl_unresolv_rec_t* name_rec; /**< Name record. */
+ rtems_rtl_obj_sym_t* sym; /**< The symbol record. */
+} rtems_rtl_unresolved_reloc_data_t;
+
+static bool
+rtems_rtl_unresolved_resolve_reloc (rtems_rtl_unresolv_rec_t* rec,
+ void* data)
+{
+ if (rec->type == rtems_rtl_unresolved_reloc)
+ {
+ rtems_rtl_unresolved_reloc_data_t* rd;
+ rd = (rtems_rtl_unresolved_reloc_data_t*) data;
+
+ if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED))
+ printf ("rtl: unresolv: resolve reloc: %s\n", rd->name_rec->rec.name.name);
+
+ if (rec->rec.reloc.name == rd->name)
+ {
+ rtems_rtl_obj_relocate_unresolved (&rec->rec.reloc, rd->sym);
+ /*
+ * 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 && rd->name_rec->rec.name.refs)
+ --rd->name_rec->rec.name.refs;
+ }
+ }
+ return false;
+}
+
+static bool
+rtems_rtl_unresolved_resolve_iterator (rtems_rtl_unresolv_rec_t* rec,
+ void* data)
+{
+ if (rec->type == rtems_rtl_unresolved_name)
+ {
+ rtems_rtl_unresolved_reloc_data_t* rd;
+ rd = (rtems_rtl_unresolved_reloc_data_t*) data;
+
+ ++rd->name;
+
+ if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED))
+ printf ("rtl: unresolv: lookup: %d: %s\n", rd->name, rec->rec.name.name);
+
+ rd->sym = rtems_rtl_symbol_global_find (rec->rec.name.name);
+
+ if (rd->sym)
+ {
+ if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED))
+ printf ("rtl: unresolv: found: %s\n", rec->rec.name.name);
+
+ rd->name_rec = rec;
+
+ rtems_rtl_unresolved_interate (rtems_rtl_unresolved_resolve_reloc, rd);
+
+ rd->name_rec = NULL;
+ rd->sym = NULL;
+ }
+ }
+
+ return false;
+}
+
+static void
+rtems_rtl_unresolved_clean_block (rtems_rtl_unresolv_block_t* block,
+ rtems_rtl_unresolv_rec_t* rec,
+ size_t count,
+ size_t recs_per_block)
+{
+ size_t index = rtems_rtl_unresolved_rec_index (block, rec);
+ size_t bytes =
+ (block->recs - index - count) * sizeof (rtems_rtl_unresolv_rec_t);
+ if (bytes)
+ memmove (rec, rec + count, bytes);
+ --block->recs;
+ bytes = count * sizeof (rtems_rtl_unresolv_rec_t);
+ memset (&block->rec + block->recs, 0, bytes);
+}
+
+static void
+rtems_rtl_unresolved_compact (void)
+{
+ rtems_rtl_unresolved_t* unresolved = rtems_rtl_unresolved ();
+ if (unresolved)
+ {
+ /*
+ * Iterate backwards over the blocks removing any used records. A block is
+ * compacted moving up the block.
+ */
+ rtems_chain_node* node = rtems_chain_last (&unresolved->blocks);
+ while (!rtems_chain_is_head (&unresolved->blocks, node))
+ {
+ rtems_chain_node* prev = rtems_chain_previous (node);
+ rtems_rtl_unresolv_block_t* block = (rtems_rtl_unresolv_block_t*) node;
+ rtems_rtl_unresolv_rec_t* rec = rtems_rtl_unresolved_rec_first (block);
+
+ while (!rtems_rtl_unresolved_rec_is_last (block, rec))
+ {
+ bool next = true;
+
+ if (rec->type == rtems_rtl_unresolved_name)
+ {
+ if (rec->rec.name.refs == 0)
+ {
+ size_t name_recs = rtems_rtl_unresolved_name_recs (rec->rec.name.name);
+ rtems_rtl_unresolved_clean_block (block, rec, name_recs,
+ unresolved->block_recs);
+ next = false;
+ }
+ }
+ else if (rec->type == rtems_rtl_unresolved_reloc)
+ {
+ if (!rec->rec.reloc.obj)
+ {
+ rtems_rtl_unresolved_clean_block (block, rec, 1,
+ unresolved->block_recs);
+ next = false;
+ }
+ }
+
+ if (next)
+ rec = rtems_rtl_unresolved_rec_next (rec);
+ }
+
+ if (block->recs == 0)
+ {
+ rtems_chain_extract (node);
+ free (block);
+ }
+
+ node = prev;
+ }
+ }
+}
+
+bool
+rtems_rtl_unresolved_table_open (rtems_rtl_unresolved_t* unresolved,
+ size_t block_recs)
+{
+ unresolved->marker = 0xdeadf00d;
+ unresolved->block_recs = block_recs;
+ rtems_chain_initialize_empty (&unresolved->blocks);
+ return true;
+}
+
+void
+rtems_rtl_unresolved_table_close (rtems_rtl_unresolved_t* unresolved)
+{
+ rtems_chain_node* node = rtems_chain_first (&unresolved->blocks);
+ while (!rtems_chain_is_tail (&unresolved->blocks, node))
+ {
+ rtems_chain_node* next = rtems_chain_next (node);
+ free (node);
+ node = next;
+ }
+}
+
+bool
+rtems_rtl_unresolved_interate (rtems_rtl_unresolved_iterator_t iterator,
+ void* data)
+{
+ rtems_rtl_unresolved_t* unresolved = rtems_rtl_unresolved ();
+ if (unresolved)
+ {
+ rtems_chain_node* node = rtems_chain_first (&unresolved->blocks);
+ while (!rtems_chain_is_tail (&unresolved->blocks, node))
+ {
+ rtems_rtl_unresolv_block_t* block = (rtems_rtl_unresolv_block_t*) node;
+ rtems_rtl_unresolv_rec_t* rec = rtems_rtl_unresolved_rec_first (block);
+
+ while (!rtems_rtl_unresolved_rec_is_last (block, rec))
+ {
+ if (iterator (rec, data))
+ return true;
+ rec = rtems_rtl_unresolved_rec_next (rec);
+ }
+
+ node = rtems_chain_next (node);
+ }
+ }
+ return false;
+}
+
+bool
+rtems_rtl_unresolved_add (rtems_rtl_obj_t* obj,
+ const uint16_t flags,
+ const char* name,
+ const uint16_t sect,
+ const rtems_rtl_word_t* rel)
+{
+ rtems_rtl_unresolved_t* unresolved;
+ rtems_chain_node* node;
+ rtems_rtl_unresolv_block_t* block;
+ rtems_rtl_unresolv_rec_t* 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",
+ rtems_rtl_obj_oname (obj), sect, name);
+
+ unresolved = rtems_rtl_unresolved ();
+ if (!unresolved)
+ 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_t*) node;
+ if (block->recs < unresolved->block_recs)
+ break;
+ node = rtems_chain_next (node);
+ }
+
+ /*
+ * No blocks with any spare records, allocate a new block.
+ */
+ 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_name_recs (name);
+
+ if ((name_index < 0) && (name_recs < (unresolved->block_recs - block->recs)))
+ {
+ rec = rtems_rtl_unresolved_rec_first_free (block);
+ rec->type = rtems_rtl_unresolved_name;
+ rec->rec.name.refs = 1;
+ rec->rec.name.length = strlen (name) + 1;
+ memcpy ((void*) &rec->rec.name.name[0], name, rec->rec.name.length + 1);
+ block->recs += name_recs;
+ name_index = 0 - name_index;
+
+ if (block->recs >= unresolved->block_recs)
+ {
+ block = rtems_rtl_unresolved_block_alloc (unresolved);
+ if (!block)
+ return false;
+ }
+ }
+
+ rec = rtems_rtl_unresolved_rec_first_free (block);
+ rec->type = rtems_rtl_unresolved_reloc;
+ rec->rec.reloc.obj = obj;
+ rec->rec.reloc.flags = flags;
+ rec->rec.reloc.name = name_index;
+ rec->rec.reloc.sect = sect;
+ rec->rec.reloc.rel[0] = rel[0];
+ rec->rec.reloc.rel[1] = rel[1];
+ rec->rec.reloc.rel[2] = rel[2];
+
+ ++block->recs;
+
+ return true;
+}
+
+void
+rtems_rtl_unresolved_resolve (void)
+{
+ rtems_rtl_unresolved_reloc_data_t rd;
+ if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED))
+ printf ("rtl: unresolv: resolving\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 ();
+}
+
+bool
+rtems_rtl_unresolved_remove (rtems_rtl_obj_t* obj,
+ const char* name,
+ const uint16_t sect,
+ const rtems_rtl_word_t* rel)
+{
+ rtems_rtl_unresolved_t* unresolved;
+ unresolved = rtems_rtl_unresolved ();
+ if (!unresolved)
+ return false;
+ return false;
+}
+
diff --git a/rtl-unresolved.h b/rtl-unresolved.h
new file mode 100644
index 0000000..3431cfe
--- /dev/null
+++ b/rtl-unresolved.h
@@ -0,0 +1,212 @@
+/*
+ * COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems_rtl
+ *
+ * @brief RTEMS Run-Time Linker Object File Unresolved Relocations Table.
+ *
+ * The unresolved relocation table holds relocations in a loaded object file
+ * which reference unresolved external symbols. The support is needed to allow
+ * dependent object files to load. In the case of dependent object files one
+ * will have unresolved externals until the dependent object file is also
+ * loaded. There is no load order that resolves this.
+ *
+ * The unresolved relocation table is a single table used by all object files
+ * with unresolved symbols. It made of blocks linked together where blocks are
+ * allocated as requiered. The table is always maintained compacted. That is as
+ * relocations are resolved and removed the table is compacted. The only
+ * pointer in the table is the object file poniter. This is used to identify
+ * which object the relocation belongs to. There are no linking or back
+ * pointers in the unresolved relocations table. The table is scanned for each
+ * object file's relocations. This is not fast but the table should be small
+ * and if it happens to grow large you have other more pressing issues to
+ * resolve in your application.
+ *
+ * The table holds two (2) types of records:
+ *
+ * # Symbol name strings.
+ * # Relocations.
+ *
+ * The symbol name a relocation references is held in a specific symbol name
+ * string record in the table the relocation record references. The record
+ * counts the number of references and the string is removed from the table
+ * when the reference count reaches 0. There can be many relocations
+ * referencing the symbol. The strings are referenced by a single 16bit
+ * unsigned integer which is the count of the string in the table.
+ *
+ * The section the relocation is for in the object is the section number. The
+ * relocation data is series of machine word sized fields:
+ *
+ * # Offset in the section.
+ * # Relocation info (format specific)
+ * # Additional format specific data.
+ */
+
+#if !defined (_RTEMS_RTL_UNRESOLVED_H_)
+#define _RTEMS_RTL_UNRESOLVED_H_
+
+#include <rtems.h>
+#include <rtl-obj-fwd.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * Hack to work around machine size. This needs to be cleaned up
+ * to better support 64bit targets.
+ */
+typedef uint32_t rtems_rtl_word_t;
+
+/**
+ * The types of records in the blocks.
+ */
+typedef enum rtems_rtl_unresolved_rtype_e
+{
+ rtems_rtl_unresolved_empty = 0, /**< The records is empty. Must always be 0 */
+ rtems_rtl_unresolved_name = 1, /**< The record is a name. */
+ rtems_rtl_unresolved_reloc = 2 /**< The record is a relocation record. */
+} rtems_rtl_unresolved_rtype_t;
+
+/**
+ * Unresolved externals symbol names. The names are reference counted and
+ * separate from the relocation records because a number of records could
+ * reference the same symbol name.
+ */
+typedef struct rtems_rtl_unresolv_name_s
+{
+ uint16_t refs; /**< The number of references to this name. */
+ uint16_t length; /**< The length of this name. */
+ const char name[12]; /**< The symbol name. */
+} rtems_rtl_unresolv_name_t;
+
+/**
+ * Unresolved externals symbols require the relocation records to be held
+ * and references.
+ */
+typedef struct rtems_rtl_unresolv_reloc_s
+{
+ rtems_rtl_obj_t* obj; /**< The relocation's object file. */
+ uint16_t flags; /**< Format specific flags. */
+ uint16_t name; /**< The symbol's name. */
+ uint16_t sect; /**< The target section. */
+ rtems_rtl_word_t rel[3]; /**< Relocation record. */
+} rtems_rtl_unresolv_reloc_t;
+
+/**
+ * Unresolved externals records.
+ */
+typedef struct rtems_rtl_unresolv_rec_s
+{
+ rtems_rtl_unresolved_rtype_t type;
+ union
+ {
+ rtems_rtl_unresolv_name_t name; /**< The name, or */
+ rtems_rtl_unresolv_reloc_t reloc; /**< the relocation record. */
+ } rec;
+} rtems_rtl_unresolv_rec_t;
+
+/**
+ * Unresolved blocks.
+ */
+typedef struct rtems_rtl_unresolv_block_s
+{
+ rtems_chain_node link; /**< Blocks are chained. */
+ uint32_t recs; /**< The number of records in the block. */
+ rtems_rtl_unresolv_rec_t rec; /**< The records. More follow. */
+} rtems_rtl_unresolv_block_t;
+
+/**
+ * Unresolved table holds the names and relocations.
+ */
+typedef struct rtems_rtl_unresolved_s
+{
+ uint32_t marker;
+ size_t block_recs; /**< The records per blocks allocated. */
+ rtems_chain_control blocks; /**< List of blocks. */
+} rtems_rtl_unresolved_t;
+
+/**
+ * The iterator function used to iterate over the unresolved table.
+ *
+ * @param rec The current iterator.
+ * @param data The user data.
+ * @retval true The iterator has finished.
+ * @retval false The iterator has not finished. Keep iterating.
+ */
+typedef bool rtems_rtl_unresolved_iterator_t (rtems_rtl_unresolv_rec_t* rec,
+ void* data);
+
+/**
+ * Open an unresolved relocation table.
+ *
+ * @param unresolv The unresolved table to open.
+ * @param block_records The number of records per block allocated.
+ * @retval true The table is open.
+ * @retval false The unresolved relocation table could not created. The RTL
+ * error has the error.
+ */
+bool rtems_rtl_unresolved_table_open (rtems_rtl_unresolved_t* unresolved,
+ size_t block_records);
+
+/**
+ * Close the table and erase the blocks.
+ *
+ * @param unreolved Close the unresolved table.
+ */
+void rtems_rtl_unresolved_table_close (rtems_rtl_unresolved_t* unresolved);
+
+/**
+ * Iterate over the table of unresolved entries.
+ */
+bool rtems_rtl_unresolved_interate (rtems_rtl_unresolved_iterator_t iterator,
+ void* data);
+
+/**
+ * Add a relocation to the list of unresolved relocations.
+ *
+ * @param unresolved The unresolved symbol table.
+ * @param obj The object table the symbols are for.
+ * @param flags Format specific flags.
+ * @param name The symbol name the relocation references.
+ * @param sect The target section number the relocation references.
+ * @param rel The format specific relocation data.
+ * @retval true The relocation has been added.
+ * @retval false The relocation could not be added.
+ */
+bool rtems_rtl_unresolved_add (rtems_rtl_obj_t* obj,
+ const uint16_t flags,
+ const char* name,
+ const uint16_t sect,
+ const rtems_rtl_word_t* rel);
+
+/**
+ * Resolve the unresolved symbols.
+ */
+void rtems_rtl_unresolved_resolve (void);
+
+/**
+ * Remove a relocation from the list of unresolved relocations.
+ *
+ * @param unresolved The unresolved symbol table.
+ * @param obj The object table the symbols are for.
+ * @param esyms The exported symbol table.
+ * @param size The size of the table in bytes.
+ */
+bool rtems_rtl_unresolved_remove (rtems_rtl_obj_t* obj,
+ const char* name,
+ const uint16_t sect,
+ const rtems_rtl_word_t* rel);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif
diff --git a/rtl.c b/rtl.c
index bad0a7c..b294262 100644
--- a/rtl.c
+++ b/rtl.c
@@ -12,7 +12,7 @@
*
* @brief RTEMS Run-Time Link Editor
*
- * This is the RTL implementation.
+ * This is the RTL implementation.
*/
#if HAVE_CONFIG_H
@@ -36,7 +36,7 @@
*/
#define RTEMS_MUTEX_ATTRIBS \
(RTEMS_PRIORITY | RTEMS_BINARY_SEMAPHORE | \
- RTEMS_INHERIT_PRIORITY | RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL)
+ RTEMS_INHERIT_PRIORITY | RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL)
/**
* Symbol table cache size. They can be big so the cache needs space to work.
@@ -73,7 +73,7 @@ rtems_rtl_base_global_syms_init (void)
static bool
rtems_rtl_data_init (void)
-{
+{
/*
* Lock the RTL. We only create a lock if a call is made. First we test if a
* lock is present. If one is present we lock it. If not the libio lock is
@@ -83,7 +83,7 @@ rtems_rtl_data_init (void)
if (!rtl)
{
rtems_libio_lock ();
-
+
if (!rtl)
{
rtems_status_code sc;
@@ -125,9 +125,9 @@ rtems_rtl_data_init (void)
free (rtl);
return false;
}
-
+
rtl->lock = lock;
-
+
/*
* Initialise the objects list and create any required services.
*/
@@ -141,19 +141,30 @@ rtems_rtl_data_init (void)
return false;
}
+ if (!rtems_rtl_unresolved_table_open (&rtl->unresolved,
+ RTEMS_RTL_UNRESOLVED_BLOCK_SIZE))
+ {
+ rtems_rtl_symbol_table_close (&rtl->globals);
+ rtems_semaphore_delete (lock);
+ free (rtl);
+ return false;
+ }
+
if (!rtems_rtl_obj_cache_open (&rtl->symbols,
RTEMS_RTL_ELF_SYMBOL_CACHE))
{
rtems_rtl_symbol_table_close (&rtl->globals);
+ rtems_rtl_unresolved_table_close (&rtl->unresolved);
rtems_semaphore_delete (lock);
free (rtl);
return false;
}
-
+
if (!rtems_rtl_obj_cache_open (&rtl->strings,
RTEMS_RTL_ELF_STRING_CACHE))
{
rtems_rtl_obj_cache_close (&rtl->symbols);
+ rtems_rtl_unresolved_table_close (&rtl->unresolved);
rtems_rtl_symbol_table_close (&rtl->globals);
rtems_semaphore_delete (lock);
free (rtl);
@@ -165,18 +176,20 @@ rtems_rtl_data_init (void)
{
rtems_rtl_obj_cache_close (&rtl->strings);
rtems_rtl_obj_cache_close (&rtl->symbols);
+ rtems_rtl_unresolved_table_close (&rtl->unresolved);
rtems_rtl_symbol_table_close (&rtl->globals);
rtems_semaphore_delete (lock);
free (rtl);
return false;
}
-
+
rtl->base = rtems_rtl_obj_alloc ();
if (!rtl->base)
{
rtems_rtl_obj_cache_close (&rtl->relocs);
rtems_rtl_obj_cache_close (&rtl->strings);
rtems_rtl_obj_cache_close (&rtl->symbols);
+ rtems_rtl_unresolved_table_close (&rtl->unresolved);
rtems_rtl_symbol_table_close (&rtl->globals);
rtems_semaphore_delete (lock);
free (rtl);
@@ -190,7 +203,7 @@ rtems_rtl_data_init (void)
rtems_chain_append (&rtl->objects, &rtl->base->link);
}
-
+
rtems_libio_unlock ();
rtems_rtl_path_append (".");
@@ -216,6 +229,14 @@ rtems_rtl_global_symbols (void)
return &rtl->globals;
}
+rtems_rtl_unresolved_t*
+rtems_rtl_unresolved (void)
+{
+ if (!rtl)
+ return NULL;
+ return &rtl->unresolved;
+}
+
void
rtems_rtl_obj_caches (rtems_rtl_obj_cache_t** symbols,
rtems_rtl_obj_cache_t** strings,
@@ -360,12 +381,14 @@ rtems_rtl_load_object (const char* name, int mode)
}
rtems_chain_append (&rtl->objects, &obj->link);
-
+
if (!rtems_rtl_obj_load (obj))
{
rtems_rtl_obj_free (obj);
return NULL;
}
+
+ rtems_rtl_unresolved_resolve ();
}
/*
@@ -374,6 +397,12 @@ rtems_rtl_load_object (const char* name, int mode)
++obj->users;
/*
+ * FIXME: Resolving exsiting unresolved symbols could add more constructors
+ * lists that need to be called. Make a list in the obj load layer and
+ * invoke the list here.
+ */
+
+ /*
* Run any local constructors if this is the first user because the object
* file will have just been loaded. Unlock the linker to avoid any dead locks
* if the object file needs to load files or update the symbol table. We also
@@ -395,7 +424,7 @@ bool
rtems_rtl_unload_object (rtems_rtl_obj_t* obj)
{
bool ok = true;
-
+
if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNLOAD))
printf ("rtl: unloading '%s'\n", rtems_rtl_obj_fname (obj));
@@ -407,7 +436,7 @@ rtems_rtl_unload_object (rtems_rtl_obj_t* obj)
rtems_rtl_set_error (EINVAL, "cannot unload when locked");
return false;
}
-
+
/*
* Check the number of users in a safe manner. If this is the last user unload the
* object file from memory.
@@ -425,7 +454,7 @@ rtems_rtl_unload_object (rtems_rtl_obj_t* obj)
ok = rtems_rtl_obj_unload (obj);
}
-
+
return ok;
}
@@ -442,19 +471,19 @@ rtems_rtl_path_update (bool prepend, const char* path)
const char* src = NULL;
char* dst;
int len;
-
+
if (!rtems_rtl_lock ())
return false;
len = strlen (path);
-
+
if (rtl->paths)
len += strlen (rtl->paths) + 1;
else
prepend = true;
-
+
paths = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, len + 1, false);
-
+
if (!paths)
{
rtems_rtl_unlock ();
@@ -462,7 +491,7 @@ rtems_rtl_path_update (bool prepend, const char* path)
}
dst = paths;
-
+
if (prepend)
{
len = strlen (path);
@@ -477,7 +506,7 @@ rtems_rtl_path_update (bool prepend, const char* path)
memcpy (dst, src, len);
dst += len;
-
+
if (rtl->paths)
{
*dst = ':';
@@ -501,11 +530,11 @@ rtems_rtl_path_update (bool prepend, const char* path)
memcpy (dst, src, len);
dst += len;
}
-
+
*dst = '\0';
rtl->paths = paths;
-
+
rtems_rtl_unlock ();
return false;
}
@@ -528,15 +557,15 @@ rtems_rtl_base_sym_global_add (const unsigned char* esyms,
{
if (rtems_rtl_trace (RTEMS_RTL_TRACE_GLOBAL_SYM))
printf ("rtl: adding global symbols, table size %u\n", size);
-
+
if (!rtems_rtl_lock ())
{
rtems_rtl_set_error (EINVAL, "global add cannot lock rtl");
return;
}
-
+
rtems_rtl_symbol_global_add (rtl->base, esyms, size);
-
+
rtems_rtl_unlock ();
}
diff --git a/rtl.h b/rtl.h
index 03d15e2..9c33b50 100644
--- a/rtl.h
+++ b/rtl.h
@@ -22,13 +22,11 @@
#include <rtems.h>
#include <rtems/chain.h>
-// #include <rtems/rtl/rtl-elf.h>
-
#include <rtl-allocator.h>
#include <rtl-fwd.h>
-#include <rtl-elf.h>
#include <rtl-obj.h>
#include <rtl-obj-cache.h>
+#include <rtl-unresolved.h>
#ifdef __cplusplus
extern "C" {
@@ -48,13 +46,18 @@ extern "C" {
* files or in an archive. Object files in an archive are referenced by
* specifing 'archive:object' format. For example 'libfoo.a:bar.o'.
*/
-
+
/**
* The number of buckets in the global symbol table.
*/
#define RTEMS_RTL_SYMS_GLOBAL_BUCKETS (32)
/**
+ * The number of relocation record per block in the unresolved table.
+ */
+#define RTEMS_RTL_UNRESOLVED_BLOCK_SIZE (64)
+
+/**
* The global debugger interface variable.
*/
extern struct r_debug _rtld_debug;
@@ -69,7 +72,7 @@ extern void _rtld_debug_state (void);
* The type of constructor/destructor function.
*/
typedef void (*rtems_rtl_cdtor_t)(void);
-
+
/**
* The global RTL data. This structure is allocated on the heap when the first
* call to the RTL is made and never released.
@@ -85,6 +88,7 @@ struct rtems_rtl_data_s
rtems_chain_control objects; /**< List if loaded object files. */
const char* paths; /**< Search paths for archives. */
rtems_rtl_symbols_t globals; /**< Global symbol table. */
+ rtems_rtl_unresolved_t unresolved; /**< Unresolved symbols. */
rtems_rtl_obj_t* base; /**< Base object file. */
rtems_rtl_obj_cache_t symbols; /**< Symbols object file cache. */
rtems_rtl_obj_cache_t strings; /**< Strings object file cache. */
@@ -111,6 +115,15 @@ rtems_rtl_data_t* rtems_rtl_data (void);
rtems_rtl_symbols_t* rtems_rtl_global_symbols (void);
/**
+ * Get the RTL resolved table with out locking. This call assmes the RTL
+ * is locked.
+ *
+ * @return rtems_rtl_unresolv_t* The RTL unresolved symbols and reloc records.
+ * @retval NULL The RTL data is not initialised.
+ */
+rtems_rtl_unresolved_t* rtems_rtl_unresolved (void);
+
+/**
* Get the RTL symbols, strings, or relocations object file caches. This call
* assmes the RTL is locked.
*
@@ -171,21 +184,24 @@ rtems_rtl_obj_t* rtems_rtl_find_obj (const char* name);
* Load an object file into memory relocating it. It will not be resolved
* against other symbols in other object files or the base image.
*
- * The name can be a file name for an ELF object file or it can be encoded to
+ * The name can be a file name for an object file or it can be encoded to
* reference an archive of object modules (static library). This encoding is
* specific to RTEMS and allows dependences to specify an archive without the
* searching overhead normally incurred by linkers locating object files in an
* archive. The file name format rules are:
*
- * 1. Absolute file references a specific ELF format file in that specific
- * location on the file system.
- * 2. Relative file references an ELF format file in the search path.
+ * 1. Absolute file references a specific object file in the architecture
+ * specific location on the file system.
+ *
+ * 2. Relative file references an object format file in the search path.
+ *
* 3. Absolute archive and file reference to a specific location in the file
* system. The archive and file are encoded as 'archive:file [@offset]'
* where 'archive' is a valid file at the absolute path in the file system,
* and 'file' is a contained in the archive, and optionally an offset to
* the 'file' in the 'archive'. If no offset is provided the archive is
* searched.
+ *
* 4. Relative archive and file in the search path. The encoding is the same
* as described in item 3 of this list.
*
@@ -215,7 +231,7 @@ bool rtems_rtl_unload_object (rtems_rtl_obj_t* obj);
* @param obj The object file.
*/
void rtems_rtl_run_ctors (rtems_rtl_obj_t* obj);
-
+
/**
* Get the last error message clearing it. This operation locks the run time
* linker and therefore keeps the RTL thread safe.
diff --git a/shell-init b/shell-init
index d8261ad..f958e55 100644
--- a/shell-init
+++ b/shell-init
@@ -1,4 +1,4 @@
-rtl-trace set all
+#rtl-trace set all
#rtl-trace set load load-sect reloc
dlo libx.a:xa.c.2.o
-#dlo libx.a:x-long-name-to-create-gnu-extension-in-archive.c.2.o
+dlo libx.a:x-long-name-to-create-gnu-extension-in-archive.c.2.o
diff --git a/wscript b/wscript
index 7ab2cbf..c58964f 100644
--- a/wscript
+++ b/wscript
@@ -17,6 +17,9 @@ def configure(conf):
conf.env.ASCIIDOC = conf.find_program(['asciidoc.py'], mandatory = False)
conf.env.ASCIIDOC_FLAGS = ['-b', 'html5', '-a', 'data-uri', '-a', 'icons', '-a', 'max-width=55em-a']
+ # hack on at the moment.
+ conf.env.GSYM_EMBEDDED = True
+
def build(bld):
bld.add_post_fun(rtl_post_build)
@@ -24,10 +27,14 @@ def build(bld):
arch = bld.get_env()['RTEMS_ARCH']
- bld.includes = ['.',
+ bld.includes = ['.',
'libbsd/include',
'libbsd/include/arch/' + arch]
+ bld.defines = ['PACKAGE_VERSION="' + version + '"']
+ if bld.env.GSYM_EMBEDDED:
+ bld.defines += ['RTL_GSYM_EMBEDDED=1']
+
rtl_source(bld, arch)
rtl_liba(bld, arch)
rtl_root_fs(bld)
@@ -39,7 +46,7 @@ def build(bld):
'main.c',
'fs-root-tarfile.o'],
includes = bld.includes,
- defines = ['PACKAGE_VERSION="' + version + '"'],
+ defines = bld.defines,
use = ['rtl', 'rootfs', 'rtld-gsyms'],
depends_on = 'gsyms')
@@ -72,15 +79,17 @@ def rtl_source(bld, arch):
'rtl-string.c',
'rtl-sym.c',
'rtl-trace.c',
+ 'rtl-unresolved.c',
'rtl-mdreloc-' + arch + '.c'])
def rtl_liba(bld, arch):
bld(target = 'x',
features = 'c cstlib',
includes = bld.includes,
+ defines = bld.defines,
source = ['xa.c',
'x-long-name-to-create-gnu-extension-in-archive.c'])
-
+
def mmap_source(bld, includes):
bld(target = 'mmap',
features = 'c',
@@ -111,35 +120,20 @@ def rtl_gsyms(bld):
import os
sb = os.stat(src)
if sb.st_size == 0:
+ if bld.env.GSYM_EMBEDDED:
+ flags = '--embed'
+ else:
+ flags = ''
bld(name = 'gsyms',
target = 'gsyms.c',
always = True,
- rule = '${NM} -g rtld | awk -f ../../mksyms.awk - > ${TGT}')
- else:
- open(src, 'a').close()
- bld(target = 'rtld-gsyms',
- features = 'c',
- includes = bld.includes,
- source = ['rtld-gsyms.c'],
- depends_on = 'gsyms')
-
-def x_rtl_gsyms(bld):
- import os.path
- src = os.path.join(bld.get_variant_dir(), 'gsyms.c')
- if os.path.exists(src):
- if os.path.exists(os.path.join(bld.get_variant_dir(), 'rtld')):
- import os
- sb = os.stat(src)
- if sb.st_size == 0:
- bld(name = 'gsyms',
- target = 'gsyms.c',
- always = True,
- rule = '${NM} -g rtld | awk -f ../../mksyms.awk - > ${TGT}')
+ rule = '${NM} -g rtld | awk -f ../../mksyms.awk - ' + flags + ' > ${TGT}')
else:
open(src, 'a').close()
bld(target = 'rtld-gsyms',
features = 'c',
includes = bld.includes,
+ defines = bld.defines,
source = ['rtld-gsyms.c'],
depends_on = 'gsyms')
diff --git a/x-long-name-to-create-gnu-extension-in-archive.c b/x-long-name-to-create-gnu-extension-in-archive.c
index e94cf0c..38cf079 100644
--- a/x-long-name-to-create-gnu-extension-in-archive.c
+++ b/x-long-name-to-create-gnu-extension-in-archive.c
@@ -14,6 +14,10 @@ void y_writeln(const char* s) __attribute__ ((section (".bar")));
int z_writeln(int argc, const char* argv[]);
int my_main (int argc, char* argv[]);
+#if RTL_GSYM_EMBEDDED
+#define sin(_d) (_d)
+#endif
+
void
w_writeln(double d)
{