summaryrefslogtreecommitdiffstats
path: root/cpukit/libdl
diff options
context:
space:
mode:
Diffstat (limited to 'cpukit/libdl')
-rw-r--r--cpukit/libdl/rtl-elf.c150
-rw-r--r--cpukit/libdl/rtl-obj.c63
2 files changed, 187 insertions, 26 deletions
diff --git a/cpukit/libdl/rtl-elf.c b/cpukit/libdl/rtl-elf.c
index 53f43aaeac..c1821bcfda 100644
--- a/cpukit/libdl/rtl-elf.c
+++ b/cpukit/libdl/rtl-elf.c
@@ -72,7 +72,8 @@ rtems_rtl_elf_find_symbol (rtems_rtl_obj* obj,
{
rtems_rtl_obj_sect* sect;
- if (ELF_ST_TYPE(sym->st_info) == STT_NOTYPE)
+ if (ELF_ST_TYPE(sym->st_info) == STT_NOTYPE ||
+ sym->st_shndx == SHN_COMMON)
{
/*
* Search the object file then the global table for the symbol.
@@ -185,9 +186,10 @@ rtems_rtl_elf_relocator (rtems_rtl_obj* obj,
return false;
/*
- * Only need the name of the symbol if global.
+ * Only need the name of the symbol if global or a common symbol.
*/
- if (ELF_ST_TYPE (sym.st_info) == STT_NOTYPE)
+ if (ELF_ST_TYPE (sym.st_info) == STT_NOTYPE ||
+ sym.st_shndx == SHN_COMMON)
{
size_t len;
off = obj->ooffset + strtab->offset + sym.st_name;
@@ -337,6 +339,68 @@ rtems_rtl_obj_relocate_unresolved (rtems_rtl_unresolv_reloc* reloc,
return true;
}
+/**
+ * Common symbol iterator data.
+ */
+typedef struct
+{
+ size_t size; /**< The size of the common section */
+ uint32_t alignment; /**< The alignment of the common section. */
+} rtems_rtl_elf_common_data;
+
+static bool
+rtems_rtl_elf_common (rtems_rtl_obj* obj,
+ int fd,
+ rtems_rtl_obj_sect* sect,
+ void* data)
+{
+ rtems_rtl_elf_common_data* common = (rtems_rtl_elf_common_data*) data;
+ rtems_rtl_obj_cache* symbols;
+ int sym;
+
+ rtems_rtl_obj_caches (&symbols, NULL, NULL);
+
+ if (!symbols)
+ return false;
+
+ /*
+ * Find the number size of the common section by finding all symbols that
+ * reference the SHN_COMMON section.
+ */
+ for (sym = 0; sym < (sect->size / sizeof (Elf_Sym)); ++sym)
+ {
+ Elf_Sym symbol;
+ off_t off;
+
+ off = obj->ooffset + sect->offset + (sym * sizeof (symbol));
+
+ if (!rtems_rtl_obj_cache_read_byval (symbols, fd, off,
+ &symbol, sizeof (symbol)))
+ return false;
+
+ if ((symbol.st_shndx == SHN_COMMON) &&
+ ((ELF_ST_TYPE (symbol.st_info) == STT_OBJECT) ||
+ (ELF_ST_TYPE (symbol.st_info) == STT_COMMON)))
+ {
+ if (rtems_rtl_trace (RTEMS_RTL_TRACE_SYMBOL))
+ printf ("rtl: com:elf:%-2d bind:%-2d type:%-2d size:%d value:%d\n",
+ sym, (int) ELF_ST_BIND (symbol.st_info),
+ (int) ELF_ST_TYPE (symbol.st_info),
+ (int) symbol.st_size, (int) symbol.st_value);
+ /*
+ * If the size is zero this is the first entry, it defines the common
+ * section's aligment. The symbol's value is the alignment.
+ */
+ if (common->size == 0)
+ common->alignment = symbol.st_value;
+ common->size +=
+ rtems_rtl_obj_align (common->size, symbol.st_value) + symbol.st_size;
+ }
+ }
+
+ return true;
+}
+
static bool
rtems_rtl_elf_symbols (rtems_rtl_obj* obj,
int fd,
@@ -354,6 +418,7 @@ rtems_rtl_elf_symbols (rtems_rtl_obj* obj,
int global_string_space;
rtems_rtl_obj_sym* gsym;
char* gstring;
+ size_t common_offset;
int sym;
strtab = rtems_rtl_obj_find_section (obj, ".strtab");
@@ -403,15 +468,28 @@ rtems_rtl_elf_symbols (rtems_rtl_obj* obj,
* object file has been loaded. Undefined symbols are NOTYPE so for locals
* we need to make sure there is a valid seciton.
*/
+ if (rtems_rtl_trace (RTEMS_RTL_TRACE_SYMBOL))
+ printf ("rtl: sym:elf:%-2d name:%-2d:%-20s bind:%-2d " \
+ "type:%-2d sect:%d size:%d\n",
+ sym, (int) symbol.st_name, name,
+ (int) ELF_ST_BIND (symbol.st_info),
+ (int) ELF_ST_TYPE (symbol.st_info),
+ symbol.st_shndx,
+ (int) symbol.st_size);
+
if ((symbol.st_shndx != 0) &&
((ELF_ST_TYPE (symbol.st_info) == STT_OBJECT) ||
+ (ELF_ST_TYPE (symbol.st_info) == STT_COMMON) ||
(ELF_ST_TYPE (symbol.st_info) == STT_FUNC) ||
(ELF_ST_TYPE (symbol.st_info) == STT_NOTYPE)))
{
+ /*
+ * There needs to be a valid section for the symbol.
+ */
rtems_rtl_obj_sect* symsect;
symsect = rtems_rtl_obj_find_section_by_index (obj, symbol.st_shndx);
- if (symsect)
+ if (symsect != NULL)
{
if ((ELF_ST_BIND (symbol.st_info) == STB_GLOBAL) ||
(ELF_ST_BIND (symbol.st_info) == STB_WEAK))
@@ -431,12 +509,18 @@ rtems_rtl_elf_symbols (rtems_rtl_obj* obj,
}
else
{
+ if (rtems_rtl_trace (RTEMS_RTL_TRACE_SYMBOL))
+ printf ("rtl: sym:elf:%-2d name:%-2d:%-20s: global\n",
+ sym, (int) symbol.st_name, name);
++globals;
global_string_space += strlen (name) + 1;
}
}
else if (ELF_ST_BIND (symbol.st_info) == STB_LOCAL)
{
+ if (rtems_rtl_trace (RTEMS_RTL_TRACE_SYMBOL))
+ printf ("rtl: sym:elf:%-2d name:%-2d:%-20s: local\n",
+ sym, (int) symbol.st_name, name);
++locals;
local_string_space += strlen (name) + 1;
}
@@ -487,6 +571,8 @@ rtems_rtl_elf_symbols (rtems_rtl_obj* obj,
gstring =
(((char*) obj->global_table) + (globals * sizeof (rtems_rtl_obj_sym)));
+ common_offset = 0;
+
for (sym = 0; sym < (sect->size / sizeof (Elf_Sym)); ++sym)
{
Elf_Sym symbol;
@@ -524,6 +610,7 @@ rtems_rtl_elf_symbols (rtems_rtl_obj* obj,
if ((symbol.st_shndx != 0) &&
((ELF_ST_TYPE (symbol.st_info) == STT_OBJECT) ||
+ (ELF_ST_TYPE (symbol.st_info) == STT_COMMON) ||
(ELF_ST_TYPE (symbol.st_info) == STT_FUNC) ||
(ELF_ST_TYPE (symbol.st_info) == STT_NOTYPE)) &&
((ELF_ST_BIND (symbol.st_info) == STB_GLOBAL) ||
@@ -533,6 +620,7 @@ rtems_rtl_elf_symbols (rtems_rtl_obj* obj,
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)
@@ -553,10 +641,25 @@ rtems_rtl_elf_symbols (rtems_rtl_obj* obj,
++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 = symbol.st_value + (uint8_t*) symsect->base;
+ osym->value = value + (uint8_t*) symsect->base;
osym->data = symbol.st_info;
if (rtems_rtl_trace (RTEMS_RTL_TRACE_SYMBOL))
@@ -656,13 +759,13 @@ 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;
- flags = 0;
-
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,
(int) shdr.sh_link, (int) shdr.sh_info);
+ flags = 0;
+
switch (shdr.sh_type)
{
case SHT_NULL:
@@ -771,6 +874,19 @@ rtems_rtl_elf_parse_sections (rtems_rtl_obj* obj, int fd, Elf_Ehdr* ehdr)
return true;
}
+static bool
+rtems_rtl_elf_add_common (rtems_rtl_obj* obj, size_t size, uint32_t alignment)
+{
+ if (size > 0)
+ {
+ if (!rtems_rtl_obj_add_section (obj, SHN_COMMON, ".common.rtems.rtl",
+ size, 0, alignment, 0, 0,
+ RTEMS_RTL_OBJ_SECT_BSS | RTEMS_RTL_OBJ_SECT_ZERO))
+ return false;
+ }
+ return true;
+}
+
bool
rtems_rtl_elf_file_check (rtems_rtl_obj* obj, int fd)
{
@@ -906,8 +1022,9 @@ rtems_rtl_elf_load_linkmap (rtems_rtl_obj* obj)
bool
rtems_rtl_elf_file_load (rtems_rtl_obj* obj, int fd)
{
- rtems_rtl_obj_cache* header;
- Elf_Ehdr ehdr;
+ rtems_rtl_obj_cache* header;
+ Elf_Ehdr ehdr;
+ rtems_rtl_elf_common_data common = { .size = 0, .alignment = 0 };
rtems_rtl_obj_caches (&header, NULL, NULL);
@@ -965,8 +1082,23 @@ rtems_rtl_elf_file_load (rtems_rtl_obj* obj, int fd)
if (!rtems_rtl_elf_parse_sections (obj, fd, &ehdr))
return false;
+ /*
+ * See if there are any common variables and if there are add a common
+ * section.
+ */
+ if (!rtems_rtl_obj_load_symbols (obj, fd, rtems_rtl_elf_common, &common))
+ return false;
+ if (!rtems_rtl_elf_add_common (obj, common.size, common.alignment))
+ return false;
+
+ /*
+ * Set the entry point if there is one.
+ */
obj->entry = (void*)(uintptr_t) ehdr.e_entry;
+ /*
+ * Load the sections and symbols and then relocation to the base address.
+ */
if (!rtems_rtl_obj_load_sections (obj, fd, rtems_rtl_elf_loader, &ehdr))
return false;
diff --git a/cpukit/libdl/rtl-obj.c b/cpukit/libdl/rtl-obj.c
index 45deccfb44..7109b86fe8 100644
--- a/cpukit/libdl/rtl-obj.c
+++ b/cpukit/libdl/rtl-obj.c
@@ -246,19 +246,6 @@ rtems_rtl_scan_decimal (const uint8_t* string, size_t len)
}
/**
- * Align the size to the next alignment point. Assume the alignment is a
- * positive integral power of 2 if not 0 or 1. If 0 or 1 then there is no
- * alignment.
- */
-static size_t
-rtems_rtl_sect_align (size_t offset, uint32_t alignment)
-{
- if ((alignment > 1) && ((offset & (alignment - 1)) != 0))
- offset = (offset + alignment) & ~(alignment - 1);
- return offset;
-}
-
-/**
* Section size summer iterator data.
*/
typedef struct
@@ -274,7 +261,7 @@ rtems_rtl_obj_sect_summer (rtems_chain_node* node, void* data)
rtems_rtl_obj_sect_summer_data* summer = data;
if ((sect->flags & summer->mask) == summer->mask)
summer->size =
- rtems_rtl_sect_align (summer->size, sect->alignment) + sect->size;
+ rtems_rtl_obj_align (summer->size, sect->alignment) + sect->size;
return true;
}
@@ -438,9 +425,9 @@ rtems_rtl_obj_add_section (rtems_rtl_obj* obj,
rtems_chain_append (&obj->sections, &sect->node);
if (rtems_rtl_trace (RTEMS_RTL_TRACE_SECTION))
- printf ("rtl: sect: %-2d: %s (%zu)\n", section, name, size);
+ printf ("rtl: sect: add: %-2d: %s (%zu) 0x%08lx\n",
+ section, name, size, flags);
}
-
return true;
}
@@ -467,6 +454,8 @@ typedef struct
rtems_rtl_obj_sect* sect; /**< The matching section. */
const char* name; /**< The name to match. */
int index; /**< The index to match. */
+ uint32_t mask; /**< The mask to match. */
+ unsigned int flags; /**< The flags to use when matching. */
} rtems_rtl_obj_sect_finder;
static bool
@@ -489,6 +478,8 @@ rtems_rtl_obj_find_section (const rtems_rtl_obj* obj,
rtems_rtl_obj_sect_finder match;
match.sect = NULL;
match.name = name;
+ match.mask = 0;
+ match.flags = 0;
rtems_rtl_chain_iterate ((rtems_chain_control*) &obj->sections,
rtems_rtl_obj_sect_match_name,
&match);
@@ -515,12 +506,50 @@ rtems_rtl_obj_find_section_by_index (const rtems_rtl_obj* obj,
rtems_rtl_obj_sect_finder match;
match.sect = NULL;
match.index = index;
+ match.mask = 0;
+ match.flags = 0;
rtems_rtl_chain_iterate ((rtems_chain_control*) &obj->sections,
rtems_rtl_obj_sect_match_index,
&match);
return match.sect;
}
+static bool
+rtems_rtl_obj_sect_match_mask (rtems_chain_node* node, void* data)
+{
+ rtems_rtl_obj_sect* sect = (rtems_rtl_obj_sect*) node;
+ rtems_rtl_obj_sect_finder* match = data;
+ if (match->flags == 0)
+ {
+ if (match->index < 0 || sect->section == match->index)
+ match->flags = 1;
+ if (match->index >= 0)
+ return true;
+ }
+ if ((sect->flags & match->mask) != 0)
+ {
+ match->sect = sect;
+ return false;
+ }
+ return true;
+}
+
+rtems_rtl_obj_sect*
+rtems_rtl_obj_find_section_by_mask (const rtems_rtl_obj* obj,
+ int index,
+ uint32_t mask)
+{
+ rtems_rtl_obj_sect_finder match;
+ match.sect = NULL;
+ match.index = index;
+ match.mask = mask;
+ match.flags = 0;
+ rtems_rtl_chain_iterate ((rtems_chain_control*) &obj->sections,
+ rtems_rtl_obj_sect_match_mask,
+ &match);
+ return match.sect;
+}
+
size_t
rtems_rtl_obj_text_size (const rtems_rtl_obj* obj)
{
@@ -775,7 +804,7 @@ rtems_rtl_obj_sections_loader (uint32_t mask,
if (sect->load_order == order)
{
if (!first)
- base_offset = rtems_rtl_sect_align (base_offset, sect->alignment);
+ base_offset = rtems_rtl_obj_align (base_offset, sect->alignment);
first = false;