C++ constructors work with ELF load now

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@5273 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo 2012-10-29 19:32:05 +00:00
parent 0f70f8c9e1
commit ef6dcd6f90
22 changed files with 618 additions and 389 deletions

View file

@ -184,6 +184,7 @@ int arch_relocate(FAR const Elf32_Rel *rel, FAR const Elf32_Sym *sym,
break;
case R_ARM_ABS32:
case R_ARM_TARGET1: /* New ABI: TARGET1 always treated as ABS32 */
{
bvdbg("Performing ABS32 link at addr=%08lx [%08lx] to sym=%p st_value=%08lx\n",
(long)addr, (long)(*(uint32_t*)addr), sym, (long)sym->st_value);

View file

@ -178,6 +178,7 @@ int arch_relocate(FAR const Elf32_Rel *rel, FAR const Elf32_Sym *sym,
break;
case R_ARM_ABS32:
case R_ARM_TARGET1: /* New ABI: TARGET1 always treated as ABS32 */
{
bvdbg("Performing ABS32 link at addr=%08lx [%08lx] to sym=%p st_value=%08lx\n",
(long)addr, (long)(*(uint32_t*)addr), sym, (long)sym->st_value);

View file

@ -34,6 +34,13 @@ endif
endif
config BINFMT_CONSTRUCTORS
bool "C++ Static Constructor Support"
default n
depends on HAVE_CXX && ELF # FIX ME: Currently only supported for ELF
---help---
Build in support for C++ constructors in loaded modules.
config SYMTAB_ORDEREDBYNAME
bool "Symbol Tables Ordered by Name"
default n

View file

@ -1,7 +1,7 @@
/****************************************************************************
* binfmt/binfmt_dumpmodule.c
*
* Copyright (C) 2009 Gregory Nutt. All rights reserved.
* Copyright (C) 2009, 2012 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -90,8 +90,12 @@ int dump_module(FAR const struct binary_s *bin)
bdbg(" filename: %s\n", bin->filename);
bdbg(" argv: %p\n", bin->argv);
bdbg(" entrypt: %p\n", bin->entrypt);
bdbg(" ispace: %p size=%d\n", bin->ispace, bin->isize);
bdbg(" dspace: %p\n", bin->dspace);
bdbg(" mapped: %p size=%d\n", bin->mapped, bin->mapsize);
bdbg(" alloc: %p %p\n", bin->alloc[0], bin->alloc[1]);
#ifdef CONFIG_BINFMT_CONSTRUCTORS
bdbg(" ctors: %p nctors=%d\n", bin->ctors, bin->nctors);
bdbg(" dtors: %p ndtors=%d\n", bin->dtors, bin->ndtors);
#endif
bdbg(" stacksize: %d\n", bin->stacksize);
}
return OK;

View file

@ -70,6 +70,39 @@
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: exec_ctors
*
* Description:
* Execute 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
static inline void exec_ctors(FAR const struct binary_s *binp)
{
elf_ctor_t *ctor = binp->ctors;
int i;
/* Execute each constructor */
for (i = 0; i < binp->nctors; i++)
{
bvdbg("Calling ctor %d at %p\n", i, (FAR void *)ctor);
(*ctor)();
ctor++;
}
}
#endif
/****************************************************************************
* Public Functions
****************************************************************************/
@ -87,7 +120,7 @@
*
****************************************************************************/
int exec_module(FAR const struct binary_s *bin, int priority)
int exec_module(FAR const struct binary_s *binp, int priority)
{
FAR _TCB *tcb;
#ifndef CONFIG_CUSTOM_STACK
@ -100,14 +133,14 @@ int exec_module(FAR const struct binary_s *bin, int priority)
/* Sanity checking */
#ifdef CONFIG_DEBUG
if (!bin || !bin->ispace || !bin->entrypt || bin->stacksize <= 0)
if (!binp || !binp->entrypt || binp->stacksize <= 0)
{
err = EINVAL;
goto errout;
}
#endif
bdbg("Executing %s\n", bin->filename);
bdbg("Executing %s\n", binp->filename);
/* Allocate a TCB for the new task. */
@ -121,7 +154,7 @@ int exec_module(FAR const struct binary_s *bin, int priority)
/* Allocate the stack for the new task */
#ifndef CONFIG_CUSTOM_STACK
stack = (FAR uint32_t*)malloc(bin->stacksize);
stack = (FAR uint32_t*)malloc(binp->stacksize);
if (!tcb)
{
err = ENOMEM;
@ -130,11 +163,13 @@ int exec_module(FAR const struct binary_s *bin, int priority)
/* Initialize the task */
ret = task_init(tcb, bin->filename, priority, stack, bin->stacksize, bin->entrypt, bin->argv);
ret = task_init(tcb, binp->filename, priority, stack,
binp->stacksize, binp->entrypt, binp->argv);
#else
/* Initialize the task */
ret = task_init(tcb, bin->filename, priority, stack, bin->entrypt, bin->argv);
ret = task_init(tcb, binp->filename, priority, stack,
binp->entrypt, binp->argv);
#endif
if (ret < 0)
{
@ -143,10 +178,12 @@ int exec_module(FAR const struct binary_s *bin, int priority)
goto errout_with_stack;
}
/* Add the DSpace address as the PIC base address */
/* Add the D-Space address as the PIC base address. By convention, this
* must be the first allocated address space.
*/
#ifdef CONFIG_PIC
tcb->dspace = bin->dspace;
tcb->dspace = binp->alloc[0];
/* Re-initialize the task's initial state to account for the new PIC base */
@ -157,6 +194,12 @@ int exec_module(FAR const struct binary_s *bin, int priority)
pid = tcb->pid;
/* Execute all of the C++ static constructors */
#ifdef CONFIG_BINFMT_CONSTRUCTORS
exec_ctors(binp);
#endif
/* Then activate the task at the provided priority */
ret = task_activate(tcb);
@ -166,6 +209,7 @@ int exec_module(FAR const struct binary_s *bin, int priority)
bdbg("task_activate() failed: %d\n", err);
goto errout_with_stack;
}
return (int)pid;
errout_with_stack:

View file

@ -1,7 +1,7 @@
/****************************************************************************
* binfmt/binfmt_loadmodule.c
*
* Copyright (C) 2009 Gregory Nutt. All rights reserved.
* Copyright (C) 2009, 2012 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -67,6 +67,39 @@
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: exec_dtors
*
* Description:
* Execute 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
static inline void exec_dtors(FAR const struct binary_s *binp)
{
elf_dtor_t *dtor = binp->dtors;
int i;
/* Execute each destructor */
for (i = 0; i < binp->ndtors; i++)
{
bvdbg("Calling dtor %d at %p\n", i, (FAR void *)dtor);
(*dtor)();
dtor++;
}
}
#endif
/****************************************************************************
* Public Functions
****************************************************************************/
@ -76,7 +109,12 @@
*
* Description:
* Unload a (non-executing) module from memory. If the module has
* been started (via exec_module), calling this will be fatal.
* been started (via exec_module) and has not exited, calling this will
* be fatal.
*
* However, this function must be called after the module exist. How
* this is done is up to your logic. Perhaps you register it to be
* called by on_exit()?
*
* Returned Value:
* This is a NuttX internal function so it follows the convention that
@ -85,22 +123,40 @@
*
****************************************************************************/
int unload_module(FAR const struct binary_s *bin)
int unload_module(FAR const struct binary_s *binp)
{
if (bin)
int i;
if (binp)
{
if (bin->ispace)
/* Execute C++ desctructors */
#ifdef CONFIG_BINFMT_CONSTRUCTORS
exec_dtors(binp);
#endif
/* Unmap mapped address spaces */
if (binp->mapped)
{
bvdbg("Unmapping ISpace: %p\n", bin->ispace);
munmap(bin->ispace, bin->isize);
bvdbg("Unmapping address space: %p\n", binp->mapped);
munmap(binp->mapped, binp->mapsize);
}
if (bin->dspace)
/* Free allocated address spaces */
for (i = 0; i < BINFMT_NALLOC; i++)
{
bvdbg("Freeing DSpace: %p\n", bin->dspace);
free(bin->dspace);
if (binp->alloc[i])
{
bvdbg("Freeing alloc[%d]: %p\n", i, binp->alloc[i]);
free(binp->alloc[i]);
}
}
}
return OK;
}

View file

@ -114,7 +114,7 @@ static void elf_dumploadinfo(FAR struct elf_loadinfo_s *loadinfo)
bdbg(" alloc: %08lx\n", (long)loadinfo->alloc);
bdbg(" allocsize: %ld\n", (long)loadinfo->allocsize);
bdbg(" filelen: %ld\n", (long)loadinfo->filelen);
#ifdef CONFIG_ELF_CONSTRUCTORS
#ifdef CONFIG_BINFMT_CONSTRUCTORS
bdbg(" ctors: %08lx\n", (long)loadinfo->ctors);
bdbg(" nctors: %d\n", loadinfo->nctors);
#endif
@ -211,13 +211,31 @@ static int elf_loadbinary(struct binary_s *binp)
/* Return the load information */
binp->entrypt = (main_t)(loadinfo.alloc + loadinfo.ehdr.e_entry);
binp->ispace = (void*)loadinfo.alloc;
binp->dspace = NULL;
binp->isize = loadinfo.allocsize;
binp->alloc[0] = (FAR void *)loadinfo.alloc;
binp->stacksize = CONFIG_ELF_STACKSIZE;
#ifdef CONFIG_BINFMT_CONSTRUCTORS
/* Save information about constructors. NOTE: desctructors are not
* yet supported.
*/
binp->ctors = loadinfo.ctors;
binp->nctors = loadinfo.nctors;
/* Was memory allocated for constructors? */
if (!loadinfo.newabi)
{
/* Yes.. save the allocation address so that it can be freed by
* unload module.
*/
binp->alloc[1] = (FAR void *)loadinfo.ctors;
}
#endif
elf_dumpbuffer("Entry code", (FAR const uint8_t*)binp->entrypt,
MIN(binp->isize - loadinfo.ehdr.e_entry, 512));
MIN(loadinfo.allocsize - loadinfo.ehdr.e_entry, 512));
elf_uninit(&loadinfo);
return OK;

View file

@ -32,13 +32,6 @@ config ELF_BUFFERINCR
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 ELF_CONSTRUCTORS
bool "C++ Static Constructor Support"
default n
depends on HAVE_CXX
---help---
Build in support for C++ constructors in ELF modules.
config ELF_DUMPBUFFER
bool "Dump ELF buffers"
default n

View file

@ -41,11 +41,11 @@ BINFMT_CSRCS += elf.c
# ELF library
BINFMT_CSRCS += libelf_init.c libelf_uninit.c libelf_load.c \
libelf_unload.c libelf_verify.c libelf_read.c \
libelf_bind.c libelf_symbols.c libelf_iobuffer.c
BINFMT_CSRCS += libelf_bind.c libelf_init.c libelf_iobuffer.c libelf_load.c \
libelf_read.c libelf_sections.c libelf_symbols.c libelf_uninit.c \
libelf_unload.c libelf_verify.c
ifeq ($(CONFIG_ELF_CONSTRUCTORS),y)
ifeq ($(CONFIG_BINFMT_CONSTRUCTORS),y)
BINFMT_CSRCS += libelf_ctors.c
endif

View file

@ -85,6 +85,39 @@ int elf_verifyheader(FAR const Elf32_Ehdr *header);
int elf_read(FAR struct elf_loadinfo_s *loadinfo, FAR uint8_t *buffer,
size_t readsize, off_t offset);
/****************************************************************************
* Name: elf_loadshdrs
*
* Description:
* Loads section headers into memory.
*
* Returned Value:
* 0 (OK) is returned on success and a negated errno is returned on
* failure.
*
****************************************************************************/
int elf_loadshdrs(FAR struct elf_loadinfo_s *loadinfo);
/****************************************************************************
* Name: elf_findsection
*
* Description:
* A section by its name.
*
* Input Parameters:
* loadinfo - Load state information
* sectname - Name of the section to find
*
* Returned Value:
* On success, the index to the section is returned; A negated errno value
* is returned on failure.
*
****************************************************************************/
int elf_findsection(FAR struct elf_loadinfo_s *loadinfo,
FAR const char *sectname);
/****************************************************************************
* Name: elf_findsymtab
*
@ -199,27 +232,8 @@ int elf_reallocbuffer(FAR struct elf_loadinfo_s *loadinfo, size_t increment);
*
****************************************************************************/
#ifdef CONFIG_ELF_CONSTRUCTORS
#ifdef CONFIG_BINFMT_CONSTRUCTORS
int elf_loadctors(FAR struct elf_loadinfo_s *loadinfo);
#endif
/****************************************************************************
* Name: elf_doctors
*
* Description:
* Execute 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_ELF_CONSTRUCTORS
int elf_doctors(FAR struct elf_loadinfo_s *loadinfo);
#endif
#endif /* __BINFMT_LIBELF_LIBELF_H */

View file

@ -49,7 +49,7 @@
#include "libelf.h"
#ifdef CONFIG_ELF_CONSTRUCTORS
#ifdef CONFIG_BINFMT_CONSTRUCTORS
/****************************************************************************
* Pre-Processor Definitions
@ -67,166 +67,6 @@
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: elf_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 elf_sectname(FAR struct elf_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)
{
readlen = loadinfo->filelen - offset;
if (readlen <= 0)
{
bdbg("At end of file\n");
return -EINVAL;
}
}
/* Read that number of bytes into the array */
buffer = &loadinfo->iobuffer[bytesread];
ret = elf_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 = elf_reallocbuffer(loadinfo, CONFIG_ELF_BUFFERINCR);
if (ret < 0)
{
bdbg("elf_reallocbuffer failed: %d\n", ret);
return ret;
}
}
/* We will not get here */
return OK;
}
/****************************************************************************
* Name: elf_findctors
*
* Description:
* Find C++ static constructors.
*
* Input Parameters:
* loadinfo - Load state information
*
* Returned Value:
* On success, the index to the CTOR section is returned; A negated errno
* value is returned on failure.
*
****************************************************************************/
static inline int elf_findctors(FAR struct elf_loadinfo_s *loadinfo)
{
FAR const Elf32_Shdr *shdr;
int ret;
int i;
/* Search through the shdr[] array in loadinfo for a section named .ctors */
for (i = 0; i < loadinfo->ehdr.e_shnum; i++)
{
/* Get the name of this section */
shdr = &loadinfo->shdr[i];
ret = elf_sectname(loadinfo, shdr);
if (ret < 0)
{
bdbg("elf_sectname failed: %d\n", ret);
return ret;
}
/* Check if the name of this section if ".ctors" */
bvdbg("%d. Comparing \"%s\" and .ctors\"\n", i, loadinfo->iobuffer);
if (strcmp(".ctors", (FAR const char *)loadinfo->iobuffer) == 0)
{
/* We found it... return the index */
return i;
}
}
/* We failed to find the .ctors sections. This may not be an error; maybe
* there are no static constructors.
*/
return -ENOENT;
}
/****************************************************************************
* Public Functions
****************************************************************************/
@ -267,16 +107,21 @@ int elf_loadctors(FAR struct elf_loadinfo_s *loadinfo)
return -ENOMEM;
}
/* Find the index to the section named ".ctors" */
/* 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 sectino name to be ".ctors"
* in either case.
*/
ctoridx = elf_findctors(loadinfo);
ctoridx = elf_findsection(loadinfo, ".ctors");
if (ctoridx < 0)
{
/* This may not be a failure. -ENOENT indicates that the file has no
* static constructor section.
*/
bvdbg("elf_findctors failed: %d\n", ctoridx);
bvdbg("elf_findsection .ctors section failed: %d\n", ctoridx);
return ret == -ENOENT ? OK : ret;
}
@ -286,7 +131,9 @@ int elf_loadctors(FAR struct elf_loadinfo_s *loadinfo)
shdr = &loadinfo->shdr[ctoridx];
/* Allocate memory to hold a copy of the .ctor section */
/* 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(elf_ctor_t);
@ -302,71 +149,72 @@ int elf_loadctors(FAR struct elf_loadinfo_s *loadinfo)
{
/* Check an assumption that we made above */
DEBUGASSERT(shdr->sh_entsize == sizeof(elf_ctor_t));
DEBUGASSERT(shdr->sh_size == loadinfo->nctors * sizeof(elf_ctor_t));
loadinfo->ctors = (elf_ctor_t)kmalloc(ctorsize);
if (!loadinfo->ctors)
/* 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)
{
bdbg("Failed to allocate memory for .ctors\n");
return -ENOMEM;
/* Not loaded -> Old ABI. */
loadinfo->newabi = false;
/* Allocate memory to hold a copy of the .ctor section */
loadinfo->ctors = (elf_ctor_t*)kmalloc(ctorsize);
if (!loadinfo->ctors)
{
bdbg("Failed to allocate memory for .ctors\n");
return -ENOMEM;
}
/* Read the section header table into memory */
ret = elf_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, loadinfo->alloc, *ptr + loadinfo->alloc);
*ptr += loadinfo->alloc;
}
}
/* Read the section header table into memory */
ret = elf_read(loadinfo, (FAR uint8_t*)loadinfo->ctors, ctorsize,
shdr->sh_offset);
if (ret < 0)
else
{
bdbg("Failed to allocate .ctors: %d\n", ret);
}
/* Loaded -> New ABI. */
/* Fix up all of the .ctor addresses */
loadinfo->newabi = true;
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, loadinfo->alloc, *ptr + loadinfo->alloc);
*ptr += loadinfo->alloc;
/* 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 = (elf_ctor_t*)shdr->sh_addr;
}
}
return OK;
}
/****************************************************************************
* Name: elf_doctors
*
* Description:
* Execute 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.
*
****************************************************************************/
int elf_doctors(FAR struct elf_loadinfo_s *loadinfo)
{
elf_ctor_t ctor = (elf_ctor_t)loadinfo->ctors;
int i;
/* Execute each constructor */
for (i = 0; i < loadinfo->nctors; i++)
{
bvdbg("Calling ctor %d at %p\n", i, (FAR void *)ctor);
ctor();
ctor++;
}
return OK;
}
#endif /* CONFIG_ELF_CONSTRUCTORS */
#endif /* CONFIG_BINFMT_CONSTRUCTORS */

