diff --git a/arch/arm/src/arm/up_elf.c b/arch/arm/src/arm/up_elf.c index b78da02c19..2dd8366aa0 100644 --- a/arch/arm/src/arm/up_elf.c +++ b/arch/arm/src/arm/up_elf.c @@ -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); diff --git a/arch/arm/src/armv7-m/up_elf.c b/arch/arm/src/armv7-m/up_elf.c index 1cc1fa32a2..b838a69057 100644 --- a/arch/arm/src/armv7-m/up_elf.c +++ b/arch/arm/src/armv7-m/up_elf.c @@ -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); diff --git a/binfmt/Kconfig b/binfmt/Kconfig index 4d020163ee..ae02c276a1 100644 --- a/binfmt/Kconfig +++ b/binfmt/Kconfig @@ -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 diff --git a/binfmt/binfmt_dumpmodule.c b/binfmt/binfmt_dumpmodule.c index 06e97e4572..e095c4a67a 100644 --- a/binfmt/binfmt_dumpmodule.c +++ b/binfmt/binfmt_dumpmodule.c @@ -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 * * 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; diff --git a/binfmt/binfmt_execmodule.c b/binfmt/binfmt_execmodule.c index bc76d4acfc..b00248183b 100644 --- a/binfmt/binfmt_execmodule.c +++ b/binfmt/binfmt_execmodule.c @@ -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: diff --git a/binfmt/binfmt_unloadmodule.c b/binfmt/binfmt_unloadmodule.c index 0de9dfccd1..15b2383570 100644 --- a/binfmt/binfmt_unloadmodule.c +++ b/binfmt/binfmt_unloadmodule.c @@ -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 * * 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; } diff --git a/binfmt/elf.c b/binfmt/elf.c index 57123ed95d..26057ffc10 100644 --- a/binfmt/elf.c +++ b/binfmt/elf.c @@ -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; diff --git a/binfmt/libelf/Kconfig b/binfmt/libelf/Kconfig index 5dc4a2d9fe..f6f579276c 100644 --- a/binfmt/libelf/Kconfig +++ b/binfmt/libelf/Kconfig @@ -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 diff --git a/binfmt/libelf/Make.defs b/binfmt/libelf/Make.defs index cf2507a995..26198ade2a 100644 --- a/binfmt/libelf/Make.defs +++ b/binfmt/libelf/Make.defs @@ -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 diff --git a/binfmt/libelf/libelf.h b/binfmt/libelf/libelf.h index 0d13515cc9..bea92496ab 100644 --- a/binfmt/libelf/libelf.h +++ b/binfmt/libelf/libelf.h @@ -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 */ diff --git a/binfmt/libelf/libelf_ctors.c b/binfmt/libelf/libelf_ctors.c index c53923d44f..a57fc37d93 100644 --- a/binfmt/libelf/libelf_ctors.c +++ b/binfmt/libelf/libelf_ctors.c @@ -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 */ diff --git a/binfmt/libelf/libelf_load.c b/binfmt/libelf/libelf_load.c index 505e2c8131..221ae8d438 100644 --- a/binfmt/libelf/libelf_load.c +++ b/binfmt/libelf/libelf_load.c @@ -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) { diff --git a/binfmt/libelf/libelf_sections.c b/binfmt/libelf/libelf_sections.c new file mode 100644 index 0000000000..c417935446 --- /dev/null +++ b/binfmt/libelf/libelf_sections.c @@ -0,0 +1,284 @@ +/**************************************************************************** + * binfmt/libelf/libelf_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 "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; +} diff --git a/binfmt/libelf/libelf_uninit.c b/binfmt/libelf/libelf_uninit.c index 06bb896816..3ec6f6c61c 100644 --- a/binfmt/libelf/libelf_uninit.c +++ b/binfmt/libelf/libelf_uninit.c @@ -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); diff --git a/binfmt/libelf/libelf_unload.c b/binfmt/libelf/libelf_unload.c index d7a8827111..8102f7bf2f 100644 --- a/binfmt/libelf/libelf_unload.c +++ b/binfmt/libelf/libelf_unload.c @@ -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; } diff --git a/binfmt/libnxflat/libnxflat_load.c b/binfmt/libnxflat/libnxflat_load.c index 02f035072d..b6693ea36a 100644 --- a/binfmt/libnxflat/libnxflat_load.c +++ b/binfmt/libnxflat/libnxflat_load.c @@ -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 ****************************************************************************/ diff --git a/binfmt/nxflat.c b/binfmt/nxflat.c index 8d0ecfdcd9..5973a96a98 100644 --- a/binfmt/nxflat.c +++ b/binfmt/nxflat.c @@ -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; diff --git a/configs/stm32f4discovery/elf/Make.defs b/configs/stm32f4discovery/elf/Make.defs index 7df9b13da6..035a03e71a 100644 --- a/configs/stm32f4discovery/elf/Make.defs +++ b/configs/stm32f4discovery/elf/Make.defs @@ -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) diff --git a/configs/stm32f4discovery/elf/defconfig b/configs/stm32f4discovery/elf/defconfig index 59c221a0ca..67f5bf365a 100644 --- a/configs/stm32f4discovery/elf/defconfig +++ b/configs/stm32f4discovery/elf/defconfig @@ -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 # diff --git a/configs/stm32f4discovery/scripts/gnu-elf.ld b/configs/stm32f4discovery/scripts/gnu-elf.ld index 0153cf5fad..1f29f02f5b 100644 --- a/configs/stm32f4discovery/scripts/gnu-elf.ld +++ b/configs/stm32f4discovery/scripts/gnu-elf.ld @@ -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 = . ; } diff --git a/include/nuttx/binfmt/binfmt.h b/include/nuttx/binfmt/binfmt.h index 82e5f3557c..0c18bfc49a 100644 --- a/include/nuttx/binfmt/binfmt.h +++ b/include/nuttx/binfmt/binfmt.h @@ -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 diff --git a/include/nuttx/binfmt/elf.h b/include/nuttx/binfmt/elf.h index 4770d82a3f..2e3cb86236 100644 --- a/include/nuttx/binfmt/elf.h +++ b/include/nuttx/binfmt/elf.h @@ -43,10 +43,13 @@ #include #include + #include #include #include +#include + /**************************************************************************** * 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 */ }; /****************************************************************************