diff --git a/include/minix/compiler-ack.h b/include/minix/compiler-ack.h index a5ab4db10..cb6e035a5 100644 --- a/include/minix/compiler-ack.h +++ b/include/minix/compiler-ack.h @@ -6,4 +6,15 @@ /* ACK expects the caller to pop the hidden pointer on struct return. */ #define BYTES_TO_POP_ON_STRUCT_RETURN +/* + * ACK doesn't move the last argument of a variadic arguments function + * anywhere, once it's on the stack as a function parameter. Thus, it is + * possible to make strong assumption on the immutability of the stack + * layout and use the address of that argument as the start of an array. + * + * If you're curious, just look at lib/libc/posix/_execl*.c ;-) + */ + +#define FUNC_ARGS_ARRAY 1 + #endif /* _MINIX_COMPILER_ACK_H */ diff --git a/include/minix/compiler.h b/include/minix/compiler.h index 25732d156..75b5d6350 100644 --- a/include/minix/compiler.h +++ b/include/minix/compiler.h @@ -4,7 +4,7 @@ #define _MINIX_COMPILER_H /*===========================================================================* - * Compiler overrides * + * Compiler overrides * *===========================================================================*/ /* ACK */ #ifdef __ACK__ @@ -12,7 +12,7 @@ #endif /*===========================================================================* - * Default values * + * Default values * *===========================================================================*/ /* * cdecl calling convention expects the callee to pop the hidden pointer on @@ -22,4 +22,28 @@ #define BYTES_TO_POP_ON_STRUCT_RETURN $4 #endif +/* + * cdecl calling convention requires to push arguments on the stack in a + * reverse order to easily support variadic arguments. Thus, instead of + * using the proper stdarg.h macros (that nowadays are + * compiler-dependant), it may be tempting to directly take the address of + * the last argument and considering it as the start of an array. This is + * a shortcut that avoid looping to get all the arguments as the CPU + * already pushed them on the stack before the call to the function. + * + * Unfortunately, such an assumption is strictly compiler-dependant and + * compilers are free to move the last argument on the stack, as a local + * variable, and return the address of the location where the argument was + * stored, if asked for. This will break things as the rest of the array's + * argument are stored elsewhere (typically, a couple of words above the + * location where the argument was stored). + * + * Conclusion: if unsure on what the compiler may do, do not make any + * assumption and use the right (typically compiler-dependant) macros. + */ + +#ifndef FUNC_ARGS_ARRAY +#define FUNC_ARGS_ARRAY 0 +#endif + #endif /* _MINIX_COMPILER_H */ diff --git a/include/stdarg.h b/include/stdarg.h index c5ea6b9f4..40a4298f8 100644 --- a/include/stdarg.h +++ b/include/stdarg.h @@ -53,20 +53,10 @@ void va_end (va_list); /* Defined in gnulib */ #else /* __GNUC__ >= 2 */ -#ifndef __sparc__ -#define va_start(AP, LASTARG) \ - (AP = ((char *) __builtin_next_arg ())) -#else -#define va_start(AP, LASTARG) \ - (__builtin_saveregs (), AP = ((char *) __builtin_next_arg ())) -#endif - -void va_end (va_list); /* Defined in libgcc.a */ -#define va_end(AP) - -#define va_arg(AP, TYPE) \ - (AP = ((char *) (AP)) += __va_rounded_size (TYPE), \ - *((TYPE *) ((char *) (AP) - __va_rounded_size (TYPE)))) +#define va_start(ap, last) __builtin_va_start((ap), (last)) +#define va_arg(ap, type) __builtin_va_arg((ap), type) +#define va_end(ap) __builtin_va_end(ap) +#define va_copy(dest, src) __builtin_va_copy((dest), (src)) #endif /* __GNUC__ >= 2 */ diff --git a/lib/libc/posix/_execl.c b/lib/libc/posix/_execl.c index 4592d0731..9337e59ae 100644 --- a/lib/libc/posix/_execl.c +++ b/lib/libc/posix/_execl.c @@ -1,18 +1,85 @@ -/* execl() - execute Author: Kees J. Bot - * 21 Jan 1994 +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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 of the University 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 REGENTS 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 REGENTS 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. */ + #define execl _execl #define execve _execve #include +#include +#include +#include +#include +#include +#include +#include extern char * const **_penviron; /* The default environment. */ -int execl(const char *path, const char *arg1, ...) +int +execl(const char *path, const char *arg, ...) /* execl("/bin/sh", "sh", "-c", "example", (char *) 0); */ { - /* Assumption: The C-implementation for this machine pushes +#if FUNC_ARGS_ARRAY + /* + * Assumption: The C-implementation for this machine pushes * function arguments downwards on the stack making a perfect * argument array. Luckily this is almost always so. + * + * execl() - execute Author: Kees J. Bot, 21 Jan 1994 */ - return execve(path, (char * const *) &arg1, *_penviron); + return execve(path, (char * const *) &arg, *_penviron); +#else + /* + * Indeed, GCC (4.4.1) behaves similarly to ACK. Nonetheless, let's + * stay the safe side. LLVM (llvm-gcc) doesn't make the aforementioned + * assumption. + */ + va_list ap; + char **argv; + int i; + + va_start(ap, arg); + for (i = 2; va_arg(ap, char *) != NULL; i++) + continue; + va_end(ap); + + if ((argv = alloca(i * sizeof (char *))) == NULL) { + errno = ENOMEM; + return -1; + } + + va_start(ap, arg); + argv[0] = __UNCONST(arg); + for (i = 1; (argv[i] = va_arg(ap, char *)) != NULL; i++) + continue; + va_end(ap); + + return execve(path, (char * const *) argv, *_penviron); +#endif } + diff --git a/lib/libc/posix/_execle.c b/lib/libc/posix/_execle.c index 10a814dcc..bb9fe1987 100644 --- a/lib/libc/posix/_execle.c +++ b/lib/libc/posix/_execle.c @@ -1,25 +1,83 @@ -/* execle() - execute with a custom environment Author: Kees J. Bot - * 21 Jan 1994 +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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 of the University 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 REGENTS 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 REGENTS 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. */ -#define nil 0 + #define execle _execle #define execve _execve #include +#include +#include #include +#include +#include +#include +#include int execle(const char *path, const char *arg1, ...) /* execle("/bin/sh", "sh", "-c", "example", (char *) 0, my_env_array); */ { - char * const * envp; - va_list ap; - + char * const * envp; + va_list ap; +#if FUNC_ARGS_ARRAY + /* + * execle() - execute with a custom environment + * Author: Kees J. Bot, 21 Jan 1994 + */ va_start(ap, arg1); /* Find the end of the argument array. */ - if (arg1 != nil) while (va_arg(ap, const char *) != nil) {} + if (arg1 != NULL) while (va_arg(ap, const char *) != NULL) {} envp = va_arg(ap, char * const *); va_end(ap); return execve(path, (char * const *) &arg1, envp); +#else + char **argv; + int i; + + va_start(ap, arg1); + for (i = 2; va_arg(ap, char *) != NULL; i++) + continue; + va_end(ap); + + if ((argv = alloca(i * sizeof (char *))) == NULL) { + errno = ENOMEM; + return -1; + } + + va_start(ap, arg1); + argv[0] = __UNCONST(arg1); + for (i = 1; (argv[i] = va_arg(ap, char *)) != NULL; i++) + continue; + envp = va_arg(ap, char **); + va_end(ap); + + return execve(path, (char * const *)argv, envp); +#endif } diff --git a/lib/libc/posix/_execlp.c b/lib/libc/posix/_execlp.c index 73dfdc389..4d3daefd0 100644 --- a/lib/libc/posix/_execlp.c +++ b/lib/libc/posix/_execlp.c @@ -1,12 +1,73 @@ -/* execlp() - execute with PATH search Author: Kees J. Bot - * 22 Jan 1994 +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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 of the University 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 REGENTS 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 REGENTS 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. */ + #define execlp _execlp #define execvp _execvp #include +#include +#include +#include +#include +#include +#include +#include int execlp(const char *file, const char *arg1, ...) /* execlp("sh", "sh", "-c", "example", (char *) 0); */ { +#if FUNC_ARGS_ARRAY + /* + * execlp() - execute with PATH search + * Author: Kees J. Bot, 22 Jan 1994 + */ return execvp(file, (char * const *) &arg1); +#else + va_list ap; + char **argv; + int i; + + va_start(ap, arg1); + for (i = 2; va_arg(ap, char *) != NULL; i++) + continue; + va_end(ap); + + if ((argv = alloca(i * sizeof (char *))) == NULL) { + errno = ENOMEM; + return -1; + } + + va_start(ap, arg1); + argv[0] = __UNCONST(arg1); + for (i = 1; (argv[i] = va_arg(ap, char *)) != NULL; i++) + continue; + va_end(ap); + + return execvp(file, (char * const *)argv); +#endif } diff --git a/lib/libc/posix/_execve.c b/lib/libc/posix/_execve.c index 3a5b6c106..4b2ec05ff 100644 --- a/lib/libc/posix/_execve.c +++ b/lib/libc/posix/_execve.c @@ -4,7 +4,6 @@ #define _MINIX_SOURCE -#define nil 0 #define execve _execve #define sbrk _sbrk #include @@ -37,7 +36,7 @@ int execve(const char *path, char * const *argv, char * const *envp) string_off= 0; /* Offset to start of the strings. */ argc= 0; /* Argument count. */ - for (ap= argv; *ap != nil; ap++) { + for (ap= argv; *ap != NULL; ap++) { n = sizeof(*ap) + strlen(*ap) + 1; frame_size+= n; if (frame_size < n) ov= 1; @@ -45,7 +44,7 @@ int execve(const char *path, char * const *argv, char * const *envp) argc++; } - for (ep= envp; *ep != nil; ep++) { + for (ep= envp; *ep != NULL; ep++) { n = sizeof(*ep) + strlen(*ep) + 1; frame_size+= n; if (frame_size < n) ov= 1; @@ -77,22 +76,22 @@ int execve(const char *path, char * const *argv, char * const *envp) sp = frame + string_off; /* Load the argument vector and strings. */ - for (ap= argv; *ap != nil; ap++) { + for (ap= argv; *ap != NULL; ap++) { *vp++= (char *) (sp - frame); n= strlen(*ap) + 1; memcpy(sp, *ap, n); sp+= n; } - *vp++= nil; + *vp++= NULL; /* Load the environment vector and strings. */ - for (ep= envp; *ep != nil; ep++) { + for (ep= envp; *ep != NULL; ep++) { *vp++= (char *) (sp - frame); n= strlen(*ep) + 1; memcpy(sp, *ep, n); sp+= n; } - *vp++= nil; + *vp++= NULL; /* Padding. */ while (sp < frame + frame_size) *sp++= 0; diff --git a/lib/libc/posix/_execvp.c b/lib/libc/posix/_execvp.c index 14b768b1d..fecb08088 100644 --- a/lib/libc/posix/_execvp.c +++ b/lib/libc/posix/_execvp.c @@ -5,7 +5,6 @@ #define _MINIX_SOURCE -#define nil 0 #define execve _execve #define execvp _execvp #define sbrk _sbrk @@ -15,6 +14,7 @@ #include #include #include +#include extern char * const **_penviron; /* The default environment. */ @@ -33,7 +33,7 @@ int execvp(const char *file, char * const *argv) size_t full_size; int err= ENOENT; /* Error return on failure. */ - if (strchr(file, '/') != nil || (path= getenv("PATH")) == nil) + if (strchr(file, '/') != NULL || (path= getenv("PATH")) == NULL) path= ""; /* Compute the maximum length the full name may have, and align. */