diff --git a/binfmt/Makefile b/binfmt/Makefile index 4e1f18ebc4..c5cfe9736b 100644 --- a/binfmt/Makefile +++ b/binfmt/Makefile @@ -1,7 +1,7 @@ ############################################################################ # nxflat/Makefile # -# Copyright (C) 2007-2009, 2012-2013 Gregory Nutt. All rights reserved. +# Copyright (C) 2007-2009, 2012-2014 Gregory Nutt. All rights reserved. # Author: Gregory Nutt # # Redistribution and use in source and binary forms, with or without @@ -61,6 +61,10 @@ endif BINFMT_CSRCS += symtab_findbyname.c symtab_findbyvalue.c BINFMT_CSRCS += symtab_findorderedbyname.c symtab_findorderedbyvalue.c +ifeq ($(CONFIG_LIBC_EXECFUNCS),y) +BINFMT_CSRCS += binfmt_execsymtab.c +endif + # Add configured binary modules VPATH = diff --git a/binfmt/binfmt_execsymtab.c b/binfmt/binfmt_execsymtab.c new file mode 100644 index 0000000000..63fa14adb2 --- /dev/null +++ b/binfmt/binfmt_execsymtab.c @@ -0,0 +1,156 @@ +/**************************************************************************** + * binfmt/binfmt_execsymtab.c + * + * Copyright (C) 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 + +#ifdef CONFIG_LIBC_EXECFUNCS + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ +/* If CONFIG_LIBC_EXECFUNCS is defined in the configuration, then the + * following must also be defined: + */ + +#ifdef CONFIG_EXECFUNCS_HAVE_SYMTAB + /* Symbol table used by exec[l|v] */ + +# ifndef CONFIG_EXECFUNCS_SYMTAB +# error "CONFIG_EXECFUNCS_SYMTAB must be defined" +# endif + + /* Number of Symbols in the Table */ + +# ifndef CONFIG_EXECFUNCS_NSYMBOLS +# error "CONFIG_EXECFUNCS_NSYMBOLS must be defined" +# endif +#endif + +/**************************************************************************** + * Public Variables + ****************************************************************************/ + +#ifdef CONFIG_EXECFUNCS_HAVE_SYMTAB +extern const struct symtab_s CONFIG_EXECFUNCS_SYMTAB; +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef CONFIG_EXECFUNCS_HAVE_SYMTAB +static FAR const struct symtab_s *g_exec_symtab = &CONFIG_EXECFUNCS_SYMTAB; +static int g_exec_nsymbols = CONFIG_EXECFUNCS_NSYMBOLS; +#else +static FAR const struct symtab_s *g_exec_symtab; +static int g_exec_nsymbols; +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: exec_getsymtab + * + * Description: + * Get the current symbol table selection as an atomic operation. + * + * Input Parameters: + * symtab - The location to store the symbol table. + * nsymbols - The location to store the number of symbols in the symbol table. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void exec_getsymtab(FAR const struct symtab_s **symtab, FAR int *nsymbols) +{ + irqstate_t flags; + + DEBUGASSERT(symtab && nsymbols); + + /* Disable interrupts very briefly so that both the symbol table and its + * size are returned as a single atomic operation. + */ + + flags = irqsave(); + *symtab = g_exec_symtab; + *nsymbols = g_exec_nsymbols; + irqrestore(flags); +} + +/**************************************************************************** + * Name: exec_setsymtab + * + * Description: + * Select a new symbol table selection as an atomic operation. + * + * Input Parameters: + * symtab - The new symbol table. + * nsymbols - The number of symbols in the symbol table. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void exec_setsymtab(FAR const struct symtab_s *symtab, int nsymbols) +{ + irqstate_t flags; + + DEBUGASSERT(symtab); + + /* Disable interrupts very briefly so that both the symbol table and its + * size are set as a single atomic operation. + */ + + flags = irqsave(); + g_exec_symtab = symtab; + g_exec_nsymbols = nsymbols; + irqrestore(flags); +} + +#endif /* CONFIG_LIBC_EXECFUNCS */ \ No newline at end of file diff --git a/include/nuttx/binfmt/symtab.h b/include/nuttx/binfmt/symtab.h index 346c6099fd..c6cdeffe44 100644 --- a/include/nuttx/binfmt/symtab.h +++ b/include/nuttx/binfmt/symtab.h @@ -77,11 +77,46 @@ struct symtab_s #undef EXTERN #if defined(__cplusplus) #define EXTERN extern "C" -extern "C" { +extern "C" +{ #else #define EXTERN extern #endif +/**************************************************************************** + * Name: exec_getsymtab + * + * Description: + * Get the current symbol table selection as an atomic operation. + * + * Input Parameters: + * symtab - The location to store the symbol table. + * nsymbols - The location to store the number of symbols in the symbol table. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void exec_getsymtab(FAR const struct symtab_s **symtab, FAR int *nsymbols); + +/**************************************************************************** + * Name: exec_setsymtab + * + * Description: + * Select a new symbol table selection as an atomic operation. + * + * Input Parameters: + * symtab - The new symbol table. + * nsymbols - The number of symbols in the symbol table. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void exec_setsymtab(FAR const struct symtab_s *symtab, int nsymbols); + /**************************************************************************** * Name: symtab_findbyname * @@ -96,7 +131,7 @@ extern "C" { * ****************************************************************************/ -EXTERN FAR const struct symtab_s * +FAR const struct symtab_s * symtab_findbyname(FAR const struct symtab_s *symtab, FAR const char *name, int nsyms); @@ -113,7 +148,7 @@ symtab_findbyname(FAR const struct symtab_s *symtab, * ****************************************************************************/ -EXTERN FAR const struct symtab_s * +FAR const struct symtab_s * symtab_findorderedbyname(FAR const struct symtab_s *symtab, FAR const char *name, int nsyms); @@ -132,7 +167,7 @@ symtab_findorderedbyname(FAR const struct symtab_s *symtab, * ****************************************************************************/ -EXTERN FAR const struct symtab_s * +FAR const struct symtab_s * symtab_findbyvalue(FAR const struct symtab_s *symtab, FAR void *value, int nsyms); @@ -150,7 +185,7 @@ symtab_findbyvalue(FAR const struct symtab_s *symtab, * ****************************************************************************/ -EXTERN FAR const struct symtab_s * +FAR const struct symtab_s * symtab_findorderedbyvalue(FAR const struct symtab_s *symtab, FAR void *value, int nsyms); diff --git a/include/unistd.h b/include/unistd.h index 4dabdb35a3..abaf7230c4 100644 --- a/include/unistd.h +++ b/include/unistd.h @@ -173,12 +173,6 @@ int rmdir(FAR const char *pathname); #ifdef CONFIG_LIBC_EXECFUNCS int execl(FAR const char *path, ...); int execv(FAR const char *path, FAR char *const argv[]); - -/* Non-standard functions to manage symbol tables */ - -struct symtab_s; /* See include/nuttx/binfmt/symtab.h */ -void exec_getsymtab(FAR const struct symtab_s **symtab, FAR int *nsymbols); -void exec_setsymtab(FAR const struct symtab_s *symtab, int nsymbols); #endif /* Other */ diff --git a/libc/unistd/Make.defs b/libc/unistd/Make.defs index 69f371d8c0..323e0a3b8e 100644 --- a/libc/unistd/Make.defs +++ b/libc/unistd/Make.defs @@ -43,7 +43,7 @@ CSRCS += lib_chdir.c lib_getcwd.c endif ifeq ($(CONFIG_LIBC_EXECFUNCS),y) -CSRCS += lib_execl.c lib_execv.c lib_execsymtab.c +CSRCS += lib_execl.c endif endif diff --git a/sched/task/Make.defs b/sched/task/Make.defs index e393f9947b..5d0b093da6 100644 --- a/sched/task/Make.defs +++ b/sched/task/Make.defs @@ -51,7 +51,7 @@ endif ifneq ($(CONFIG_BINFMT_DISABLE),y) ifeq ($(CONFIG_LIBC_EXECFUNCS),y) -TSK_SRCS += task_posixspawn.c +TSK_SRCS += task_execv.c task_posixspawn.c endif endif diff --git a/sched/task/task_execv.c b/sched/task/task_execv.c new file mode 100644 index 0000000000..01d89f1393 --- /dev/null +++ b/sched/task/task_execv.c @@ -0,0 +1,153 @@ +/**************************************************************************** + * sched/task/lib_execv.c + * + * Copyright (C) 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 +#include + +#ifdef CONFIG_LIBC_EXECFUNCS + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Variables + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: execv + * + * Description: + * The standard 'exec' family of functions will replace the current process + * image with a new process image. The new image will be constructed from a + * regular, executable file called the new process image file. There will + * be no return from a successful exec, because the calling process image + * is overlaid by the new process image. + * + * Simplified 'execl()' and 'execv()' functions are provided by NuttX for + * compatibility. NuttX is a tiny embedded RTOS that does not support + * processes and hence the concept of overlaying a tasks process image with + * a new process image does not make any sense. In NuttX, these functions + * are wrapper functions that: + * + * 1. Call the non-standard binfmt function 'exec', and then + * 2. exit(0). + * + * Note the inefficiency when 'exec[l|v]()' is called in the normal, two- + * step process: (1) first call vfork() to create a new thread, then (2) + * call 'exec[l|v]()' to replace the new thread with a program from the + * file system. Since the new thread will be terminated by the + * 'exec[l|v]()' call, it really served no purpose other than to support + * Unix compatility. + * + * The non-standard binfmt function 'exec()' needs to have (1) a symbol + * table that provides the list of symbols exported by the base code, and + * (2) the number of symbols in that table. This information is currently + * provided to 'exec()' from 'exec[l|v]()' via NuttX configuration settings: + * + * CONFIG_LIBC_EXECFUNCS : Enable exec[l|v] support + * CONFIG_EXECFUNCS_HAVE_SYMTAB : Defined if there is a symbol table + * CONFIG_EXECFUNCS_SYMTAB : Symbol table used by exec[l|v] + * CONFIG_EXECFUNCS_NSYMBOLS : Number of symbols in the table + * + * As a result of the above, the current implementations of 'execl()' and + * 'execv()' suffer from some incompatibilities that may or may not be + * addressed in a future version of NuttX. Other than just being an + * inefficient use of MCU resource, the most serious of these is that + * the exec'ed task will not have the same task ID as the vfork'ed + * function. So the parent function cannot know the ID of the exec'ed + * task. + * + * Input Parameters: + * path - The path to the program to be executed. If CONFIG_BINFMT_EXEPATH + * is defined in the configuration, then this may be a relative path + * from the current working directory. Otherwise, path must be the + * absolute path to the program. + * argv - A pointer to an array of string arguments. The end of the + * array is indicated with a NULL entry. + * + * Returned Value: + * This function does not return on success. On failure, it will return + * -1 (ERROR) and will set the 'errno' value appropriately. + * + ****************************************************************************/ + +int execv(FAR const char *path, FAR char * const argv[]) +{ + FAR const struct symtab_s *symtab; + int nsymbols; + int ret; + + /* Get the current symbol table selection */ + + exec_getsymtab(&symtab, &nsymbols); + + /* Start the task */ + + ret = exec(path, (FAR char * const *)argv, symtab, nsymbols); + if (ret < 0) + { + sdbg("exec failed: %d\n", errno); + return ERROR; + } + + /* Then exit */ + + exit(0); + + /* We should not get here, but might be needed by some compilers. Other, + * smarter compilers might complain that this code is unreachable. You just + * can't win. + */ + + return ERROR; +} + +#endif /* CONFIG_LIBC_EXECFUNCS */