diff --git a/libs/libc/elf/elf.h b/libs/libc/elf/elf.h index 986a3fa5803a9..7d5a7bcd67184 100644 --- a/libs/libc/elf/elf.h +++ b/libs/libc/elf/elf.h @@ -238,6 +238,34 @@ int libelf_reallocbuffer(FAR struct mod_loadinfo_s *loadinfo, int libelf_freebuffers(FAR struct mod_loadinfo_s *loadinfo); +/**************************************************************************** + * Name: libelf_addr + * + * Description: + * Translate a link-time address in a loaded object to the address it + * occupies now. An address below the data segment's link-time base + * belongs to text, anything at or above it to data. + * + * Input Parameters: + * loadinfo - Load state information + * vaddr - The link-time address to translate + * + * Returned Value: + * The run-time address. + * + ****************************************************************************/ + +static inline uintptr_t libelf_addr(FAR struct mod_loadinfo_s *loadinfo, + uintptr_t vaddr) +{ + if (loadinfo->datasec != 0 && vaddr >= loadinfo->datasec) + { + return loadinfo->datastart + (vaddr - loadinfo->datasec); + } + + return loadinfo->textalloc + vaddr; +} + #ifdef CONFIG_ARCH_ADDRENV /**************************************************************************** diff --git a/libs/libc/elf/elf_bind.c b/libs/libc/elf/elf_bind.c index 34f3fddf79d14..dddb626add817 100644 --- a/libs/libc/elf/elf_bind.c +++ b/libs/libc/elf/elf_bind.c @@ -815,56 +815,48 @@ static int libelf_relocatedyn(FAR struct module_s *modp, if (sym[idx_sym].st_shndx == SHN_UNDEF) { - FAR void *ep; - - ep = libelf_findglobal(modp, loadinfo, symhdr, - &sym[idx_sym]); - if ((ep == NULL) && (ELF_ST_BIND(sym[idx_sym].st_info) - != STB_WEAK)) - { - berr("ERROR: Unable to resolve addr of ext ref %s\n", - loadinfo->iobuffer); - ret = -EINVAL; - lib_free(sym); - lib_free(rels); - lib_free(dyn); - return ret; - } - - addr = rel->r_offset + loadinfo->textalloc; - - if (reldata.relrela[idx_rel] == 1) - { - addr += rela->r_addend; - } - - *(FAR uintptr_t *)addr = (uintptr_t)ep; + FAR void *ep; + + ep = libelf_findglobal(modp, loadinfo, symhdr, + &sym[idx_sym]); + if ((ep == NULL) && (ELF_ST_BIND(sym[idx_sym].st_info) + != STB_WEAK)) + { + berr("ERROR: Unable to resolve addr of ext ref %s\n", + loadinfo->iobuffer); + ret = -EINVAL; + lib_free(sym); + lib_free(rels); + lib_free(dyn); + return ret; + } + + addr = libelf_addr(loadinfo, rel->r_offset); + + if (reldata.relrela[idx_rel] == 1) + { + addr += rela->r_addend; + } + + *(FAR uintptr_t *)addr = (uintptr_t)ep; } } else { Elf_Sym dynsym = - { - 0 - }; + { + 0 + }; - addr = rel->r_offset - loadinfo->datasec + loadinfo->datastart; + addr = libelf_addr(loadinfo, rel->r_offset); if (reldata.relrela[idx_rel] == 1) { addr += rela->r_addend; } - if ((*(FAR uint32_t *)addr) < loadinfo->datasec) - { - dynsym.st_value = *(FAR uint32_t *)addr + - loadinfo->textalloc; - } - else - { - dynsym.st_value = *(FAR uint32_t *)addr - - loadinfo->datasec + loadinfo->datastart; - } + dynsym.st_value = libelf_addr(loadinfo, + *(FAR uint32_t *)addr); ret = up_relocate(rel, &dynsym, addr, ARCH_ELFDATA_PARM); } @@ -951,6 +943,7 @@ int libelf_bind(FAR struct module_s *modp, /* Get the index to the relocation section */ int infosec = loadinfo->shdr[i].sh_info; + if (infosec >= loadinfo->ehdr.e_shnum) { continue; @@ -968,23 +961,20 @@ int libelf_bind(FAR struct module_s *modp, loadinfo->dsymtabidx = i; break; case SHT_INIT_ARRAY: - loadinfo->initarr = loadinfo->shdr[i].sh_addr - - loadinfo->datasec + - loadinfo->datastart; + loadinfo->initarr = libelf_addr(loadinfo, + loadinfo->shdr[i].sh_addr); loadinfo->ninit = loadinfo->shdr[i].sh_size / sizeof(uintptr_t); break; case SHT_FINI_ARRAY: - loadinfo->finiarr = loadinfo->shdr[i].sh_addr - - loadinfo->datasec + - loadinfo->datastart; + loadinfo->finiarr = libelf_addr(loadinfo, + loadinfo->shdr[i].sh_addr); loadinfo->nfini = loadinfo->shdr[i].sh_size / sizeof(uintptr_t); break; case SHT_PREINIT_ARRAY: - loadinfo->preiarr = loadinfo->shdr[i].sh_addr - - loadinfo->datasec + - loadinfo->datastart; + loadinfo->preiarr = libelf_addr(loadinfo, + loadinfo->shdr[i].sh_addr); loadinfo->nprei = loadinfo->shdr[i].sh_size / sizeof(uintptr_t); break; @@ -1085,6 +1075,7 @@ int libelf_bind(FAR struct module_s *modp, if (loadinfo->addrenv != NULL) { int status = libelf_addrenv_restore(loadinfo); + if (status < 0) { berr("ERROR: libelf_addrenv_restore() failed: %d\n", status);