summaryrefslogtreecommitdiffstats
path: root/cpukit/libdl/rtl-elf.c
diff options
context:
space:
mode:
authorChris Johns <chrisj@rtems.org>2018-11-13 17:26:17 +1100
committerChris Johns <chrisj@rtems.org>2018-11-22 12:43:21 +1100
commit803eac954ed7a3481c6af9b020d5d25419d3a19d (patch)
tree03f0a06f907a5dd5e26a68c8b3c67c6722300833 /cpukit/libdl/rtl-elf.c
parentpsxtmbarrierattr01: Added new POSIX timing suite (GCI 2018) (diff)
downloadrtems-803eac954ed7a3481c6af9b020d5d25419d3a19d.tar.bz2
libdl: Manage the allocation of common uninitialised variables.
The use of separate text and data results in uninitialised variables being placed in the common section. There is no section in ELF for the common variables so the loader needs to create the section and allocate the variables in that section. This patch does that. The patch adds a second pass over the symbols. The issue can also be seen as a section 65522 error. Updates #3604
Diffstat (limited to 'cpukit/libdl/rtl-elf.c')
-rw-r--r--cpukit/libdl/rtl-elf.c150
1 files changed, 141 insertions, 9 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;