View file

@ -75,62 +75,6 @@
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: elf_loadshdrs
*
* Description:
* Loads section headers into memory.
*
* Returned Value:
* 0 (OK) is returned on success and a negated errno is returned on
* failure.
*
****************************************************************************/
static inline int elf_loadshdrs(FAR struct elf_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 Elf32_Shdr*)kmalloc(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 = elf_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: elf_allocsize
*
@ -292,7 +236,7 @@ int elf_load(FAR struct elf_loadinfo_s *loadinfo)
/* Find static constructors. */
#ifdef CONFIG_ELF_CONSTRUCTORS
#ifdef CONFIG_BINFMT_CONSTRUCTORS
ret = elf_loadctors(loadinfo);
if (ret < 0)
{

View file

@ -0,0 +1,284 @@
/****************************************************************************
* binfmt/libelf/libelf_sections.c
*
* Copyright (C) 2012 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/kmalloc.h>
#include <nuttx/binfmt/elf.h>
#include "libelf.h"
/****************************************************************************
* Pre-Processor Definitions
****************************************************************************/
/****************************************************************************
* Private Constant Data
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: elf_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 elf_sectname(FAR struct elf_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)
{
readlen = loadinfo->filelen - offset;
if (readlen <= 0)
{
bdbg("At end of file\n");
return -EINVAL;
}
}
/* Read that number of bytes into the array */
buffer = &loadinfo->iobuffer[bytesread];
ret = elf_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 = elf_reallocbuffer(loadinfo, CONFIG_ELF_BUFFERINCR);
if (ret < 0)
{
bdbg("elf_reallocbuffer failed: %d\n", ret);
return ret;
}
}
/* We will not get here */
return OK;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: elf_loadshdrs
*
* Description:
* Loads section headers into memory.
*
* Returned Value:
* 0 (OK) is returned on success and a negated errno is returned on
* failure.
*
****************************************************************************/
int elf_loadshdrs(FAR struct elf_loadinfo_s *loadinfo)
{
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 Elf32_Shdr*)kmalloc(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 = elf_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: elf_findsection
*
* Description:
* A section by its name.
*
* Input Parameters:
* loadinfo - Load state information
* sectname - Name of the section to find
*
* Returned Value:
* On success, the index to the section is returned; A negated errno value
* is returned on failure.
*
****************************************************************************/
int elf_findsection(FAR struct elf_loadinfo_s *loadinfo,
FAR const char *sectname)
{
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 = elf_sectname(loadinfo, shdr);
if (ret < 0)
{
bdbg("elf_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;
}

View file

@ -115,15 +115,6 @@ int elf_freebuffers(struct elf_loadinfo_s *loadinfo)
loadinfo->shdr = NULL;
}
#ifdef CONFIG_ELF_CONSTRUCTORS
if (loadinfo->ctors)
{
kfree((FAR void *)loadinfo->ctors);
loadinfo->ctors = NULL;
loadinfo->nctors = 0;
}
#endif
if (loadinfo->iobuffer)
{
kfree((FAR void *)loadinfo->iobuffer);

View file

@ -91,6 +91,26 @@ int elf_unload(struct elf_loadinfo_s *loadinfo)
loadinfo->allocsize = 0;
}
/* Release any allocated constructor memory */
#ifdef CONFIG_BINFMT_CONSTRUCTORS
if (loadinfo->ctors)
{
/* In the old ABI, the .ctors section is not make for allocation. In
* that case, we need to free the working buffer that was used to hold
* the constructors.
*/
if (!loadinfo->newabi)
{
kfree((FAR void *)loadinfo->ctors);
}
loadinfo->ctors = NULL;
loadinfo->nctors = 0;
}
#endif
return OK;
}

View file

@ -62,24 +62,6 @@
* Private Constant Data
****************************************************************************/
#if defined(CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_BINFMT)
static const char g_relocrel32i[] = "RELOC_REL32I";
static const char g_relocrel32d[] = "RELOC_REL32D";
static const char g_relocabs32[] = "RELOC_AB32";
static const char g_undefined[] = "UNDEFINED";
static const char *g_reloctype[] =
{
g_relocrel32i,
g_relocrel32d,
g_relocabs32,
g_undefined
};
# define RELONAME(rl) g_reloctype[NXFLAT_RELOC_TYPE(rl)]
#else
# define RELONAME(rl) "(no name)"
#endif
/****************************************************************************
* Private Functions
****************************************************************************/

View file

@ -181,16 +181,18 @@ static int nxflat_loadbinary(struct binary_s *binp)
goto errout_with_load;
}
/* Return the load information */
/* Return the load information. By convention, D-space address
* space is stored as the first allocated memory.
*/
binp->entrypt = (main_t)(loadinfo.ispace + loadinfo.entryoffs);
binp->ispace = (void*)loadinfo.ispace;
binp->dspace = (void*)loadinfo.dspace;
binp->isize = loadinfo.isize;
binp->mapped = (void*)loadinfo.ispace;
binp->alloc[0] = (void*)loadinfo.dspace;
binp->mapsize = loadinfo.isize;
binp->stacksize = loadinfo.stacksize;
nxflat_dumpbuffer("Entry code", (FAR const uint8_t*)binp->entrypt,
MIN(binp->isize - loadinfo.entryoffs,512));
MIN(loadinfo.isize - loadinfo.entryoffs, 512));
nxflat_uninit(&loadinfo);
return OK;

