diff options
Diffstat (limited to 'nuttx/binfmt/libelf')
-rw-r--r-- | nuttx/binfmt/libelf/Make.defs | 58 | ||||
-rw-r--r-- | nuttx/binfmt/libelf/libelf.h | 341 | ||||
-rw-r--r-- | nuttx/binfmt/libelf/libelf_addrenv.c | 176 | ||||
-rw-r--r-- | nuttx/binfmt/libelf/libelf_bind.c | 334 | ||||
-rw-r--r-- | nuttx/binfmt/libelf/libelf_load.c | 288 | ||||
-rw-r--r-- | nuttx/binfmt/libelf/libelf_read.c | 165 | ||||
-rw-r--r-- | nuttx/binfmt/libelf/libelf_unload.c | 114 |
7 files changed, 1476 insertions, 0 deletions
diff --git a/nuttx/binfmt/libelf/Make.defs b/nuttx/binfmt/libelf/Make.defs new file mode 100644 index 000000000..93d95a23c --- /dev/null +++ b/nuttx/binfmt/libelf/Make.defs @@ -0,0 +1,58 @@ +############################################################################ +# binfmt/libelf/Make.defs +# +# Copyright (C) 2012 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <gnutt@nuttx.org> +# +# 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. +# +############################################################################ + +ifeq ($(CONFIG_ELF),y) + +# ELF application interfaces + +BINFMT_CSRCS += elf.c + +# ELF library + +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 +endif + +# Hook the libelf subdirectory into the build + +VPATH += libelf +SUBDIRS += libelf +DEPPATH += --dep-path libelf + +endif diff --git a/nuttx/binfmt/libelf/libelf.h b/nuttx/binfmt/libelf/libelf.h new file mode 100644 index 000000000..04c9144f6 --- /dev/null +++ b/nuttx/binfmt/libelf/libelf.h @@ -0,0 +1,341 @@ +/**************************************************************************** + * binfmt/libelf/libelf.h + * + * Copyright (C) 2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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. + * + ****************************************************************************/ + +#ifndef __BINFMT_LIBELF_LIBELF_H +#define __BINFMT_LIBELF_LIBELF_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> +#include <elf32.h> + +#include <nuttx/arch.h> +#include <nuttx/binfmt/elf.h> + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Name: elf_verifyheader + * + * Description: + * Given the header from a possible ELF executable, verify that it is + * an ELF executable. + * + * Returned Value: + * 0 (OK) is returned on success and a negated errno is returned on + * failure. + * + ****************************************************************************/ + +int elf_verifyheader(FAR const Elf32_Ehdr *header); + +/**************************************************************************** + * Name: elf_read + * + * Description: + * 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 + * failure. + * + ****************************************************************************/ + +int elf_read(FAR struct elf_loadinfo_s *loadinfo, FAR uint8_t *buffer, + size_t readsize, off_t offset); + +/**************************************************************************** + * Name: elf_loadshdrs + * + * Description: + * Loads section headers into memory. + * + * Returned Value: + * 0 (OK) is returned on success and a negated errno is returned on + * failure. + * + ****************************************************************************/ + +int elf_loadshdrs(FAR struct elf_loadinfo_s *loadinfo); + +/**************************************************************************** + * Name: elf_findsection + * + * Description: + * A section by its name. + * + * Input Parameters: + * loadinfo - Load state information + * sectname - Name of the section to find + * + * Returned Value: + * On success, the index to the section is returned; A negated errno value + * is returned on failure. + * + ****************************************************************************/ + +int elf_findsection(FAR struct elf_loadinfo_s *loadinfo, + FAR const char *sectname); + +/**************************************************************************** + * Name: elf_findsymtab + * + * Description: + * Find the symbol table section. + * + * Returned Value: + * 0 (OK) is returned on success and a negated errno is returned on + * failure. + * + ****************************************************************************/ + +int elf_findsymtab(FAR struct elf_loadinfo_s *loadinfo); + +/**************************************************************************** + * Name: elf_readsym + * + * Description: + * Read the ELFT symbol structure at the specfied index into memory. + * + * Input Parameters: + * loadinfo - Load state information + * index - Symbol table index + * sym - Location to return the table entry + * + * Returned Value: + * 0 (OK) is returned on success and a negated errno is returned on + * failure. + * + ****************************************************************************/ + +int elf_readsym(FAR struct elf_loadinfo_s *loadinfo, int index, + FAR Elf32_Sym *sym); + +/**************************************************************************** + * Name: elf_symvalue + * + * Description: + * Get the value of a symbol. The updated value of the symbol is returned + * in the st_value field of the symbol table entry. + * + * Input Parameters: + * loadinfo - Load state information + * sym - Symbol table entry (value might be undefined) + * exports - The symbol table to use for resolving undefined symbols. + * nexports - Number of symbols in the symbol table. + * + * Returned Value: + * 0 (OK) is returned on success and a negated errno is returned on + * failure. + * + ****************************************************************************/ + +int elf_symvalue(FAR struct elf_loadinfo_s *loadinfo, FAR Elf32_Sym *sym, + FAR const struct symtab_s *exports, int nexports); + +/**************************************************************************** + * Name: elf_freebuffers + * + * Description: + * Release all working buffers. + * + * Returned Value: + * 0 (OK) is returned on success and a negated errno is returned on + * failure. + * + ****************************************************************************/ + +int elf_freebuffers(FAR struct elf_loadinfo_s *loadinfo); + +/**************************************************************************** + * Name: elf_allocbuffer + * + * Description: + * Perform the initial allocation of the I/O buffer, if it has not already + * been allocated. + * + * Returned Value: + * 0 (OK) is returned on success and a negated errno is returned on + * failure. + * + ****************************************************************************/ + +int elf_allocbuffer(FAR struct elf_loadinfo_s *loadinfo); + +/**************************************************************************** + * Name: elf_reallocbuffer + * + * Description: + * Increase the size of I/O buffer by the specified buffer increment. + * + * Returned Value: + * 0 (OK) is returned on success and a negated errno is returned on + * failure. + * + ****************************************************************************/ + +int elf_reallocbuffer(FAR struct elf_loadinfo_s *loadinfo, size_t increment); + +/**************************************************************************** + * Name: elf_findctors + * + * Description: + * Find C++ static constructors. + * + * Input Parameters: + * loadinfo - Load state information + * + * Returned Value: + * 0 (OK) is returned on success and a negated errno is returned on + * failure. + * + ****************************************************************************/ + +#ifdef CONFIG_BINFMT_CONSTRUCTORS +int elf_loadctors(FAR struct elf_loadinfo_s *loadinfo); +#endif + +/**************************************************************************** + * Name: elf_loaddtors + * + * Description: + * Load pointers to static destructors into an in-memory array. + * + * Input Parameters: + * loadinfo - Load state information + * + * Returned Value: + * 0 (OK) is returned on success and a negated errno is returned on + * failure. + * + ****************************************************************************/ + +#ifdef CONFIG_BINFMT_CONSTRUCTORS +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..193062a54 --- /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 <gnutt@nuttx.org> + * + * 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 <nuttx/config.h> + +#include <errno.h> +#include <debug.h> + +#include <nuttx/arch.h> +#include <nuttx/kmalloc.h> + +#include "libelf.h" + +/**************************************************************************** + * Pre-Processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Constant Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * 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) +{ +#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 new file mode 100644 index 000000000..ccdb5108e --- /dev/null +++ b/nuttx/binfmt/libelf/libelf_bind.c @@ -0,0 +1,334 @@ +/**************************************************************************** + * binfmt/libelf/libelf_bind.c + * + * Copyright (C) 2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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 <nuttx/config.h> + +#include <stdint.h> +#include <string.h> +#include <elf32.h> +#include <errno.h> +#include <assert.h> +#include <debug.h> + +#include <nuttx/binfmt/elf.h> +#include <nuttx/binfmt/symtab.h> + +#include "libelf.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* CONFIG_DEBUG, CONFIG_DEBUG_VERBOSE, and CONFIG_DEBUG_BINFMT have to be + * defined or CONFIG_ELF_DUMPBUFFER does nothing. + */ + +#if !defined(CONFIG_DEBUG_VERBOSE) || !defined (CONFIG_DEBUG_BINFMT) +# undef CONFIG_ELF_DUMPBUFFER +#endif + +#ifndef CONFIG_ELF_BUFFERSIZE +# define CONFIG_ELF_BUFFERSIZE 128 +#endif + +#ifdef CONFIG_ELF_DUMPBUFFER +# define elf_dumpbuffer(m,b,n) bvdbgdumpbuffer(m,b,n) +#else +# define elf_dumpbuffer(m,b,n) +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: elf_readrel + * + * Description: + * Read the ELF32_Rel structure into memory. + * + ****************************************************************************/ + +static inline int elf_readrel(FAR struct elf_loadinfo_s *loadinfo, + FAR const Elf32_Shdr *relsec, + int index, FAR Elf32_Rel *rel) +{ + off_t offset; + + /* Verify that the symbol table index lies within symbol table */ + + if (index < 0 || index > (relsec->sh_size / sizeof(Elf32_Rel))) + { + bdbg("Bad relocation symbol index: %d\n", index); + return -EINVAL; + } + + /* Get the file offset to the symbol table entry */ + + offset = relsec->sh_offset + sizeof(Elf32_Rel) * index; + + /* And, finally, read the symbol table entry into memory */ + + return elf_read(loadinfo, (FAR uint8_t*)rel, sizeof(Elf32_Rel), offset); +} + +/**************************************************************************** + * Name: elf_relocate and elf_relocateadd + * + * Description: + * Perform all relocations associated with a section. + * + * Returned Value: + * 0 (OK) is returned on success and a negated errno is returned on + * failure. + * + ****************************************************************************/ + +static int elf_relocate(FAR struct elf_loadinfo_s *loadinfo, int relidx, + FAR const struct symtab_s *exports, int nexports) + +{ + FAR Elf32_Shdr *relsec = &loadinfo->shdr[relidx]; + FAR Elf32_Shdr *dstsec = &loadinfo->shdr[relsec->sh_info]; + Elf32_Rel rel; + Elf32_Sym sym; + uintptr_t addr; + int symidx; + int ret; + int i; + + /* Examine each relocation in the section. 'relsec' is the section + * containing the relations. 'dstsec' is the section containing the data + * to be relocated. + */ + + for (i = 0; i < relsec->sh_size / sizeof(Elf32_Rel); i++) + { + /* Read the relocation entry into memory */ + + ret = elf_readrel(loadinfo, relsec, i, &rel); + if (ret < 0) + { + bdbg("Section %d reloc %d: Failed to read relocation entry: %d\n", + relidx, i, ret); + return ret; + } + + /* Get the symbol table index for the relocation. This is contained + * in a bit-field within the r_info element. + */ + + symidx = ELF32_R_SYM(rel.r_info); + + /* Read the symbol table entry into memory */ + + ret = elf_readsym(loadinfo, symidx, &sym); + if (ret < 0) + { + bdbg("Section %d reloc %d: Failed to read symbol[%d]: %d\n", + relidx, i, symidx, ret); + return ret; + } + + /* Get the value of the symbol (in sym.st_value) */ + + ret = elf_symvalue(loadinfo, &sym, exports, nexports); + if (ret < 0) + { + bdbg("Section %d reloc %d: Failed to get value of symbol[%d]: %d\n", + relidx, i, symidx, ret); + return ret; + } + + /* Calculate the relocation address. */ + + if (rel.r_offset < 0 || rel.r_offset > dstsec->sh_size - sizeof(uint32_t)) + { + bdbg("Section %d reloc %d: Relocation address out of range, offset %d size %d\n", + relidx, i, rel.r_offset, dstsec->sh_size); + return -EINVAL; + } + + 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) + { +#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; +} + +static int elf_relocateadd(FAR struct elf_loadinfo_s *loadinfo, int relidx, + FAR const struct symtab_s *exports, int nexports) +{ + bdbg("Not implemented\n"); + return -ENOSYS; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: elf_bind + * + * Description: + * Bind the imported symbol names in the loaded module described by + * 'loadinfo' using the exported symbol values provided by 'symtab'. + * + * Returned Value: + * 0 (OK) is returned on success and a negated errno is returned on + * failure. + * + ****************************************************************************/ + +int elf_bind(FAR struct elf_loadinfo_s *loadinfo, + FAR const struct symtab_s *exports, int nexports) +{ + int ret; + int i; + + /* Find the symbol and string tables */ + + ret = elf_findsymtab(loadinfo); + if (ret < 0) + { + return ret; + } + + /* Allocate an I/O buffer. This buffer is used by elf_symname() to + * accumulate the variable length symbol name. + */ + + ret = elf_allocbuffer(loadinfo); + if (ret < 0) + { + bdbg("elf_allocbuffer failed: %d\n", ret); + return -ENOMEM; + } + + /* Process relocations in every allocated section */ + + for (i = 1; i < loadinfo->ehdr.e_shnum; i++) + { + /* Get the index to the relocation section */ + + int infosec = loadinfo->shdr[i].sh_info; + if (infosec >= loadinfo->ehdr.e_shnum) + { + continue; + } + + /* Make sure that the section is allocated. We can't relocated + * sections that were not loaded into memory. + */ + + if ((loadinfo->shdr[infosec].sh_flags & SHF_ALLOC) == 0) + { + continue; + } + + /* Process the relocations by type */ + + if (loadinfo->shdr[i].sh_type == SHT_REL) + { + ret = elf_relocate(loadinfo, i, exports, nexports); + } + else if (loadinfo->shdr[i].sh_type == SHT_RELA) + { + ret = elf_relocateadd(loadinfo, i, exports, nexports); + } + + if (ret < 0) + { + break; + } + } + + /* Flush the instruction cache before starting the newly loaded module */ + +#ifdef CONFIG_ELF_ICACHE + arch_flushicache((FAR void*)loadinfo->elfalloc, loadinfo->elfsize); +#endif + + return ret; +} + diff --git a/nuttx/binfmt/libelf/libelf_load.c b/nuttx/binfmt/libelf/libelf_load.c new file mode 100644 index 000000000..0e4ad9798 --- /dev/null +++ b/nuttx/binfmt/libelf/libelf_load.c @@ -0,0 +1,288 @@ +/**************************************************************************** + * binfmt/libelf/libelf_load.c + * + * Copyright (C) 2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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 <nuttx/config.h> + +#include <sys/types.h> + +#include <stdint.h> +#include <stdlib.h> +#include <unistd.h> +#include <elf32.h> +#include <assert.h> +#include <errno.h> +#include <debug.h> + +#include <nuttx/binfmt/elf.h> + +#include "libelf.h" + +/**************************************************************************** + * Pre-Processor Definitions + ****************************************************************************/ + +#define ELF_ALIGN_MASK ((1 << CONFIG_ELF_ALIGN_LOG2) - 1) +#define ELF_ALIGNUP(a) (((unsigned long)(a) + ELF_ALIGN_MASK) & ~ELF_ALIGN_MASK) +#define ELF_ALIGNDOWN(a) ((unsigned long)(a) & ~ELF_ALIGN_MASK) + + +#ifndef MAX +#define MAX(x,y) ((x) > (y) ? (x) : (y)) +#endif + +/**************************************************************************** + * Private Constant Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: elf_elfsize + * + * Description: + * Calculate total memory allocation for the ELF file. + * + * Returned Value: + * 0 (OK) is returned on success and a negated errno is returned on + * failure. + * + ****************************************************************************/ + +static void elf_elfsize(struct elf_loadinfo_s *loadinfo) +{ + size_t elfsize; + int i; + + /* Accumulate the size each section into memory that is marked SHF_ALLOC */ + + elfsize = 0; + for (i = 0; i < loadinfo->ehdr.e_shnum; i++) + { + FAR Elf32_Shdr *shdr = &loadinfo->shdr[i]; + + /* SHF_ALLOC indicates that the section requires memory during + * execution. + */ + + if ((shdr->sh_flags & SHF_ALLOC) != 0) + { + elfsize += ELF_ALIGNUP(shdr->sh_size); + } + } + + /* Save the allocation size */ + + loadinfo->elfsize = elfsize; +} + +/**************************************************************************** + * 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. + * + * Returned Value: + * 0 (OK) is returned on success and a negated errno is returned on + * failure. + * + ****************************************************************************/ + +static inline int elf_loadfile(FAR struct elf_loadinfo_s *loadinfo) +{ + FAR uint8_t *dest; + int ret; + int i; + + /* Allocate (and zero) memory for the ELF file. */ + + ret = elf_addrenv_alloc(loadinfo, loadinfo->elfsize); + 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"); + dest = (FAR uint8_t*)loadinfo->elfalloc; + + for (i = 0; i < loadinfo->ehdr.e_shnum; i++) + { + FAR Elf32_Shdr *shdr = &loadinfo->shdr[i]; + + /* SHF_ALLOC indicates that the section requires memory during + * execution */ + + if ((shdr->sh_flags & SHF_ALLOC) == 0) + { + continue; + } + + /* SHT_NOBITS indicates that there is no data in the file for the + * section. + */ + + 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); + if (ret < 0) + { + 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 */ + + bvdbg("%d. %08x->%08x\n", i, (long)shdr->sh_addr, (long)dest); + shdr->sh_addr = (uintptr_t)dest; + + /* Setup the memory pointer for the next time through the loop */ + + dest += ELF_ALIGNUP(shdr->sh_size); + } + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: elf_load + * + * Description: + * Loads the binary into memory, allocating memory, performing relocations + * and inializing the data and bss segments. + * + * Returned Value: + * 0 (OK) is returned on success and a negated errno is returned on + * failure. + * + ****************************************************************************/ + +int elf_load(FAR struct elf_loadinfo_s *loadinfo) +{ + int ret; + + bvdbg("loadinfo: %p\n", loadinfo); + DEBUGASSERT(loadinfo && loadinfo->filfd >= 0); + + /* Load section headers into memory */ + + ret = elf_loadshdrs(loadinfo); + if (ret < 0) + { + bdbg("elf_loadshdrs failed: %d\n", ret); + goto errout_with_buffers; + } + + /* Determine total size to allocate */ + + elf_elfsize(loadinfo); + + /* Allocate memory and load sections into memory */ + + ret = elf_loadfile(loadinfo); + if (ret < 0) + { + bdbg("elf_loadfile failed: %d\n", ret); + goto errout_with_buffers; + } + + /* Load static constructors and destructors. */ + +#ifdef CONFIG_BINFMT_CONSTRUCTORS + ret = elf_loadctors(loadinfo); + if (ret < 0) + { + bdbg("elf_loadctors failed: %d\n", ret); + goto errout_with_buffers; + } + + ret = elf_loaddtors(loadinfo); + if (ret < 0) + { + bdbg("elf_loaddtors failed: %d\n", ret); + goto errout_with_buffers; + } +#endif + + return OK; + + /* Error exits */ + +errout_with_buffers: + elf_unload(loadinfo); + return ret; +} + diff --git a/nuttx/binfmt/libelf/libelf_read.c b/nuttx/binfmt/libelf/libelf_read.c new file mode 100644 index 000000000..f4b725183 --- /dev/null +++ b/nuttx/binfmt/libelf/libelf_read.c @@ -0,0 +1,165 @@ +/**************************************************************************** + * binfmt/libelf/libelf_read.c + * + * Copyright (C) 2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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 <nuttx/config.h> + +#include <sys/types.h> +#include <stdint.h> +#include <unistd.h> +#include <string.h> +#include <elf32.h> +#include <debug.h> +#include <errno.h> + +#include <nuttx/binfmt/elf.h> + +/**************************************************************************** + * Pre-Processor Definitions + ****************************************************************************/ + +#undef ELF_DUMP_READDATA /* Define to dump all file data read */ +#define DUMPER lib_rawprintf /* If ELF_DUMP_READDATA is defined, this + * is the API used to dump data */ + +/**************************************************************************** + * Private Constant Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: elf_dumpreaddata + ****************************************************************************/ + +#if defined(ELF_DUMP_READDATA) +static inline void elf_dumpreaddata(char *buffer, int buflen) +{ + uint32_t *buf32 = (uint32_t*)buffer; + int i; + int j; + + for (i = 0; i < buflen; i += 32) + { + DUMPER("%04x:", i); + for (j = 0; j < 32; j += sizeof(uint32_t)) + { + DUMPER(" %08x", *buf32++); + } + DUMPER("\n"); + } +} +#else +# define elf_dumpreaddata(b,n) +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: elf_read + * + * Description: + * 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 + * failure. + * + ****************************************************************************/ + +int elf_read(FAR struct elf_loadinfo_s *loadinfo, FAR uint8_t *buffer, + size_t readsize, off_t offset) +{ + ssize_t nbytes; /* Number of bytes read */ + off_t rpos; /* Position returned by lseek */ + + bvdbg("Read %ld bytes from offset %ld\n", (long)readsize, (long)offset); + + /* Loop until all of the requested data has been read. */ + + while (readsize > 0) + { + /* Seek to the next read position */ + + rpos = lseek(loadinfo->filfd, offset, SEEK_SET); + if (rpos != offset) + { + int errval = errno; + bdbg("Failed to seek to position %ld: %d\n", (long)offset, errval); + return -errval; + } + + /* Read the file data at offset into the user buffer */ + + nbytes = read(loadinfo->filfd, buffer, readsize); + if (nbytes < 0) + { + int errval = errno; + + /* EINTR just means that we received a signal */ + + if (errval != EINTR) + { + bdbg("Read of .data failed: %d\n", errval); + return -errval; + } + } + else if (nbytes == 0) + { + bdbg("Unexpected end of file\n"); + return -ENODATA; + } + else + { + readsize -= nbytes; + buffer += nbytes; + offset += nbytes; + } + } + + elf_dumpreaddata(buffer, readsize); + return OK; +} diff --git a/nuttx/binfmt/libelf/libelf_unload.c b/nuttx/binfmt/libelf/libelf_unload.c new file mode 100644 index 000000000..539e5faf7 --- /dev/null +++ b/nuttx/binfmt/libelf/libelf_unload.c @@ -0,0 +1,114 @@ +/**************************************************************************** + * binfmt/libelf/libelf_unload.c + * + * Copyright (C) 2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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 <nuttx/config.h> + +#include <stdlib.h> +#include <debug.h> + +#include <nuttx/kmalloc.h> +#include <nuttx/binfmt/elf.h> + +#include "libelf.h" + +/**************************************************************************** + * Pre-Processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Constant Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: elf_unload + * + * Description: + * 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 + * failure. + * + ****************************************************************************/ + +int elf_unload(struct elf_loadinfo_s *loadinfo) +{ + /* Free all working buffers */ + + elf_freebuffers(loadinfo); + + /* Release memory holding the relocated ELF image */ + + elf_addrenv_free(loadinfo); + + /* Release memory used to hold static constructors and destructors */ + +#ifdef CONFIG_BINFMT_CONSTRUCTORS + if (loadinfo->ctoralloc != 0) + { + kfree(loadinfo->ctoralloc); + loadinfo->ctoralloc = NULL; + } + + loadinfo->ctors = NULL; + loadinfo->nctors = 0; + + if (loadinfo->dtoralloc != 0) + { + kfree(loadinfo->dtoralloc); + loadinfo->dtoralloc = NULL; + } + + loadinfo->dtors = NULL; + loadinfo->ndtors = 0; +#endif + + return OK; +} + |