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