View file

@ -160,8 +160,8 @@ LDNXFLATFLAGS = -e main -s 2048
# ELF module definitions
CELFFLAGS = $(CFLAGS) -mlong-calls
CXXELFFLAGS = $(CXXFLAGS) -mlong-calls
CELFFLAGS = $(CFLAGS) -mlong-calls # --target1-abs
CXXELFFLAGS = $(CXXFLAGS) -mlong-calls # --target1-abs
LDELFFLAGS = -r -e main
ifeq ($(WINTOOL),y)

View file

@ -388,7 +388,7 @@ CONFIG_ELF_ALIGN_LOG2=2
CONFIG_ELF_STACKSIZE=2048
CONFIG_ELF_BUFFERSIZE=128
CONFIG_ELF_BUFFERINCR=32
CONFIG_ELF_CONSTRUCTORS=y
CONFIG_BINFMT_CONSTRUCTORS=y
CONFIG_SYMTAB_ORDEREDBYNAME=y
#

View file

@ -51,8 +51,8 @@ SECTIONS
*/
*(.gnu.linkonce.t.*)
*(.init)
*(.fini)
*(.init) /* Old ABI */
*(.fini) /* Old ABI */
_etext = . ;
}
@ -86,15 +86,17 @@ SECTIONS
.ctors :
{
_sctros = . ;
*(.ctors)
_sctors = . ;
*(.ctors) /* Old ABI: Unallocated */
*(.init_array) /* New ABI: Allocated */
_edtors = . ;
}
.ctors :
.dtors :
{
_sdtors = . ;
*(.dtors)
*(.dtors) /* Old ABI: Unallocated */
*(.fini_array) /* New ABI: Allocated */
_edtors = . ;
}

