From 913f876fac94f21a683809d9f648e4793f61e237 Mon Sep 17 00:00:00 2001 From: patacongo Date: Wed, 19 Dec 2012 17:54:26 +0000 Subject: Incorporate address environment interfaces in binfmt/ logic git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@5443 42af7a65-404d-4744-a932-0658087f49c3 --- nuttx/binfmt/libelf/Make.defs | 6 +- nuttx/binfmt/libelf/libelf.h | 85 ++++++++++++++++- nuttx/binfmt/libelf/libelf_addrenv.c | 176 +++++++++++++++++++++++++++++++++++ nuttx/binfmt/libelf/libelf_bind.c | 36 ++++++- nuttx/binfmt/libelf/libelf_load.c | 35 ++++++- nuttx/binfmt/libelf/libelf_read.c | 6 +- nuttx/binfmt/libelf/libelf_unload.c | 13 +-- 7 files changed, 334 insertions(+), 23 deletions(-) create mode 100644 nuttx/binfmt/libelf/libelf_addrenv.c (limited to 'nuttx/binfmt/libelf') diff --git a/nuttx/binfmt/libelf/Make.defs b/nuttx/binfmt/libelf/Make.defs index c8857c3f7..93d95a23c 100644 --- a/nuttx/binfmt/libelf/Make.defs +++ b/nuttx/binfmt/libelf/Make.defs @@ -41,9 +41,9 @@ BINFMT_CSRCS += elf.c # ELF library -BINFMT_CSRCS += libelf_bind.c libelf_init.c libelf_iobuffer.c libelf_load.c \ - libelf_read.c libelf_sections.c libelf_symbols.c libelf_uninit.c \ - libelf_unload.c libelf_verify.c +BINFMT_CSRCS += libelf_bind.c libelf_init.c libelf_addrenv.c libelf_iobuffer.c +BINFMT_CSRCS += libelf_load.c libelf_read.c libelf_sections.c libelf_symbols.c +BINFMT_CSRCS += libelf_uninit.c libelf_unload.c libelf_verify.c ifeq ($(CONFIG_BINFMT_CONSTRUCTORS),y) BINFMT_CSRCS += libelf_ctors.c libelf_dtors.c diff --git a/nuttx/binfmt/libelf/libelf.h b/nuttx/binfmt/libelf/libelf.h index 5b0be9ab0..04c9144f6 100644 --- a/nuttx/binfmt/libelf/libelf.h +++ b/nuttx/binfmt/libelf/libelf.h @@ -45,6 +45,7 @@ #include #include +#include #include /**************************************************************************** @@ -74,7 +75,11 @@ int elf_verifyheader(FAR const Elf32_Ehdr *header); * Name: elf_read * * Description: - * Read 'readsize' bytes from the object file at 'offset' + * Read 'readsize' bytes from the object file at 'offset'. The data is + * read into 'buffer.' If 'buffer' is part of the ELF address environment, + * then the caller is responsibile for assuring that that address + * environment is in place before calling this function (i.e., that + * elf_addrenv_select() has been called if CONFIG_ADDRENV=y). * * Returned Value: * 0 (OK) is returned on success and a negated errno is returned on @@ -255,4 +260,82 @@ int elf_loadctors(FAR struct elf_loadinfo_s *loadinfo); int elf_loaddtors(FAR struct elf_loadinfo_s *loadinfo); #endif +/**************************************************************************** + * Name: elf_addrenv_alloc + * + * Description: + * Allocate memory for the ELF image (elfalloc). If CONFIG_ADDRENV=n, + * elfalloc will be allocated using kzalloc(). If CONFIG_ADDRENV-y, then + * elfalloc will be allocated using up_addrenv_create(). In either case, + * there will be a unique instance of elfalloc (and stack) for each + * instance of a process. + * + * Input Parameters: + * loadinfo - Load state information + * envsize - The size (in bytes) of the address environment needed for the + * ELF image. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int elf_addrenv_alloc(FAR struct elf_loadinfo_s *loadinfo, size_t envsize); + +/**************************************************************************** + * Name: elf_addrenv_select + * + * Description: + * Temporarity select the task's address environemnt. + * + * Input Parameters: + * loadinfo - Load state information + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +#ifdef CONFIG_ADDRENV +# define elf_addrenv_select(l) up_addrenv_select((l)->addrenv, &(l)->oldenv) +#endif + +/**************************************************************************** + * Name: elf_addrenv_restore + * + * Description: + * Restore the address environment before elf_addrenv_select() was called.. + * + * Input Parameters: + * loadinfo - Load state information + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +#ifdef CONFIG_ADDRENV +# define elf_addrenv_restore(l) up_addrenv_restore((l)->oldenv) +#endif + +/**************************************************************************** + * Name: elf_addrenv_free + * + * Description: + * Release the address environment previously created by + * elf_addrenv_alloc(). This function is called only under certain error + * conditions after the the module has been loaded but not yet started. + * After the module has been started, the address environment will + * automatically be freed when the module exits. + * + * Input Parameters: + * loadinfo - Load state information + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void elf_addrenv_free(FAR struct elf_loadinfo_s *loadinfo); + #endif /* __BINFMT_LIBELF_LIBELF_H */ diff --git a/nuttx/binfmt/libelf/libelf_addrenv.c b/nuttx/binfmt/libelf/libelf_addrenv.c new file mode 100644 index 000000000..28cc0e108 --- /dev/null +++ b/nuttx/binfmt/libelf/libelf_addrenv.c @@ -0,0 +1,176 @@ +/**************************************************************************** + * binfmt/libelf/libelf_addrenv.c + * + * Copyright (C) 2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include +#include + +#include "libelf.h" + +/**************************************************************************** + * Pre-Processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Constant Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: elf_addrenv_create + * + * Description: + * Allocate memory for the ELF image (elfalloc). If CONFIG_ADDRENV=n, + * elfalloc will be allocated using kzalloc(). If CONFIG_ADDRENV-y, then + * elfalloc will be allocated using up_addrenv_create(). In either case, + * there will be a unique instance of elfalloc (and stack) for each + * instance of a process. + * + * Input Parameters: + * loadinfo - Load state information + * envsize - The size (in bytes) of the address environment needed for the + * ELF image. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int elf_addrenv_create(FAR struct elf_loadinfo_s *loadinfo, size_t envsize) +{ +#ifdef CONFIG_ADDRENV + FAR void *vaddr; + int ret; + + /* Create an address environment for the new ELF task */ + + ret = up_addrenv_create(envsize, &loadinfo->addrenv); + if (ret < 0) + { + bdbg("ERROR: up_addrenv_create failed: %d\n", ret); + return ret; + } + + /* Get the virtual address associated with the start of the address + * environment. This is the base address that we will need to use to + * access the ELF image (but only if the address environment has been + * selected. + */ + + ret = up_addrenv_vaddr(loadinfo->addrenv, &vaddr); + if (ret < 0) + { + bdbg("ERROR: up_addrenv_vaddr failed: %d\n", ret); + return ret; + } + + loadinfo->elfalloc = (uintptr_t)vaddr; + return OK; +#else + /* Allocate memory to hold the ELF image */ + + loadinfo->elfalloc = (uintptr_t)kzalloc(envsize); + if (!loadinfo->elfalloc) + { + return -ENOMEM; + } + + return OK; +#endif +} + +/**************************************************************************** + * Name: elf_addrenv_free + * + * Description: + * Release the address environment previously created by + * elf_addrenv_create(). This function is called only under certain error + * conditions after the the module has been loaded but not yet started. + * After the module has been started, the address environment will + * automatically be freed when the module exits. + * + * Input Parameters: + * loadinfo - Load state information + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void elf_addrenv_free(FAR struct elf_loadinfo_s *loadinfo) +{ +#ifdef CONFIG_ADDRENV + int ret; + + /* Free the address environemnt */ + + ret = up_addrenv_destroy(loadinfo->addrenv); + if (ret < 0) + { + bdbg("ERROR: up_addrenv_destroy failed: %d\n", ret); + } + + /* Clear out all indications of the allocated address environment */ + + loadinfo->elfalloc = 0; + loadinfo->elfsize = 0; + loadinfo->addrenv = 0; +#else + /* If there is an allocation for the ELF image, free it */ + + if (loadinfo->elfalloc != 0) + { + kfree((FAR void *)loadinfo->elfalloc); + loadinfo->elfalloc = 0; + } + + loadinfo->elfsize = 0; +#endif +} diff --git a/nuttx/binfmt/libelf/libelf_bind.c b/nuttx/binfmt/libelf/libelf_bind.c index e35087b1d..ccdb5108e 100644 --- a/nuttx/binfmt/libelf/libelf_bind.c +++ b/nuttx/binfmt/libelf/libelf_bind.c @@ -86,10 +86,10 @@ ****************************************************************************/ /**************************************************************************** - * Name: elf_readsym + * Name: elf_readrel * * Description: - * Read the ELFT symbol structure at the specfied index into memory. + * Read the ELF32_Rel structure into memory. * ****************************************************************************/ @@ -184,7 +184,7 @@ static int elf_relocate(FAR struct elf_loadinfo_s *loadinfo, int relidx, return ret; } - /* Calculate the relocation address */ + /* Calculate the relocation address. */ if (rel.r_offset < 0 || rel.r_offset > dstsec->sh_size - sizeof(uint32_t)) { @@ -195,14 +195,42 @@ static int elf_relocate(FAR struct elf_loadinfo_s *loadinfo, int relidx, addr = dstsec->sh_addr + rel.r_offset; + /* If CONFIG_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_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 = arch_relocate(&rel, &sym, addr); if (ret < 0) { - bdbg("Section %d reloc %d: Relocation failed: %d\n", ret); +#ifdef CONFIG_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_ADDRENV + ret = elf_addrenv_restore(loadinfo); + if (ret < 0) + { + bdbg("ERROR: elf_addrenv_restore() failed: %d\n", ret); return ret; } +#endif } return OK; diff --git a/nuttx/binfmt/libelf/libelf_load.c b/nuttx/binfmt/libelf/libelf_load.c index b1ac44e21..0e4ad9798 100644 --- a/nuttx/binfmt/libelf/libelf_load.c +++ b/nuttx/binfmt/libelf/libelf_load.c @@ -49,7 +49,6 @@ #include #include -#include #include #include "libelf.h" @@ -135,11 +134,12 @@ static inline int elf_loadfile(FAR struct elf_loadinfo_s *loadinfo) int i; /* Allocate (and zero) memory for the ELF file. */ - - loadinfo->elfalloc = (uintptr_t)kzalloc(loadinfo->elfsize); - if (!loadinfo->elfalloc) + + ret = elf_addrenv_alloc(loadinfo, loadinfo->elfsize); + if (ret < 0) { - return -ENOMEM; + bdbg("ERROR: elf_addrenv_alloc() failed: %d\n", ret); + return ret; } /* Read each section into memory that is marked SHF_ALLOC + SHT_NOBITS */ @@ -165,6 +165,20 @@ static inline int elf_loadfile(FAR struct elf_loadinfo_s *loadinfo) if (shdr->sh_type != SHT_NOBITS) { + /* If CONFIG_ADDRENV=y, then 'dest' lies in a virtual address space + * that may not be in place now. elf_addrenv_select() will + * temporarily instantiate that address space. + */ + +#ifdef CONFIG_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 dest */ ret = elf_read(loadinfo, dest, shdr->sh_size, shdr->sh_offset); @@ -173,6 +187,17 @@ static inline int elf_loadfile(FAR struct elf_loadinfo_s *loadinfo) bdbg("Failed to read section %d: %d\n", i, ret); return ret; } + + /* Restore the original address environment */ + +#ifdef CONFIG_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 */ diff --git a/nuttx/binfmt/libelf/libelf_read.c b/nuttx/binfmt/libelf/libelf_read.c index da41212f2..f4b725183 100644 --- a/nuttx/binfmt/libelf/libelf_read.c +++ b/nuttx/binfmt/libelf/libelf_read.c @@ -98,7 +98,11 @@ static inline void elf_dumpreaddata(char *buffer, int buflen) * Name: elf_read * * Description: - * Read 'readsize' bytes from the object file at 'offset' + * Read 'readsize' bytes from the object file at 'offset'. The data is + * read into 'buffer.' If 'buffer' is part of the ELF address environment, + * then the caller is responsibile for assuring that that address + * environment is in place before calling this function (i.e., that + * elf_addrenv_select() has been called if CONFIG_ADDRENV=y). * * Returned Value: * 0 (OK) is returned on success and a negated errno is returned on diff --git a/nuttx/binfmt/libelf/libelf_unload.c b/nuttx/binfmt/libelf/libelf_unload.c index 532fc606f..539e5faf7 100644 --- a/nuttx/binfmt/libelf/libelf_unload.c +++ b/nuttx/binfmt/libelf/libelf_unload.c @@ -67,8 +67,9 @@ * Name: elf_unload * * Description: - * This function unloads the object from memory. This essentially - * undoes the actions of elf_load. + * This function unloads the object from memory. This essentially undoes + * the actions of elf_load. It is called only under certain error + * conditions after the the module has been loaded but not yet started. * * Returned Value: * 0 (OK) is returned on success and a negated errno is returned on @@ -84,13 +85,7 @@ int elf_unload(struct elf_loadinfo_s *loadinfo) /* Release memory holding the relocated ELF image */ - if (loadinfo->elfalloc != 0) - { - kfree((FAR void *)loadinfo->elfalloc); - loadinfo->elfalloc = 0; - } - - loadinfo->elfsize = 0; + elf_addrenv_free(loadinfo); /* Release memory used to hold static constructors and destructors */ -- cgit v1.2.3