diff options
Diffstat (limited to 'cpukit/libdl/rtl-elf.c')
-rw-r--r-- | cpukit/libdl/rtl-elf.c | 150 |
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; |