View file

@ -49,9 +49,15 @@
* Pre-processor Definitions
****************************************************************************/
#define BINFMT_NALLOC 2
/****************************************************************************
* Public Types
****************************************************************************/
/* The type of one C++ constructor or destructor */
typedef FAR void (*elf_ctor_t)(void);
typedef FAR void (*elf_dtor_t)(void);
/* This describes the file to be loaded */
@ -70,9 +76,15 @@ struct binary_s
*/
main_t entrypt; /* Entry point into a program module */
FAR void *ispace; /* Memory-mapped, I-space (.text) address */
FAR struct dspace_s *dspace; /* Address of the allocated .data/.bss space */
size_t isize; /* Size of the I-space region (needed for munmap) */
FAR void *mapped; /* Memory-mapped, address space */
FAR void *alloc[BINFMT_NALLOC]; /* Allocated address spaces */
#ifdef CONFIG_BINFMT_CONSTRUCTORS
elf_ctor_t *ctors; /* Pointer to a list of constructors */
elf_dtor_t *dtors; /* Pointer to a list of destructors */
uint16_t nctors; /* Number of constructors in the list */
uint16_t ndtors; /* Number of destructors in the list */
#endif
size_t mapsize; /* Size of the mapped address region (needed for munmap) */
size_t stacksize; /* Size of the stack in bytes (unallocated) */
};
@ -151,7 +163,12 @@ EXTERN int load_module(FAR struct binary_s *bin);
*
* Description:
* Unload a (non-executing) module from memory. If the module has
* been started (via exec_module), calling this will be fatal.
* been started (via exec_module) and has not exited, calling this will
* be fatal.
*
* However, this function must be called after the module exist. How
* this is done is up to your logic. Perhaps you register it to be
* called by on_exit()?
*
* Returned Value:
* This is a NuttX internal function so it follows the convention that

