diff --git a/ChangeLog b/ChangeLog index c9407d6344..96a49dff89 100755 --- a/ChangeLog +++ b/ChangeLog @@ -11233,4 +11233,6 @@ that of the type of a pthread. Hence, it could be confused as a task. Same problem as fixed on 2015-11-29, but in different location (2015-12-09). + * binfmt/libmodule: Add support for kernel modules. Initial commit is + just the ELF module support with name changes (2015-12-10). diff --git a/binfmt/libmodule/Kconfig b/binfmt/libmodule/Kconfig new file mode 100644 index 0000000000..feb42b68e5 --- /dev/null +++ b/binfmt/libmodule/Kconfig @@ -0,0 +1,52 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +config MODULE_ALIGN_LOG2 + int "Log2 Section Alignment" + default 2 + ---help--- + Align all sections to this Log2 value: 0->1, 1->2, 2->4, etc. + +config MODULE_STACKSIZE + int "Module Stack Size" + default 2048 + ---help--- + This is the default stack size that will be used when starting + module initialization tasks. + +config MODULE_BUFFERSIZE + int "Module I/O Buffer Size" + default 128 + ---help--- + This is an I/O buffer that is used to access the module file. + Variable length items will need to be read (such as symbol names). + This is really just this initial size of the buffer; it will be + reallocated as necessary to hold large symbol names). Default: 128 + +config MODULE_BUFFERINCR + int "Module I/O Buffer Realloc Increment" + default 32 + ---help--- + This is an I/O buffer that is used to access the module file. + Variable length items will need to be read (such as symbol names). + This value specifies the size increment to use each time the + buffer is reallocated. Default: 32 + +config MODULE_DUMPBUFFER + bool "Dump module buffers" + default n + depends on DEBUG && DEBUG_VERBOSE + ---help--- + Dump various module buffers for debug purposes + +config MODULE_EXIDX_SECTNAME + string "Module Section Name for Exception Index" + default ".ARM.exidx" + depends on UCLIBCXX_EXCEPTION + ---help--- + Set the name string for the exception index section on the modules to + be loaded by the module binary loader. + + This is needed to support exception handling on loadable modules. diff --git a/binfmt/libmodule/Make.defs b/binfmt/libmodule/Make.defs new file mode 100644 index 0000000000..e610aec6a3 --- /dev/null +++ b/binfmt/libmodule/Make.defs @@ -0,0 +1,59 @@ +############################################################################ +# binfmt/libmodule/Make.defs +# +# 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. +# +############################################################################ + +ifeq ($(CONFIG_ELF),y) + +# ELF application interfaces + +BINFMT_CSRCS += module.c + +# ELF library + +BINFMT_CSRCS += libmodule_bind.c libmodule_init.c libmodule_iobuffer.c +BINFMT_CSRCS += libmodule_load.c libmodule_read.c libmodule_sections.c +BINFMT_CSRCS += libmodule_symbols.c libmodule_uninit.c libmodule_unload.c +BINFMT_CSRCS += libmodule_verify.c + +ifeq ($(CONFIG_BINFMT_CONSTRUCTORS),y) +BINFMT_CSRCS += libmodule_ctors.c libmodule_dtors.c +endif + +# Hook the libmodule subdirectory into the build + +VPATH += libmodule +SUBDIRS += libmodule +DEPPATH += --dep-path libmodule + +endif diff --git a/binfmt/libmodule/gnu-elf.ld b/binfmt/libmodule/gnu-elf.ld new file mode 100644 index 0000000000..8b79f8d45a --- /dev/null +++ b/binfmt/libmodule/gnu-elf.ld @@ -0,0 +1,129 @@ +/**************************************************************************** + * binfmt/libmodule/gnu-elf.ld + * + * 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. + * + ****************************************************************************/ + +SECTIONS +{ + .text 0x00000000 : + { + _stext = . ; + *(.text) + *(.text.*) + *(.gnu.warning) + *(.stub) + *(.glue_7) + *(.glue_7t) + *(.jcr) + + /* C++ support: The .init and .fini sections contain specific logic + * to manage static constructors and destructors. + */ + + *(.gnu.linkonce.t.*) + *(.init) /* Old ABI */ + *(.fini) /* Old ABI */ + _etext = . ; + } + + .rodata : + { + _srodata = . ; + *(.rodata) + *(.rodata1) + *(.rodata.*) + *(.gnu.linkonce.r*) + _erodata = . ; + } + + .data : + { + _sdata = . ; + *(.data) + *(.data1) + *(.data.*) + *(.gnu.linkonce.d*) + _edata = . ; + } + + /* C++ support. For each global and static local C++ object, + * GCC creates a small subroutine to construct the object. Pointers + * to these routines (not the routines themselves) are stored as + * simple, linear arrays in the .ctors section of the object file. + * Similarly, pointers to global/static destructor routines are + * stored in .dtors. + */ + + .ctors : + { + _sctors = . ; + *(.ctors) /* Old ABI: Unallocated */ + *(.init_array) /* New ABI: Allocated */ + _ectors = . ; + } + + .dtors : + { + _sdtors = . ; + *(.dtors) /* Old ABI: Unallocated */ + *(.fini_array) /* New ABI: Allocated */ + _edtors = . ; + } + + .bss : + { + _sbss = . ; + *(.bss) + *(.bss.*) + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.b*) + *(COMMON) + _ebss = . ; + } + + /* Stabs debugging sections. */ + + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_info 0 : { *(.debug_info) } + .debug_line 0 : { *(.debug_line) } + .debug_pubnames 0 : { *(.debug_pubnames) } + .debug_aranges 0 : { *(.debug_aranges) } +} diff --git a/binfmt/libmodule/libmodule.h b/binfmt/libmodule/libmodule.h new file mode 100644 index 0000000000..eeed0498df --- /dev/null +++ b/binfmt/libmodule/libmodule.h @@ -0,0 +1,266 @@ +/**************************************************************************** + * binfmt/libmodule/libmodule.h + * + * Copyright (C) 2012, 2014 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. + * + ****************************************************************************/ + +#ifndef __BINFMT_LIBELF_LIBELF_H +#define __BINFMT_LIBELF_LIBELF_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Name: mod_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 mod_verifyheader(FAR const Elf32_Ehdr *header); + +/**************************************************************************** + * Name: mod_read + * + * Description: + * Read 'readsize' bytes from the object file at 'offset'. The data is + * read into 'buffer.' + * + * Returned Value: + * 0 (OK) is returned on success and a negated errno is returned on + * failure. + * + ****************************************************************************/ + +int mod_read(FAR struct mod_loadinfo_s *loadinfo, FAR uint8_t *buffer, + size_t readsize, off_t offset); + +/**************************************************************************** + * Name: mod_loadshdrs + * + * Description: + * Loads section headers into memory. + * + * Returned Value: + * 0 (OK) is returned on success and a negated errno is returned on + * failure. + * + ****************************************************************************/ + +int mod_loadshdrs(FAR struct mod_loadinfo_s *loadinfo); + +/**************************************************************************** + * Name: mod_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 mod_findsection(FAR struct mod_loadinfo_s *loadinfo, + FAR const char *sectname); + +/**************************************************************************** + * Name: mod_findsymtab + * + * Description: + * Find the symbol table section. + * + * Returned Value: + * 0 (OK) is returned on success and a negated errno is returned on + * failure. + * + ****************************************************************************/ + +int mod_findsymtab(FAR struct mod_loadinfo_s *loadinfo); + +/**************************************************************************** + * Name: mod_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 mod_readsym(FAR struct mod_loadinfo_s *loadinfo, int index, + FAR Elf32_Sym *sym); + +/**************************************************************************** + * Name: mod_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. + * + * EINVAL - There is something inconsistent in the symbol table (should only + * happen if the file is corrupted) + * ENOSYS - Symbol lies in common + * ESRCH - Symbol has no name + * ENOENT - Symbol undefined and not provided via a symbol table + * + ****************************************************************************/ + +int mod_symvalue(FAR struct mod_loadinfo_s *loadinfo, FAR Elf32_Sym *sym, + FAR const struct symtab_s *exports, int nexports); + +/**************************************************************************** + * Name: mod_freebuffers + * + * Description: + * Release all working buffers. + * + * Returned Value: + * 0 (OK) is returned on success and a negated errno is returned on + * failure. + * + ****************************************************************************/ + +int mod_freebuffers(FAR struct mod_loadinfo_s *loadinfo); + +/**************************************************************************** + * Name: mod_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 mod_allocbuffer(FAR struct mod_loadinfo_s *loadinfo); + +/**************************************************************************** + * Name: mod_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 mod_reallocbuffer(FAR struct mod_loadinfo_s *loadinfo, size_t increment); + +/**************************************************************************** + * Name: mod_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 mod_loadctors(FAR struct mod_loadinfo_s *loadinfo); +#endif + +/**************************************************************************** + * Name: mod_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 mod_loaddtors(FAR struct mod_loadinfo_s *loadinfo); +#endif + +#endif /* __BINFMT_LIBELF_LIBELF_H */ diff --git a/binfmt/libmodule/libmodule_bind.c b/binfmt/libmodule/libmodule_bind.c new file mode 100644 index 0000000000..8b5b680c8b --- /dev/null +++ b/binfmt/libmodule/libmodule_bind.c @@ -0,0 +1,332 @@ +/**************************************************************************** + * binfmt/libmodule/libmodule_bind.c + * + * Copyright (C) 2012, 2014 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 +#include + +#include +#include + +#include "libmodule.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 mod_dumpbuffer(m,b,n) bvdbgdumpbuffer(m,b,n) +#else +# define mod_dumpbuffer(m,b,n) +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mod_readrel + * + * Description: + * Read the ELF32_Rel structure into memory. + * + ****************************************************************************/ + +static inline int mod_readrel(FAR struct mod_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 mod_read(loadinfo, (FAR uint8_t *)rel, sizeof(Elf32_Rel), offset); +} + +/**************************************************************************** + * Name: mod_relocate and mod_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 mod_relocate(FAR struct mod_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; + FAR Elf32_Sym *psym; + 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++) + { + psym = &sym; + + /* Read the relocation entry into memory */ + + ret = mod_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 = mod_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 = mod_symvalue(loadinfo, &sym, exports, nexports); + if (ret < 0) + { + /* The special error -ESRCH is returned only in one condition: The + * symbol has no name. + * + * There are a few relocations for a few architectures that do + * no depend upon a named symbol. We don't know if that is the + * case here, but we will use a NULL symbol pointer to indicate + * that case to up_relocate(). That function can then do what + * is best. + */ + + if (ret == -ESRCH) + { + bdbg("Section %d reloc %d: Undefined symbol[%d] has no name: %d\n", + relidx, i, symidx, ret); + psym = NULL; + } + else + { + 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; + + /* Now perform the architecture-specific relocation */ + + ret = up_relocate(&rel, psym, addr); + if (ret < 0) + { + bdbg("ERROR: Section %d reloc %d: Relocation failed: %d\n", relidx, i, ret); + return ret; + } + } + + return OK; +} + +static int mod_relocateadd(FAR struct mod_loadinfo_s *loadinfo, int relidx, + FAR const struct symtab_s *exports, int nexports) +{ + bdbg("Not implemented\n"); + return -ENOSYS; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mod_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 mod_bind(FAR struct mod_loadinfo_s *loadinfo, + FAR const struct symtab_s *exports, int nexports) +{ + int ret; + int i; + + /* Find the symbol and string tables */ + + ret = mod_findsymtab(loadinfo); + if (ret < 0) + { + return ret; + } + + /* Allocate an I/O buffer. This buffer is used by mod_symname() to + * accumulate the variable length symbol name. + */ + + ret = mod_allocbuffer(loadinfo); + if (ret < 0) + { + bdbg("mod_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 = mod_relocate(loadinfo, i, exports, nexports); + } + else if (loadinfo->shdr[i].sh_type == SHT_RELA) + { + ret = mod_relocateadd(loadinfo, i, exports, nexports); + } + + if (ret < 0) + { + break; + } + } + +#if defined(CONFIG_ARCH_HAVE_COHERENT_DCACHE) + /* Ensure that the I and D caches are coherent before starting the newly + * loaded module by cleaning the D cache (i.e., flushing the D cache + * contents to memory and invalidating the I cache). + */ + + up_coherent_dcache(loadinfo->textalloc, loadinfo->textsize); + up_coherent_dcache(loadinfo->dataalloc, loadinfo->datasize); + +#endif + + return ret; +} diff --git a/binfmt/libmodule/libmodule_ctors.c b/binfmt/libmodule/libmodule_ctors.c new file mode 100644 index 0000000000..e89d310fbe --- /dev/null +++ b/binfmt/libmodule/libmodule_ctors.c @@ -0,0 +1,216 @@ +/**************************************************************************** + * binfmt/libmodule/libmodule_ctors.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 +#include + +#include "libmodule.h" + +#ifdef CONFIG_BINFMT_CONSTRUCTORS + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Constant Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mod_loadctors + * + * Description: + * Load pointers to static constructors 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. + * + ****************************************************************************/ + +int mod_loadctors(FAR struct mod_loadinfo_s *loadinfo) +{ + FAR Elf32_Shdr *shdr; + size_t ctorsize; + int ctoridx; + int ret; + int i; + + DEBUGASSERT(loadinfo->ctors == NULL); + + /* Allocate an I/O buffer if necessary. This buffer is used by + * mod_sectname() to accumulate the variable length symbol name. + */ + + ret = mod_allocbuffer(loadinfo); + if (ret < 0) + { + bdbg("mod_allocbuffer failed: %d\n", ret); + return -ENOMEM; + } + + /* Find the index to the section named ".ctors." NOTE: On old ABI system, + * .ctors is the name of the section containing the list of constructors; + * On newer systems, the similar section is called .init_array. It is + * expected that the linker script will force the section name to be ".ctors" + * in either case. + */ + + ctoridx = mod_findsection(loadinfo, ".ctors"); + if (ctoridx < 0) + { + /* This may not be a failure. -ENOENT indicates that the file has no + * static constructor section. + */ + + bvdbg("mod_findsection .ctors section failed: %d\n", ctoridx); + return ret == -ENOENT ? OK : ret; + } + + /* Now we can get a pointer to the .ctor section in the section header + * table. + */ + + shdr = &loadinfo->shdr[ctoridx]; + + /* Get the size of the .ctor section and the number of constructors that + * will need to be called. + */ + + ctorsize = shdr->sh_size; + loadinfo->nctors = ctorsize / sizeof(binfmt_ctor_t); + + bvdbg("ctoridx=%d ctorsize=%d sizeof(binfmt_ctor_t)=%d nctors=%d\n", + ctoridx, ctorsize, sizeof(binfmt_ctor_t), loadinfo->nctors); + + /* Check if there are any constructors. It is not an error if there + * are none. + */ + + if (loadinfo->nctors > 0) + { + /* Check an assumption that we made above */ + + DEBUGASSERT(shdr->sh_size == loadinfo->nctors * sizeof(binfmt_ctor_t)); + + /* In the old ABI, the .ctors section is not allocated. In that case, + * we need to allocate memory to hold the .ctors and then copy the + * from the file into the allocated memory. + * + * SHF_ALLOC indicates that the section requires memory during + * execution. + */ + + if ((shdr->sh_flags & SHF_ALLOC) == 0) + { + /* Allocate memory to hold a copy of the .ctor section */ + + loadinfo->ctoralloc = (binfmt_ctor_t *)kmm_malloc(ctorsize); + if (!loadinfo->ctoralloc) + { + bdbg("Failed to allocate memory for .ctors\n"); + return -ENOMEM; + } + + loadinfo->ctors = (binfmt_ctor_t *)loadinfo->ctoralloc; + + /* Read the section header table into memory */ + + ret = mod_read(loadinfo, (FAR uint8_t *)loadinfo->ctors, ctorsize, + shdr->sh_offset); + if (ret < 0) + { + bdbg("Failed to allocate .ctors: %d\n", ret); + return ret; + } + + /* Fix up all of the .ctor addresses. Since the addresses + * do not lie in allocated memory, there will be no relocation + * section for them. + */ + + for (i = 0; i < loadinfo->nctors; i++) + { + FAR uintptr_t *ptr = (uintptr_t *)((FAR void *)(&loadinfo->ctors)[i]); + + bvdbg("ctor %d: %08lx + %08lx = %08lx\n", + i, *ptr, (unsigned long)loadinfo->textalloc, + (unsigned long)(*ptr + loadinfo->textalloc)); + + *ptr += loadinfo->textalloc; + } + } + else + { + + /* Save the address of the .ctors (actually, .init_array) where it was + * loaded into memory. Since the .ctors lie in allocated memory, they + * will be relocated via the normal mechanism. + */ + + loadinfo->ctors = (binfmt_ctor_t *)shdr->sh_addr; + } + } + + return OK; +} + +#endif /* CONFIG_BINFMT_CONSTRUCTORS */ diff --git a/binfmt/libmodule/libmodule_dtors.c b/binfmt/libmodule/libmodule_dtors.c new file mode 100644 index 0000000000..d94c341ed7 --- /dev/null +++ b/binfmt/libmodule/libmodule_dtors.c @@ -0,0 +1,216 @@ +/**************************************************************************** + * binfmt/libmodule/libmodule_dtors.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 +#include + +#include "libmodule.h" + +#ifdef CONFIG_BINFMT_CONSTRUCTORS + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Constant Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mod_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. + * + ****************************************************************************/ + +int mod_loaddtors(FAR struct mod_loadinfo_s *loadinfo) +{ + FAR Elf32_Shdr *shdr; + size_t dtorsize; + int dtoridx; + int ret; + int i; + + DEBUGASSERT(loadinfo->dtors == NULL); + + /* Allocate an I/O buffer if necessary. This buffer is used by + * mod_sectname() to accumulate the variable length symbol name. + */ + + ret = mod_allocbuffer(loadinfo); + if (ret < 0) + { + bdbg("mod_allocbuffer failed: %d\n", ret); + return -ENOMEM; + } + + /* Find the index to the section named ".dtors." NOTE: On old ABI system, + * .dtors is the name of the section containing the list of destructors; + * On newer systems, the similar section is called .fini_array. It is + * expected that the linker script will force the section name to be ".dtors" + * in either case. + */ + + dtoridx = mod_findsection(loadinfo, ".dtors"); + if (dtoridx < 0) + { + /* This may not be a failure. -ENOENT indicates that the file has no + * static destructor section. + */ + + bvdbg("mod_findsection .dtors section failed: %d\n", dtoridx); + return ret == -ENOENT ? OK : ret; + } + + /* Now we can get a pointer to the .dtor section in the section header + * table. + */ + + shdr = &loadinfo->shdr[dtoridx]; + + /* Get the size of the .dtor section and the number of destructors that + * will need to be called. + */ + + dtorsize = shdr->sh_size; + loadinfo->ndtors = dtorsize / sizeof(binfmt_dtor_t); + + bvdbg("dtoridx=%d dtorsize=%d sizeof(binfmt_dtor_t)=%d ndtors=%d\n", + dtoridx, dtorsize, sizeof(binfmt_dtor_t), loadinfo->ndtors); + + /* Check if there are any destructors. It is not an error if there + * are none. + */ + + if (loadinfo->ndtors > 0) + { + /* Check an assumption that we made above */ + + DEBUGASSERT(shdr->sh_size == loadinfo->ndtors * sizeof(binfmt_dtor_t)); + + /* In the old ABI, the .dtors section is not allocated. In that case, + * we need to allocate memory to hold the .dtors and then copy the + * from the file into the allocated memory. + * + * SHF_ALLOC indicates that the section requires memory during + * execution. + */ + + if ((shdr->sh_flags & SHF_ALLOC) == 0) + { + /* Allocate memory to hold a copy of the .dtor section */ + + loadinfo->ctoralloc = (binfmt_dtor_t *)kmm_malloc(dtorsize); + if (!loadinfo->ctoralloc) + { + bdbg("Failed to allocate memory for .dtors\n"); + return -ENOMEM; + } + + loadinfo->dtors = (binfmt_dtor_t *)loadinfo->ctoralloc; + + /* Read the section header table into memory */ + + ret = mod_read(loadinfo, (FAR uint8_t *)loadinfo->dtors, dtorsize, + shdr->sh_offset); + if (ret < 0) + { + bdbg("Failed to allocate .dtors: %d\n", ret); + return ret; + } + + /* Fix up all of the .dtor addresses. Since the addresses + * do not lie in allocated memory, there will be no relocation + * section for them. + */ + + for (i = 0; i < loadinfo->ndtors; i++) + { + FAR uintptr_t *ptr = (uintptr_t *)((FAR void *)(&loadinfo->dtors)[i]); + + bvdbg("dtor %d: %08lx + %08lx = %08lx\n", + i, *ptr, (unsigned long)loadinfo->textalloc, + (unsigned long)(*ptr + loadinfo->textalloc)); + + *ptr += loadinfo->textalloc; + } + } + else + { + + /* Save the address of the .dtors (actually, .init_array) where it was + * loaded into memory. Since the .dtors lie in allocated memory, they + * will be relocated via the normal mechanism. + */ + + loadinfo->dtors = (binfmt_dtor_t *)shdr->sh_addr; + } + } + + return OK; +} + +#endif /* CONFIG_BINFMT_CONSTRUCTORS */ diff --git a/binfmt/libmodule/libmodule_init.c b/binfmt/libmodule/libmodule_init.c new file mode 100644 index 0000000000..a1ba9b0859 --- /dev/null +++ b/binfmt/libmodule/libmodule_init.c @@ -0,0 +1,202 @@ +/**************************************************************************** + * binfmt/libmodule/libmodule_init.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 +#include +#include + +#include + +#include "libmodule.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 + +#ifdef CONFIG_ELF_DUMPBUFFER +# define mod_dumpbuffer(m,b,n) bvdbgdumpbuffer(m,b,n) +#else +# define mod_dumpbuffer(m,b,n) +#endif + +/**************************************************************************** + * Private Constant Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mod_filelen + * + * Description: + * Get the size of the ELF file + * + * Returned Value: + * 0 (OK) is returned on success and a negated errno is returned on + * failure. + * + ****************************************************************************/ + +static inline int mod_filelen(FAR struct mod_loadinfo_s *loadinfo, + FAR const char *filename) +{ + struct stat buf; + int ret; + + /* Get the file stats */ + + ret = stat(filename, &buf); + if (ret < 0) + { + int errval = errno; + bdbg("Failed to stat file: %d\n", errval); + return -errval; + } + + /* Verify that it is a regular file */ + + if (!S_ISREG(buf.st_mode)) + { + bdbg("Not a regular file. mode: %d\n", buf.st_mode); + return -ENOENT; + } + + /* TODO: Verify that the file is readable. Not really important because + * we will detect this when we try to open the file read-only. + */ + + /* Return the size of the file in the loadinfo structure */ + + loadinfo->filelen = buf.st_size; + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mod_initialize + * + * Description: + * This function is called to configure the library to process an ELF + * program binary. + * + * Returned Value: + * 0 (OK) is returned on success and a negated errno is returned on + * failure. + * + ****************************************************************************/ + +int mod_initialize(FAR const char *filename, FAR struct mod_loadinfo_s *loadinfo) +{ + int ret; + + bvdbg("filename: %s loadinfo: %p\n", filename, loadinfo); + + /* Clear the load info structure */ + + memset(loadinfo, 0, sizeof(struct mod_loadinfo_s)); + + /* Get the length of the file. */ + + ret = mod_filelen(loadinfo, filename); + if (ret < 0) + { + bdbg("mod_filelen failed: %d\n", ret); + return ret; + } + + /* Open the binary file for reading (only) */ + + loadinfo->filfd = open(filename, O_RDONLY); + if (loadinfo->filfd < 0) + { + int errval = errno; + bdbg("Failed to open ELF binary %s: %d\n", filename, errval); + return -errval; + } + + /* Read the ELF ehdr from offset 0 */ + + ret = mod_read(loadinfo, (FAR uint8_t *)&loadinfo->ehdr, sizeof(Elf32_Ehdr), 0); + if (ret < 0) + { + bdbg("Failed to read ELF header: %d\n", ret); + return ret; + } + + mod_dumpbuffer("ELF header", (FAR const uint8_t *)&loadinfo->ehdr, sizeof(Elf32_Ehdr)); + + /* Verify the ELF header */ + + ret = mod_verifyheader(&loadinfo->ehdr); + if (ret < 0) + { + /* This may not be an error because we will be called to attempt loading + * EVERY binary. If mod_verifyheader() does not recognize the ELF header, + * it will -ENOEXEC whcih simply informs the system that the file is not an + * ELF file. mod_verifyheader() will return other errors if the ELF header + * is not correctly formed. + */ + + bdbg("Bad ELF header: %d\n", ret); + return ret; + } + + return OK; +} + diff --git a/binfmt/libmodule/libmodule_iobuffer.c b/binfmt/libmodule/libmodule_iobuffer.c new file mode 100644 index 0000000000..17f8da4c5c --- /dev/null +++ b/binfmt/libmodule/libmodule_iobuffer.c @@ -0,0 +1,136 @@ +/**************************************************************************** + * binfmt/libmodule/mod_iobuffer.c + * + * Copyright (C) 2012-2013 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 "libmodule.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Constant Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mod_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 mod_allocbuffer(FAR struct mod_loadinfo_s *loadinfo) +{ + /* Has a buffer been allocated> */ + + if (!loadinfo->iobuffer) + { + /* No.. allocate one now */ + + loadinfo->iobuffer = (FAR uint8_t *)kmm_malloc(CONFIG_ELF_BUFFERSIZE); + if (!loadinfo->iobuffer) + { + bdbg("Failed to allocate an I/O buffer\n"); + return -ENOMEM; + } + + loadinfo->buflen = CONFIG_ELF_BUFFERSIZE; + } + + return OK; +} + +/**************************************************************************** + * Name: mod_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 mod_reallocbuffer(FAR struct mod_loadinfo_s *loadinfo, size_t increment) +{ + FAR void *buffer; + size_t newsize; + + /* Get the new size of the allocation */ + + newsize = loadinfo->buflen + increment; + + /* And perform the reallocation */ + + buffer = kmm_realloc((FAR void *)loadinfo->iobuffer, newsize); + if (!buffer) + { + bdbg("Failed to reallocate the I/O buffer\n"); + return -ENOMEM; + } + + /* Save the new buffer info */ + + loadinfo->iobuffer = buffer; + loadinfo->buflen = newsize; + return OK; +} + diff --git a/binfmt/libmodule/libmodule_load.c b/binfmt/libmodule/libmodule_load.c new file mode 100644 index 0000000000..af89d3ff63 --- /dev/null +++ b/binfmt/libmodule/libmodule_load.c @@ -0,0 +1,333 @@ +/**************************************************************************** + * binfmt/libmodule/libmodule_load.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 +#include +#include +#include +#include + +#include + +#include "libmodule.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 + +#ifndef MIN +# define MIN(x,y) ((x) < (y) ? (x) : (y)) +#endif + +/**************************************************************************** + * Private Constant Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mod_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 mod_elfsize(struct mod_loadinfo_s *loadinfo) +{ + size_t textsize; + size_t datasize; + int i; + + /* Accumulate the size each section into memory that is marked SHF_ALLOC */ + + textsize = 0; + datasize = 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) + { + /* SHF_WRITE indicates that the section address space is write- + * able + */ + + if ((shdr->sh_flags & SHF_WRITE) != 0) + { + datasize += ELF_ALIGNUP(shdr->sh_size); + } + else + { + textsize += ELF_ALIGNUP(shdr->sh_size); + } + } + } + + /* Save the allocation size */ + + loadinfo->textsize = textsize; + loadinfo->datasize = datasize; +} + +/**************************************************************************** + * Name: mod_loadfile + * + * Description: + * 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 + * failure. + * + ****************************************************************************/ + +static inline int mod_loadfile(FAR struct mod_loadinfo_s *loadinfo) +{ + FAR uint8_t *text; + FAR uint8_t *data; + FAR uint8_t **pptr; + int ret; + int i; + + /* Read each section into memory that is marked SHF_ALLOC + SHT_NOBITS */ + + bvdbg("Loaded sections:\n"); + text = (FAR uint8_t *)loadinfo->textalloc; + data = (FAR uint8_t *)loadinfo->dataalloc; + + 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; + } + + /* SHF_WRITE indicates that the section address space is write- + * able + */ + + if ((shdr->sh_flags & SHF_WRITE) != 0) + { + pptr = &data; + } + else + { + pptr = &text; + } + + /* SHT_NOBITS indicates that there is no data in the file for the + * section. + */ + + if (shdr->sh_type != SHT_NOBITS) + { + /* Read the section data from sh_offset to the memory region */ + + ret = mod_read(loadinfo, *pptr, shdr->sh_size, shdr->sh_offset); + if (ret < 0) + { + bdbg("ERROR: Failed to read section %d: %d\n", i, ret); + return ret; + } + } + + /* If there is no data in an allocated section, then the allocated + * section must be cleared. + */ + + else + { + memset(*pptr, 0, shdr->sh_size); + } + + /* Update sh_addr to point to copy in memory */ + + bvdbg("%d. %08lx->%08lx\n", i, + (unsigned long)shdr->sh_addr, (unsigned long)*pptr); + + shdr->sh_addr = (uintptr_t)*pptr; + + /* Setup the memory pointer for the next time through the loop */ + + *pptr += ELF_ALIGNUP(shdr->sh_size); + } + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mod_load + * + * Description: + * Loads the binary into memory, allocating memory, performing relocations + * and initializing the data and bss segments. + * + * Returned Value: + * 0 (OK) is returned on success and a negated errno is returned on + * failure. + * + ****************************************************************************/ + +int mod_load(FAR struct mod_loadinfo_s *loadinfo) +{ + size_t heapsize; +#ifdef CONFIG_UCLIBCXX_EXCEPTION + int exidx; +#endif + int ret; + + bvdbg("loadinfo: %p\n", loadinfo); + DEBUGASSERT(loadinfo && loadinfo->filfd >= 0); + + /* Load section headers into memory */ + + ret = mod_loadshdrs(loadinfo); + if (ret < 0) + { + bdbg("ERROR: mod_loadshdrs failed: %d\n", ret); + goto errout_with_buffers; + } + + /* Determine total size to allocate */ + + mod_elfsize(loadinfo); + + /* Determine the heapsize to allocate. */ + + heapsize = 0; + + /* Allocate (and zero) memory for the ELF file. */ + + /* Allocate memory to hold the ELF image */ + + loadinfo->textalloc = (uintptr_t)kmm_zalloc(textsize + datasize); + if (!loadinfo->textalloc) + { + bdbg("ERROR: Failed to allocate memory for the module\n"); + ret = -ENOMEM; + goto errout_with_buffers; + } + + loadinfo->dataalloc = loadinfo->textalloc + textsize; + + /* Load ELF section data into memory */ + + ret = mod_loadfile(loadinfo); + if (ret < 0) + { + bdbg("ERROR: mod_loadfile failed: %d\n", ret); + goto errout_with_buffers; + } + + /* Load static constructors and destructors. */ + +#ifdef CONFIG_BINFMT_CONSTRUCTORS + ret = mod_loadctors(loadinfo); + if (ret < 0) + { + bdbg("ERROR: mod_loadctors failed: %d\n", ret); + goto errout_with_buffers; + } + + ret = mod_loaddtors(loadinfo); + if (ret < 0) + { + bdbg("ERROR: mod_loaddtors failed: %d\n", ret); + goto errout_with_buffers; + } +#endif + +#ifdef CONFIG_UCLIBCXX_EXCEPTION + exidx = mod_findsection(loadinfo, CONFIG_ELF_EXIDX_SECTNAME); + if (exidx < 0) + { + bvdbg("mod_findsection: Exception Index section not found: %d\n", exidx); + } + else + { + up_init_exidx(loadinfo->shdr[exidx].sh_addr, loadinfo->shdr[exidx].sh_size); + } +#endif + + return OK; + + /* Error exits */ + +errout_with_buffers: + mod_unload(loadinfo); + return ret; +} + diff --git a/binfmt/libmodule/libmodule_read.c b/binfmt/libmodule/libmodule_read.c new file mode 100644 index 0000000000..60f3c37c03 --- /dev/null +++ b/binfmt/libmodule/libmodule_read.c @@ -0,0 +1,163 @@ +/**************************************************************************** + * binfmt/libmodule/libmodule_read.c + * + * Copyright (C) 2014 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 +#include +#include + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#undef ELF_DUMP_READDATA /* Define to dump all file data read */ + +/**************************************************************************** + * Private Constant Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mod_dumpreaddata + ****************************************************************************/ + +#if defined(ELF_DUMP_READDATA) +static inline void mod_dumpreaddata(FAR char *buffer, int buflen) +{ + FAR uint32_t *buf32 = (FAR uint32_t *)buffer; + int i; + int j; + + for (i = 0; i < buflen; i += 32) + { + syslog(LOG_DEBUG, "%04x:", i); + for (j = 0; j < 32; j += sizeof(uint32_t)) + { + syslog(LOG_DEBUG, " %08x", *buf32++); + } + + syslog(LOG_DEBUG, "\n"); + } +} +#else +# define mod_dumpreaddata(b,n) +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mod_read + * + * Description: + * Read 'readsize' bytes from the object file at 'offset'. The data is + * read into 'buffer.' + * + * Returned Value: + * 0 (OK) is returned on success and a negated errno is returned on + * failure. + * + ****************************************************************************/ + +int mod_read(FAR struct mod_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 %lu: %d\n", + (unsigned 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 from offset %lu failed: %d\n", + (unsigned long)offset, errval); + return -errval; + } + } + else if (nbytes == 0) + { + bdbg("Unexpected end of file\n"); + return -ENODATA; + } + else + { + readsize -= nbytes; + buffer += nbytes; + offset += nbytes; + } + } + + mod_dumpreaddata(buffer, readsize); + return OK; +} diff --git a/binfmt/libmodule/libmodule_sections.c b/binfmt/libmodule/libmodule_sections.c new file mode 100644 index 0000000000..183d014141 --- /dev/null +++ b/binfmt/libmodule/libmodule_sections.c @@ -0,0 +1,287 @@ +/**************************************************************************** + * binfmt/libmodule/libmodule_sections.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 + +#include +#include + +#include "libmodule.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Constant Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mod_sectname + * + * Description: + * Get the symbol name in loadinfo->iobuffer[]. + * + * Returned Value: + * 0 (OK) is returned on success and a negated errno is returned on + * failure. + * + ****************************************************************************/ + +static inline int mod_sectname(FAR struct mod_loadinfo_s *loadinfo, + FAR const Elf32_Shdr *shdr) +{ + FAR Elf32_Shdr *shstr; + FAR uint8_t *buffer; + off_t offset; + size_t readlen; + size_t bytesread; + int shstrndx; + int ret; + + /* Get the section header table index of the entry associated with the + * section name string table. If the file has no section name string table, + * this member holds the value SH_UNDEF. + */ + + shstrndx = loadinfo->ehdr.e_shstrndx; + if (shstrndx == SHN_UNDEF) + { + bdbg("No section header string table\n"); + return -EINVAL; + } + + /* Get the section name string table section header */ + + shstr = &loadinfo->shdr[shstrndx]; + + /* Get the file offset to the string that is the name of the section. This + * is the sum of: + * + * shstr->sh_offset: The file offset to the first byte of the section + * header string table data. + * shdr->sh_name: The offset to the name of the section in the section + * name table + */ + + offset = shstr->sh_offset + shdr->sh_name; + + /* Loop until we get the entire section name into memory */ + + buffer = loadinfo->iobuffer; + bytesread = 0; + + for (; ; ) + { + /* Get the number of bytes to read */ + + readlen = loadinfo->buflen - bytesread; + if (offset + readlen > loadinfo->filelen) + { + if (loadinfo->filelen <= offset) + { + bdbg("At end of file\n"); + return -EINVAL; + } + + readlen = loadinfo->filelen - offset; + } + + /* Read that number of bytes into the array */ + + buffer = &loadinfo->iobuffer[bytesread]; + ret = mod_read(loadinfo, buffer, readlen, offset); + if (ret < 0) + { + bdbg("Failed to read section name\n"); + return ret; + } + + bytesread += readlen; + + /* Did we read the NUL terminator? */ + + if (memchr(buffer, '\0', readlen) != NULL) + { + /* Yes, the buffer contains a NUL terminator. */ + + return OK; + } + + /* No.. then we have to read more */ + + ret = mod_reallocbuffer(loadinfo, CONFIG_ELF_BUFFERINCR); + if (ret < 0) + { + bdbg("mod_reallocbuffer failed: %d\n", ret); + return ret; + } + } + + /* We will not get here */ + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mod_loadshdrs + * + * Description: + * Loads section headers into memory. + * + * Returned Value: + * 0 (OK) is returned on success and a negated errno is returned on + * failure. + * + ****************************************************************************/ + +int mod_loadshdrs(FAR struct mod_loadinfo_s *loadinfo) +{ + size_t shdrsize; + int ret; + + DEBUGASSERT(loadinfo->shdr == NULL); + + /* Verify that there are sections */ + + if (loadinfo->ehdr.e_shnum < 1) + { + bdbg("No sections(?)\n"); + return -EINVAL; + } + + /* Get the total size of the section header table */ + + shdrsize = (size_t)loadinfo->ehdr.e_shentsize * (size_t)loadinfo->ehdr.e_shnum; + if (loadinfo->ehdr.e_shoff + shdrsize > loadinfo->filelen) + { + bdbg("Insufficent space in file for section header table\n"); + return -ESPIPE; + } + + /* Allocate memory to hold a working copy of the sector header table */ + + loadinfo->shdr = (FAR FAR Elf32_Shdr *)kmm_malloc(shdrsize); + if (!loadinfo->shdr) + { + bdbg("Failed to allocate the section header table. Size: %ld\n", + (long)shdrsize); + return -ENOMEM; + } + + /* Read the section header table into memory */ + + ret = mod_read(loadinfo, (FAR uint8_t *)loadinfo->shdr, shdrsize, + loadinfo->ehdr.e_shoff); + if (ret < 0) + { + bdbg("Failed to read section header table: %d\n", ret); + } + + return ret; +} + +/**************************************************************************** + * Name: mod_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 mod_findsection(FAR struct mod_loadinfo_s *loadinfo, + FAR const char *sectname) +{ + FAR const Elf32_Shdr *shdr; + int ret; + int i; + + /* Search through the shdr[] array in loadinfo for a section named 'sectname' */ + + for (i = 0; i < loadinfo->ehdr.e_shnum; i++) + { + /* Get the name of this section */ + + shdr = &loadinfo->shdr[i]; + ret = mod_sectname(loadinfo, shdr); + if (ret < 0) + { + bdbg("mod_sectname failed: %d\n", ret); + return ret; + } + + /* Check if the name of this section is 'sectname' */ + + bvdbg("%d. Comparing \"%s\" and .\"%s\"\n", + i, loadinfo->iobuffer, sectname); + + if (strcmp((FAR const char *)loadinfo->iobuffer, sectname) == 0) + { + /* We found it... return the index */ + + return i; + } + } + + /* We failed to find a section with this name. */ + + return -ENOENT; +} diff --git a/binfmt/libmodule/libmodule_symbols.c b/binfmt/libmodule/libmodule_symbols.c new file mode 100644 index 0000000000..9e9de001d7 --- /dev/null +++ b/binfmt/libmodule/libmodule_symbols.c @@ -0,0 +1,346 @@ +/**************************************************************************** + * binfmt/libmodule/libmodule_symbols.c + * + * Copyright (C) 2012, 2014 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 + +#include +#include + +#include "libmodule.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef CONFIG_ELF_BUFFERINCR +# define CONFIG_ELF_BUFFERINCR 32 +#endif + +/**************************************************************************** + * Private Constant Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mod_symname + * + * Description: + * Get the symbol name in loadinfo->iobuffer[]. + * + * Returned Value: + * 0 (OK) is returned on success and a negated errno is returned on + * failure. + * + * EINVAL - There is something inconsistent in the symbol table (should only + * happen if the file is corrupted). + * ESRCH - Symbol has no name + * + ****************************************************************************/ + +static int mod_symname(FAR struct mod_loadinfo_s *loadinfo, + FAR const Elf32_Sym *sym) +{ + FAR uint8_t *buffer; + off_t offset; + size_t readlen; + size_t bytesread; + int ret; + + /* Get the file offset to the string that is the name of the symbol. The + * st_name member holds an offset into the file's symbol string table. + */ + + if (sym->st_name == 0) + { + bdbg("Symbol has no name\n"); + return -ESRCH; + } + + offset = loadinfo->shdr[loadinfo->strtabidx].sh_offset + sym->st_name; + + /* Loop until we get the entire symbol name into memory */ + + bytesread = 0; + + for (; ; ) + { + /* Get the number of bytes to read */ + + readlen = loadinfo->buflen - bytesread; + if (offset + readlen > loadinfo->filelen) + { + if (loadinfo->filelen <= offset) + { + bdbg("At end of file\n"); + return -EINVAL; + } + + readlen = loadinfo->filelen - offset; + } + + /* Read that number of bytes into the array */ + + buffer = &loadinfo->iobuffer[bytesread]; + ret = mod_read(loadinfo, buffer, readlen, offset); + if (ret < 0) + { + bdbg("mod_read failed: %d\n", ret); + return ret; + } + + bytesread += readlen; + + /* Did we read the NUL terminator? */ + + if (memchr(buffer, '\0', readlen) != NULL) + { + /* Yes, the buffer contains a NUL terminator. */ + + return OK; + } + + /* No.. then we have to read more */ + + ret = mod_reallocbuffer(loadinfo, CONFIG_ELF_BUFFERINCR); + if (ret < 0) + { + bdbg("mod_reallocbuffer failed: %d\n", ret); + return ret; + } + } + + /* We will not get here */ + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mod_findsymtab + * + * Description: + * Find the symbol table section. + * + * Returned Value: + * 0 (OK) is returned on success and a negated errno is returned on + * failure. + * + ****************************************************************************/ + +int mod_findsymtab(FAR struct mod_loadinfo_s *loadinfo) +{ + int i; + + /* Find the symbol table section header and its associated string table */ + + for (i = 1; i < loadinfo->ehdr.e_shnum; i++) + { + if (loadinfo->shdr[i].sh_type == SHT_SYMTAB) + { + loadinfo->symtabidx = i; + loadinfo->strtabidx = loadinfo->shdr[i].sh_link; + break; + } + } + + /* Verify that there is a symbol and string table */ + + if (loadinfo->symtabidx == 0) + { + bdbg("No symbols in ELF file\n"); + return -EINVAL; + } + + return OK; +} + +/**************************************************************************** + * Name: mod_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 mod_readsym(FAR struct mod_loadinfo_s *loadinfo, int index, + FAR Elf32_Sym *sym) +{ + FAR Elf32_Shdr *symtab = &loadinfo->shdr[loadinfo->symtabidx]; + off_t offset; + + /* Verify that the symbol table index lies within symbol table */ + + if (index < 0 || index > (symtab->sh_size / sizeof(Elf32_Sym))) + { + bdbg("Bad relocation symbol index: %d\n", index); + return -EINVAL; + } + + /* Get the file offset to the symbol table entry */ + + offset = symtab->sh_offset + sizeof(Elf32_Sym) * index; + + /* And, finally, read the symbol table entry into memory */ + + return mod_read(loadinfo, (FAR uint8_t *)sym, sizeof(Elf32_Sym), offset); +} + +/**************************************************************************** + * Name: mod_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) + * + * Returned Value: + * 0 (OK) is returned on success and a negated errno is returned on + * failure. + * + * EINVAL - There is something inconsistent in the symbol table (should only + * happen if the file is corrupted). + * ENOSYS - Symbol lies in common + * ESRCH - Symbol has no name + * ENOENT - Symbol undefined and not provided via a symbol table + * + ****************************************************************************/ + +int mod_symvalue(FAR struct mod_loadinfo_s *loadinfo, FAR Elf32_Sym *sym, + FAR const struct symtab_s *exports, int nexports) +{ + FAR const struct symtab_s *symbol; + uintptr_t secbase; + int ret; + + switch (sym->st_shndx) + { + case SHN_COMMON: + { + /* NuttX ELF modules should be compiled with -fno-common. */ + + bdbg("SHN_COMMON: Re-compile with -fno-common\n"); + return -ENOSYS; + } + + case SHN_ABS: + { + /* st_value already holds the correct value */ + + bvdbg("SHN_ABS: st_value=%08lx\n", (long)sym->st_value); + return OK; + } + + case SHN_UNDEF: + { + /* Get the name of the undefined symbol */ + + ret = mod_symname(loadinfo, sym); + if (ret < 0) + { + /* There are a few relocations for a few architectures that do + * no depend upon a named symbol. We don't know if that is the + * case here, but return and special error to the caller to + * indicate the nameless symbol. + */ + + bdbg("SHN_UNDEF: Failed to get symbol name: %d\n", ret); + return ret; + } + + /* Check if the base code exports a symbol of this name */ + +#ifdef CONFIG_SYMTAB_ORDEREDBYNAME + symbol = symtab_findorderedbyname(exports, (FAR char *)loadinfo->iobuffer, nexports); +#else + symbol = symtab_findbyname(exports, (FAR char *)loadinfo->iobuffer, nexports); +#endif + if (!symbol) + { + bdbg("SHN_UNDEF: Exported symbol \"%s\" not found\n", loadinfo->iobuffer); + return -ENOENT; + } + + /* Yes... add the exported symbol value to the ELF symbol table entry */ + + bvdbg("SHN_ABS: name=%s %08x+%08x=%08x\n", + loadinfo->iobuffer, sym->st_value, symbol->sym_value, + sym->st_value + symbol->sym_value); + + sym->st_value += (Elf32_Word)((uintptr_t)symbol->sym_value); + } + break; + + default: + { + secbase = loadinfo->shdr[sym->st_shndx].sh_addr; + + bvdbg("Other: %08x+%08x=%08x\n", + sym->st_value, secbase, sym->st_value + secbase); + + sym->st_value += secbase; + } + break; + } + + return OK; +} diff --git a/binfmt/libmodule/libmodule_uninit.c b/binfmt/libmodule/libmodule_uninit.c new file mode 100644 index 0000000000..9ca3684ce3 --- /dev/null +++ b/binfmt/libmodule/libmodule_uninit.c @@ -0,0 +1,126 @@ +/**************************************************************************** + * binfmt/libmodule/libmodule_uninit.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 + +#include "libmodule.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Constant Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mod_uninit + * + * Description: + * Releases any resources committed by mod_initialize(). This essentially + * undoes the actions of mod_initialize. + * + * Returned Value: + * 0 (OK) is returned on success and a negated errno is returned on + * failure. + * + ****************************************************************************/ + +int mod_uninit(struct mod_loadinfo_s *loadinfo) +{ + /* Free all working buffers */ + + mod_freebuffers(loadinfo); + + /* Close the ELF file */ + + if (loadinfo->filfd >= 0) + { + close(loadinfo->filfd); + } + + return OK; +} + +/**************************************************************************** + * Name: mod_freebuffers + * + * Description: + * Release all working buffers. + * + * Returned Value: + * 0 (OK) is returned on success and a negated errno is returned on + * failure. + * + ****************************************************************************/ + +int mod_freebuffers(struct mod_loadinfo_s *loadinfo) +{ + /* Release all working allocations */ + + if (loadinfo->shdr) + { + kmm_free((FAR void *)loadinfo->shdr); + loadinfo->shdr = NULL; + } + + if (loadinfo->iobuffer) + { + kmm_free((FAR void *)loadinfo->iobuffer); + loadinfo->iobuffer = NULL; + loadinfo->buflen = 0; + } + + return OK; +} diff --git a/binfmt/libmodule/libmodule_unload.c b/binfmt/libmodule/libmodule_unload.c new file mode 100644 index 0000000000..c424a8686b --- /dev/null +++ b/binfmt/libmodule/libmodule_unload.c @@ -0,0 +1,124 @@ +/**************************************************************************** + * binfmt/libmodule/libmodule_unload.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 "libmodule.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Constant Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mod_unload + * + * Description: + * This function unloads the object from memory. This essentially undoes + * the actions of mod_load. It is called only under certain error + * conditions after 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 mod_unload(struct mod_loadinfo_s *loadinfo) +{ + /* Free all working buffers */ + + mod_freebuffers(loadinfo); + + /* Release memory holding the relocated ELF image */ + + if (loadinfo->textalloc != 0) + { + kmm_free((FAR void *)loadinfo->textalloc); + } + + /* Clear out all indications of the allocated address environment */ + + loadinfo->textalloc = 0; + loadinfo->dataalloc = 0; + loadinfo->textsize = 0; + loadinfo->datasize = 0; + +#ifdef CONFIG_BINFMT_CONSTRUCTORS + /* Release memory used to hold static constructors and destructors */ + + if (loadinfo->ctoralloc != 0) + { + kmm_free(loadinfo->ctoralloc); + loadinfo->ctoralloc = NULL; + } + + loadinfo->ctors = NULL; + loadinfo->nctors = 0; + + if (loadinfo->dtoralloc != 0) + { + kmm_free(loadinfo->dtoralloc); + loadinfo->dtoralloc = NULL; + } + + loadinfo->dtors = NULL; + loadinfo->ndtors = 0; +#endif + + return OK; +} + diff --git a/binfmt/libmodule/libmodule_verify.c b/binfmt/libmodule/libmodule_verify.c new file mode 100644 index 0000000000..9d207180b3 --- /dev/null +++ b/binfmt/libmodule/libmodule_verify.c @@ -0,0 +1,123 @@ +/**************************************************************************** + * binfmt/libmodule/mod_verify.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 + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Constant Data + ****************************************************************************/ + +static const char g_modmagic[EI_MAGIC_SIZE] = +{ + 0x7f, 'E', 'L', 'F' +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mod_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. + * + * -ENOEXEC : Not an ELF file + * -EINVAL : Not a relocatable ELF file or not supported by the current, + * configured architecture. + * + ****************************************************************************/ + +int mod_verifyheader(FAR const Elf32_Ehdr *ehdr) +{ + if (!ehdr) + { + bdbg("NULL ELF header!"); + return -ENOEXEC; + } + + /* Verify that the magic number indicates an ELF file */ + + if (memcmp(ehdr->e_ident, g_modmagic, EI_MAGIC_SIZE) != 0) + { + bvdbg("Not ELF magic {%02x, %02x, %02x, %02x}\n", + ehdr->e_ident[0], ehdr->e_ident[1], ehdr->e_ident[2], ehdr->e_ident[3]); + return -ENOEXEC; + } + + /* Verify that this is a relocatable file */ + + if (ehdr->e_type != ET_REL) + { + bdbg("Not a relocatable file: e_type=%d\n", ehdr->e_type); + return -EINVAL; + } + + /* Verify that this file works with the currently configured architecture */ + + if (up_checkarch(ehdr)) + { + bdbg("Not a supported architecture\n"); + return -ENOEXEC; + } + + /* Looks good so far... we still might find some problems later. */ + + return OK; +} + diff --git a/binfmt/module.c b/binfmt/module.c new file mode 100644 index 0000000000..79f63df7c7 --- /dev/null +++ b/binfmt/module.c @@ -0,0 +1,368 @@ +/**************************************************************************** + * binfmt/module.c + * + * Copyright (C) 2015 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 +#include + +#include + +#include +#include +#include + +#include "libmodule/libmodule.h" + +#ifdef CONFIG_MODULE + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* CONFIG_DEBUG, CONFIG_DEBUG_VERBOSE, and CONFIG_DEBUG_BINFMT have to be + * defined or CONFIG_MODULE_DUMPBUFFER does nothing. + */ + +#if !defined(CONFIG_DEBUG_VERBOSE) || !defined (CONFIG_DEBUG_BINFMT) +# undef CONFIG_MODULE_DUMPBUFFER +#endif + +#ifndef CONFIG_MODULE_STACKSIZE +# define CONFIG_MODULE_STACKSIZE 2048 +#endif + +#ifdef CONFIG_MODULE_DUMPBUFFER +# define mod_dumpbuffer(m,b,n) bvdbgdumpbuffer(m,b,n) +#else +# define mod_dumpbuffer(m,b,n) +#endif + +#ifndef MIN +# define MIN(a,b) (a < b ? a : b) +#endif + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int mod_loadbinary(FAR struct binary_s *binp); +#if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_BINFMT) +static void mod_dumploadinfo(FAR struct mod_loadinfo_s *loadinfo); +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct binfmt_s g_modbinfmt = +{ + NULL, /* next */ + mod_loadbinary, /* load */ + NULL, /* unload */ +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mod_dumploadinfo + ****************************************************************************/ + +#if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_BINFMT) +static void mod_dumploadinfo(FAR struct mod_loadinfo_s *loadinfo) +{ + int i; + + bdbg("LOAD_INFO:\n"); + bdbg(" textalloc: %08lx\n", (long)loadinfo->textalloc); + bdbg(" dataalloc: %08lx\n", (long)loadinfo->dataalloc); + bdbg(" textsize: %ld\n", (long)loadinfo->textsize); + bdbg(" datasize: %ld\n", (long)loadinfo->datasize); + bdbg(" filelen: %ld\n", (long)loadinfo->filelen); +#ifdef CONFIG_BINFMT_CONSTRUCTORS + bdbg(" ctoralloc: %08lx\n", (long)loadinfo->ctoralloc); + bdbg(" ctors: %08lx\n", (long)loadinfo->ctors); + bdbg(" nctors: %d\n", loadinfo->nctors); + bdbg(" dtoralloc: %08lx\n", (long)loadinfo->dtoralloc); + bdbg(" dtors: %08lx\n", (long)loadinfo->dtors); + bdbg(" ndtors: %d\n", loadinfo->ndtors); +#endif + bdbg(" filfd: %d\n", loadinfo->filfd); + bdbg(" symtabidx: %d\n", loadinfo->symtabidx); + bdbg(" strtabidx: %d\n", loadinfo->strtabidx); + + bdbg("ELF Header:\n"); + bdbg(" e_ident: %02x %02x %02x %02x\n", + loadinfo->ehdr.e_ident[0], loadinfo->ehdr.e_ident[1], + loadinfo->ehdr.e_ident[2], loadinfo->ehdr.e_ident[3]); + bdbg(" e_type: %04x\n", loadinfo->ehdr.e_type); + bdbg(" e_machine: %04x\n", loadinfo->ehdr.e_machine); + bdbg(" e_version: %08x\n", loadinfo->ehdr.e_version); + bdbg(" e_entry: %08lx\n", (long)loadinfo->ehdr.e_entry); + bdbg(" e_phoff: %d\n", loadinfo->ehdr.e_phoff); + bdbg(" e_shoff: %d\n", loadinfo->ehdr.e_shoff); + bdbg(" e_flags: %08x\n" , loadinfo->ehdr.e_flags); + bdbg(" e_ehsize: %d\n", loadinfo->ehdr.e_ehsize); + bdbg(" e_phentsize: %d\n", loadinfo->ehdr.e_phentsize); + bdbg(" e_phnum: %d\n", loadinfo->ehdr.e_phnum); + bdbg(" e_shentsize: %d\n", loadinfo->ehdr.e_shentsize); + bdbg(" e_shnum: %d\n", loadinfo->ehdr.e_shnum); + bdbg(" e_shstrndx: %d\n", loadinfo->ehdr.e_shstrndx); + + if (loadinfo->shdr && loadinfo->ehdr.e_shnum > 0) + { + for (i = 0; i < loadinfo->ehdr.e_shnum; i++) + { + FAR Elf32_Shdr *shdr = &loadinfo->shdr[i]; + bdbg("Sections %d:\n", i); + bdbg(" sh_name: %08x\n", shdr->sh_name); + bdbg(" sh_type: %08x\n", shdr->sh_type); + bdbg(" sh_flags: %08x\n", shdr->sh_flags); + bdbg(" sh_addr: %08x\n", shdr->sh_addr); + bdbg(" sh_offset: %d\n", shdr->sh_offset); + bdbg(" sh_size: %d\n", shdr->sh_size); + bdbg(" sh_link: %d\n", shdr->sh_link); + bdbg(" sh_info: %d\n", shdr->sh_info); + bdbg(" sh_addralign: %d\n", shdr->sh_addralign); + bdbg(" sh_entsize: %d\n", shdr->sh_entsize); + } + } +} +#else +# define mod_dumploadinfo(i) +#endif + +/**************************************************************************** + * Name: mod_dumpentrypt + ****************************************************************************/ + +#ifdef CONFIG_MODULE_DUMPBUFFER +static void mod_dumpentrypt(FAR struct binary_s *binp, + FAR struct mod_loadinfo_s *loadinfo) +{ +#ifdef CONFIG_ARCH_ADDRENV + int ret; + + /* If CONFIG_ARCH_ADDRENV=y, then the loaded ELF lies in a virtual address + * space that may not be in place now. mod_addrenv_select() will + * temporarily instantiate that address space. + */ + + ret = mod_addrenv_select(loadinfo); + if (ret < 0) + { + bdbg("ERROR: mod_addrenv_select() failed: %d\n", ret); + return; + } +#endif + + mod_dumpbuffer("Entry code", (FAR const uint8_t *)binp->entrypt, + MIN(loadinfo->textsize - loadinfo->ehdr.e_entry, 512)); + +#ifdef CONFIG_ARCH_ADDRENV + /* Restore the original address environment */ + + ret = mod_addrenv_restore(loadinfo); + if (ret < 0) + { + bdbg("ERROR: mod_addrenv_restore() failed: %d\n", ret); + } +#endif +} +#else +# define mod_dumpentrypt(b,l) +#endif + +/**************************************************************************** + * Name: mod_loadbinary + * + * Description: + * Verify that the file is an ELF binary and, if so, load the ELF + * binary into memory + * + ****************************************************************************/ + +static int mod_loadbinary(FAR struct binary_s *binp) +{ + struct mod_loadinfo_s loadinfo; /* Contains globals for libmodule */ + int ret; + + bvdbg("Loading file: %s\n", binp->filename); + + /* Initialize the ELF library to load the program binary. */ + + ret = mod_init(binp->filename, &loadinfo); + mod_dumploadinfo(&loadinfo); + if (ret != 0) + { + bdbg("Failed to initialize for load of ELF program: %d\n", ret); + goto errout; + } + + /* Load the program binary */ + + ret = mod_load(&loadinfo); + mod_dumploadinfo(&loadinfo); + if (ret != 0) + { + bdbg("Failed to load ELF program binary: %d\n", ret); + goto errout_with_init; + } + + /* Bind the program to the exported symbol table */ + + ret = mod_bind(&loadinfo, binp->exports, binp->nexports); + if (ret != 0) + { + bdbg("Failed to bind symbols program binary: %d\n", ret); + goto errout_with_load; + } + + /* Return the load information */ + + binp->entrypt = (main_t)(loadinfo.textalloc + loadinfo.ehdr.e_entry); + binp->stacksize = CONFIG_MODULE_STACKSIZE; + + /* Add the ELF allocation to the alloc[] only if there is no address + * environment. If there is an address environment, it will automatically + * be freed when the function exits + * + * REVISIT: If the module is loaded then unloaded, wouldn't this cause + * a memory leak? + */ + +#ifdef CONFIG_ARCH_ADDRENV +# warning "REVISIT" +#else + binp->alloc[0] = (FAR void *)loadinfo.textalloc; +#endif + +#ifdef CONFIG_BINFMT_CONSTRUCTORS + /* Save information about constructors. NOTE: destructors are not + * yet supported. + */ + + binp->alloc[1] = loadinfo.ctoralloc; + binp->ctors = loadinfo.ctors; + binp->nctors = loadinfo.nctors; + + binp->alloc[2] = loadinfo.dtoralloc; + binp->dtors = loadinfo.dtors; + binp->ndtors = loadinfo.ndtors; +#endif + +#ifdef CONFIG_ARCH_ADDRENV + /* Save the address environment in the binfmt structure. This will be + * needed when the module is executed. + */ + + up_addrenv_clone(&loadinfo.addrenv, &binp->addrenv); +#endif + + mod_dumpentrypt(binp, &loadinfo); + mod_uninit(&loadinfo); + return OK; + +errout_with_load: + mod_unload(&loadinfo); +errout_with_init: + mod_uninit(&loadinfo); +errout: + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mod_initialize + * + * Description: + * ELF support is built unconditionally. However, in order to + * use this binary format, this function must be called during system + * initialization in order to register the ELF binary format. + * + * Returned Value: + * This is a NuttX internal function so it follows the convention that + * 0 (OK) is returned on success and a negated errno is returned on + * failure. + * + ****************************************************************************/ + +int mod_initialize(void) +{ + int ret; + + /* Register ourselves as a binfmt loader */ + + bvdbg("Registering ELF\n"); + + ret = register_binfmt(&g_modbinfmt); + if (ret != 0) + { + bdbg("Failed to register binfmt: %d\n", ret); + } + + return ret; +} + +/**************************************************************************** + * Name: mod_uninitialize + * + * Description: + * Unregister the ELF binary loader + * + * Returned Value: + * None + * + ****************************************************************************/ + +void mod_uninitialize(void) +{ + unregister_binfmt(&g_modbinfmt); +} + +#endif /* CONFIG_MODULE */ diff --git a/include/nuttx/binfmt/module.h b/include/nuttx/binfmt/module.h new file mode 100644 index 0000000000..811921f14f --- /dev/null +++ b/include/nuttx/binfmt/module.h @@ -0,0 +1,369 @@ +/**************************************************************************** + * include/nuttx/binfmt/module.h + * + * Copyright (C) 2015 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. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_BINFMT_MODULE_H +#define __INCLUDE_NUTTX_BINFMT_MODULE_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include +#include +#include + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ +/* Configuration ************************************************************/ + +#ifndef CONFIG_MODULE_ALIGN_LOG2 +# define CONFIG_MODULE_ALIGN_LOG2 2 +#endif + +#ifndef CONFIG_MODULE_STACKSIZE +# define CONFIG_MODULE_STACKSIZE 2048 +#endif + +#ifndef CONFIG_MODULE_BUFFERSIZE +# define CONFIG_MODULE_BUFFERSIZE 128 +#endif + +#ifndef CONFIG_MODULE_BUFFERINCR +# define CONFIG_MODULE_BUFFERINCR 32 +#endif + +/* Allocation array size and indices */ + +#define LIBMODULE_MODULE_ALLOC 0 +#ifdef CONFIG_BINFMT_CONSTRUCTORS +# define LIBMODULE_CTORS_ALLOC 1 +# define LIBMODULE_CTPRS_ALLOC 2 +# define LIBMODULE_NALLOC 3 +#else +# define LIBMODULE_NALLOC 1 +#endif + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* This struct provides a description of the currently loaded instantiation + * of the kernel module. + */ + +struct mod_loadinfo_s +{ + /* elfalloc is the base address of the memory that is allocated to hold the + * module image. + * + * If CONFIG_ARCH_ADDRENV=n, elfalloc will be allocated using kmm_malloc() (or + * kmm_zalloc()). If CONFIG_ARCH_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. + * + * The alloc[] array in struct binary_s will hold memory that persists after + * the module has been loaded. + */ + + uintptr_t textalloc; /* .text memory allocated when module was loaded */ + uintptr_t dataalloc; /* .bss/.data memory allocated when module was loaded */ + size_t textsize; /* Size of the module .text memory allocation */ + size_t datasize; /* Size of the module .bss/.data memory allocation */ + off_t filelen; /* Length of the entire module file */ + Elf32_Ehdr ehdr; /* Buffered module file header */ + FAR Elf32_Shdr *shdr; /* Buffered module section headers */ + uint8_t *iobuffer; /* File I/O buffer */ + + /* Constructors and destructors */ + +#ifdef CONFIG_BINFMT_CONSTRUCTORS + FAR void *ctoralloc; /* Memory allocated for ctors */ + FAR void *dtoralloc; /* Memory allocated dtors */ + FAR binfmt_ctor_t *ctors; /* Pointer to a list of constructors */ + FAR binfmt_dtor_t *dtors; /* Pointer to a list of destructors */ + uint16_t nctors; /* Number of constructors */ + uint16_t ndtors; /* Number of destructors */ +#endif + + /* Address environment. + * + * addrenv - This is the handle created by up_addrenv_create() that can be + * used to manage the tasks address space. + * oldenv - This is a value returned by up_addrenv_select() that must be + * used to restore the current address environment. + */ + +#ifdef CONFIG_ARCH_ADDRENV + group_addrenv_t addrenv; /* Task group address environment */ + save_addrenv_t oldenv; /* Saved address environment */ +#endif + + uint16_t symtabidx; /* Symbol table section index */ + uint16_t strtabidx; /* String table section index */ + uint16_t buflen; /* size of iobuffer[] */ + int filfd; /* Descriptor for the file being loaded */ +}; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * These are APIs exported by libelf (but are used only by the binfmt logic): + ****************************************************************************/ + +/**************************************************************************** + * Name: mod_init + * + * Description: + * This function is called to configure the library to process an kernel + * module. + * + * Returned Value: + * 0 (OK) is returned on success and a negated errno is returned on + * failure. + * + ****************************************************************************/ + +int mod_init(FAR const char *filename, FAR struct mod_loadinfo_s *loadinfo); + +/**************************************************************************** + * Name: mod_uninit + * + * Description: + * Releases any resources committed by mod_init(). This essentially + * undoes the actions of mod_init. + * + * Returned Value: + * 0 (OK) is returned on success and a negated errno is returned on + * failure. + * + ****************************************************************************/ + +int mod_uninit(FAR struct mod_loadinfo_s *loadinfo); + +/**************************************************************************** + * Name: mod_load + * + * Description: + * Loads the binary into memory, allocating memory, performing relocations + * and initializing the data and bss segments. + * + * Returned Value: + * 0 (OK) is returned on success and a negated errno is returned on + * failure. + * + ****************************************************************************/ + +int mod_load(FAR struct mod_loadinfo_s *loadinfo); + +/**************************************************************************** + * Name: mod_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. + * + ****************************************************************************/ + +struct symtab_s; +int mod_bind(FAR struct mod_loadinfo_s *loadinfo, + FAR const struct symtab_s *exports, int nexports); + +/**************************************************************************** + * Name: mod_unload + * + * Description: + * This function unloads the object from memory. This essentially undoes + * the actions of mod_load. It is called only under certain error + * conditions after 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 mod_unload(struct mod_loadinfo_s *loadinfo); + +/**************************************************************************** + * These are APIs used outside of binfmt by NuttX: + ****************************************************************************/ +/**************************************************************************** + * Name: mod_initialize + * + * Description: + * Module support is built unconditionally. However, in order to + * use this binary format, this function must be called during system + * initialization in order to register the module binary format. + * + * Returned Value: + * This is a NuttX internal function so it follows the convention that + * 0 (OK) is returned on success and a negated errno is returned on + * failure. + * + ****************************************************************************/ + +int mod_initialize(void); + +/**************************************************************************** + * Name: mod_uninitialize + * + * Description: + * Unregister the module loader + * + * Returned Value: + * None + * + ****************************************************************************/ + +void mod_uninitialize(void); + +/**************************************************************************** + * These are APIs must be provided by architecture-specific logic. + * (These really belong in include/nuttx/arch.h): + ****************************************************************************/ +/**************************************************************************** + * Name: up_checkarch + * + * Description: + * Given the ELF header in 'hdr', verify that the module is appropriate + * for the current, configured architecture. Every architecture that uses + * the module loader must provide this function. + * + * Input Parameters: + * hdr - The ELF header read from the module file. + * + * Returned Value: + * True if the architecture supports this module file. + * + ****************************************************************************/ + +bool up_checkarch(FAR const Elf32_Ehdr *hdr); + +/**************************************************************************** + * Name: up_relocate and up_relocateadd + * + * Description: + * Perform on architecture-specific ELF relocation. Every architecture + * that uses the module loader must provide this function. + * + * Input Parameters: + * rel - The relocation type + * sym - The ELF symbol structure containing the fully resolved value. + * There are a few relocation types for a few architectures that do + * not require symbol information. For those, this value will be + * NULL. Implementations of these functions must be able to handle + * that case. + * addr - The address that requires the relocation. + * + * Returned Value: + * Zero (OK) if the relocation was successful. Otherwise, a negated errno + * value indicating the cause of the relocation failure. + * + ****************************************************************************/ + +int up_relocate(FAR const Elf32_Rel *rel, FAR const Elf32_Sym *sym, + uintptr_t addr); +int up_relocateadd(FAR const Elf32_Rela *rel, + FAR const Elf32_Sym *sym, uintptr_t addr); + +#ifdef CONFIG_UCLIBCXX_EXCEPTION +/**************************************************************************** + * Name: up_init_exidx + * + * Description: + * Load the boundaries of the Exception Index ELF section in order to + * support exception handling for loaded modules. + * + * Input Parameters: + * address - The ELF section address for the Exception Index + * size - The size of the ELF section. + * + * Returned Value: + * Always returns Zero (OK). + * + ****************************************************************************/ +int up_init_exidx(Elf32_Addr address, Elf32_Word size); +#endif + +/**************************************************************************** + * Name: up_coherent_dcache + * + * Description: + * Ensure that the I and D caches are coherent within specified region + * by cleaning the D cache (i.e., flushing the D cache contents to memory + * and invalidating the I cache. This is typically used when code has been + * written to a memory region, and will be executed. + * + * Input Parameters: + * addr - virtual start address of region + * len - Size of the address region in bytes + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_ARCH_HAVE_COHERENT_DCACHE +void up_coherent_dcache(uintptr_t addr, size_t len); +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __INCLUDE_NUTTX_BINFMT_MODULE_H */