diff --git a/binfmt/libelf/libelf_bind.c b/binfmt/libelf/libelf_bind.c index d046b7a7b35..da2dcd4ceac 100644 --- a/binfmt/libelf/libelf_bind.c +++ b/binfmt/libelf/libelf_bind.c @@ -195,42 +195,14 @@ static int elf_relocate(FAR struct elf_loadinfo_s *loadinfo, int relidx, addr = dstsec->sh_addr + rel.r_offset; - /* If CONFIG_ARCH_ADDRENV=y, then 'addr' lies in a virtual address space that - * may not be in place now. elf_addrenv_select() will temporarily - * instantiate that address space. - */ - -#ifdef CONFIG_ARCH_ADDRENV - ret = elf_addrenv_select(loadinfo); - if (ret < 0) - { - bdbg("ERROR: elf_addrenv_select() failed: %d\n", ret); - return ret; - } -#endif - /* Now perform the architecture-specific relocation */ ret = up_relocate(&rel, &sym, addr); if (ret < 0) { -#ifdef CONFIG_ARCH_ADDRENV - (void)elf_addrenv_restore(loadinfo); -#endif bdbg("ERROR: Section %d reloc %d: Relocation failed: %d\n", ret); return ret; } - - /* Restore the original address environment */ - -#ifdef CONFIG_ARCH_ADDRENV - ret = elf_addrenv_restore(loadinfo); - if (ret < 0) - { - bdbg("ERROR: elf_addrenv_restore() failed: %d\n", ret); - return ret; - } -#endif } return OK; @@ -263,6 +235,9 @@ static int elf_relocateadd(FAR struct elf_loadinfo_s *loadinfo, int relidx, int elf_bind(FAR struct elf_loadinfo_s *loadinfo, FAR const struct symtab_s *exports, int nexports) { +#ifdef CONFIG_ARCH_ADDRENV + int status; +#endif int ret; int i; @@ -285,6 +260,20 @@ int elf_bind(FAR struct elf_loadinfo_s *loadinfo, return -ENOMEM; } +#ifdef CONFIG_ARCH_ADDRENV + /* If CONFIG_ARCH_ADDRENV=y, then the loaded ELF lies in a virtual address + * space that may not be in place now. elf_addrenv_select() will + * temporarily instantiate that address space. + */ + + ret = elf_addrenv_select(loadinfo); + if (ret < 0) + { + bdbg("ERROR: elf_addrenv_select() failed: %d\n", ret); + return ret; + } +#endif + /* Process relocations in every allocated section */ for (i = 1; i < loadinfo->ehdr.e_shnum; i++) @@ -332,5 +321,19 @@ int elf_bind(FAR struct elf_loadinfo_s *loadinfo, up_coherent_dcache(loadinfo->textalloc, loadinfo->textsize); #endif +#ifdef CONFIG_ARCH_ADDRENV + /* Restore the original address environment */ + + status = elf_addrenv_restore(loadinfo); + if (status < 0) + { + bdbg("ERROR: elf_addrenv_restore() failed: %d\n", status); + if (ret == OK) + { + ret = status; + } + } +#endif + return ret; } diff --git a/binfmt/libelf/libelf_load.c b/binfmt/libelf/libelf_load.c index 81016a9085a..de3165606f5 100644 --- a/binfmt/libelf/libelf_load.c +++ b/binfmt/libelf/libelf_load.c @@ -132,9 +132,8 @@ static void elf_elfsize(struct elf_loadinfo_s *loadinfo) * Name: elf_loadfile * * Description: - * Allocate memory for the file and read the section data into the - * allocated memory. Section addresses in the shdr[] are updated to point - * to the corresponding position in the allocated memory. + * Read the section data into memory. Section addresses in the shdr[] are + * updated to point to the corresponding position in the memory. * * Returned Value: * 0 (OK) is returned on success and a negated errno is returned on @@ -150,15 +149,6 @@ static inline int elf_loadfile(FAR struct elf_loadinfo_s *loadinfo) int ret; int i; - /* Allocate (and zero) memory for the ELF file. */ - - ret = elf_addrenv_alloc(loadinfo, loadinfo->textsize, loadinfo->datasize); - if (ret < 0) - { - bdbg("ERROR: elf_addrenv_alloc() failed: %d\n", ret); - return ret; - } - /* Read each section into memory that is marked SHF_ALLOC + SHT_NOBITS */ bvdbg("Loaded sections:\n"); @@ -196,39 +186,14 @@ static inline int elf_loadfile(FAR struct elf_loadinfo_s *loadinfo) if (shdr->sh_type != SHT_NOBITS) { - /* If CONFIG_ARCH_ADDRENV=y, then 'text' lies in a virtual address - * space that may not be in place now. elf_addrenv_select() will - * temporarily instantiate that address space. - */ - -#ifdef CONFIG_ARCH_ADDRENV - ret = elf_addrenv_select(loadinfo); - if (ret < 0) - { - bdbg("ERROR: elf_addrenv_select() failed: %d\n", ret); - return ret; - } -#endif - /* Read the section data from sh_offset to the memory region */ ret = elf_read(loadinfo, *pptr, shdr->sh_size, shdr->sh_offset); if (ret < 0) { - bdbg("Failed to read section %d: %d\n", i, ret); + bdbg("ERROR: Failed to read section %d: %d\n", i, ret); return ret; } - - /* Restore the original address environment */ - -#ifdef CONFIG_ARCH_ADDRENV - ret = elf_addrenv_restore(loadinfo); - if (ret < 0) - { - bdbg("ERROR: elf_addrenv_restore() failed: %d\n", ret); - return ret; - } -#endif } /* Update sh_addr to point to copy in memory */ @@ -275,7 +240,7 @@ int elf_load(FAR struct elf_loadinfo_s *loadinfo) ret = elf_loadshdrs(loadinfo); if (ret < 0) { - bdbg("elf_loadshdrs failed: %d\n", ret); + bdbg("ERROR: elf_loadshdrs failed: %d\n", ret); goto errout_with_buffers; } @@ -283,13 +248,36 @@ int elf_load(FAR struct elf_loadinfo_s *loadinfo) elf_elfsize(loadinfo); - /* Allocate memory and load sections into memory */ + /* Allocate (and zero) memory for the ELF file. */ + + ret = elf_addrenv_alloc(loadinfo, loadinfo->textsize, loadinfo->datasize); + if (ret < 0) + { + bdbg("ERROR: elf_addrenv_alloc() failed: %d\n", ret); + goto errout_with_buffers; + } + +#ifdef CONFIG_ARCH_ADDRENV + /* If CONFIG_ARCH_ADDRENV=y, then the loaded ELF lies in a virtual address + * space that may not be in place now. elf_addrenv_select() will + * temporarily instantiate that address space. + */ + + ret = elf_addrenv_select(loadinfo); + if (ret < 0) + { + bdbg("ERROR: elf_addrenv_select() failed: %d\n", ret); + goto errout_with_buffers; + } +#endif + + /* Load ELF section data into memory */ ret = elf_loadfile(loadinfo); if (ret < 0) { - bdbg("elf_loadfile failed: %d\n", ret); - goto errout_with_buffers; + bdbg("ERROR: elf_loadfile failed: %d\n", ret); + goto errout_with_addrenv; } /* Load static constructors and destructors. */ @@ -298,14 +286,25 @@ int elf_load(FAR struct elf_loadinfo_s *loadinfo) ret = elf_loadctors(loadinfo); if (ret < 0) { - bdbg("elf_loadctors failed: %d\n", ret); - goto errout_with_buffers; + bdbg("ERROR: elf_loadctors failed: %d\n", ret); + goto errout_with_addrenv; } ret = elf_loaddtors(loadinfo); if (ret < 0) { - bdbg("elf_loaddtors failed: %d\n", ret); + bdbg("ERROR: elf_loaddtors failed: %d\n", ret); + goto errout_with_addrenv; + } +#endif + +#ifdef CONFIG_ARCH_ADDRENV + /* Restore the original address environment */ + + ret = elf_addrenv_restore(loadinfo); + if (ret < 0) + { + bdbg("ERROR: elf_addrenv_restore() failed: %d\n", ret); goto errout_with_buffers; } #endif @@ -314,6 +313,11 @@ int elf_load(FAR struct elf_loadinfo_s *loadinfo) /* Error exits */ +errout_with_addrenv: +#ifdef CONFIG_ARCH_ADDRENV + (void)elf_addrenv_restore(loadinfo); +#endif + errout_with_buffers: elf_unload(loadinfo); return ret;