View file

@ -43,10 +43,13 @@
#include <nuttx/config.h>
#include <sys/types.h>
#include <stdint.h>
#include <stdbool.h>
#include <elf32.h>
#include <nuttx/binfmt/binfmt.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
@ -59,9 +62,6 @@
/****************************************************************************
* Public Types
****************************************************************************/
/* The type of one C++ constructor */
typedef FAR void (*elf_ctor_t)(void);
/* This struct provides a desciption of the currently loaded instantiation
* of an ELF binary.
@ -72,17 +72,18 @@ struct elf_loadinfo_s
uintptr_t alloc; /* Allocated memory with the ELF file is loaded */
size_t allocsize; /* Size of the memory allocation */
off_t filelen; /* Length of the entire ELF file */
int filfd; /* Descriptor for the file being loaded */
#ifdef CONFIG_ELF_CONSTRUCTORS
elf_ctor_t ctors; /* Pointer to a list of constructors */
Elf32_Ehdr ehdr; /* Buffered ELF file header */
FAR Elf32_Shdr *shdr; /* Buffered ELF section headers */
uint8_t *iobuffer; /* File I/O buffer */
#ifdef CONFIG_BINFMT_CONSTRUCTORS
elf_ctor_t *ctors; /* Pointer to a list of constructors */
bool newabi; /* True: ctors in 'alloc' */
uint16_t nctors; /* Number of constructors */
#endif
uint16_t symtabidx; /* Symbol table section index */
uint16_t strtabidx; /* String table section index */
uint16_t buflen; /* size of iobuffer[] */
Elf32_Ehdr ehdr; /* Buffered ELF file header */
FAR Elf32_Shdr *shdr; /* Buffered ELF section headers */
uint8_t *iobuffer; /* File I/O buffer */
int filfd; /* Descriptor for the file being loaded */
};
/****************************************************************************