]> Zhao Yanbai Git Server - minix.git/commitdiff
cdecl calling convention requires to push arguments on the stack in a
authorLorenzo Cavallaro <lorenzo@minix3.org>
Tue, 30 Mar 2010 09:36:46 +0000 (09:36 +0000)
committerLorenzo Cavallaro <lorenzo@minix3.org>
Tue, 30 Mar 2010 09:36:46 +0000 (09:36 +0000)
reverse order to easily support variadic arguments. Thus, instead of
using the proper stdarg.h macros (that nowadays are
compiler-dependent), 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-dependent 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).

This patch fixes the issue by allowing ACK to take the shortcut and
enabling gcc/llvm-gcc to follow the right way.

include/minix/compiler-ack.h
include/minix/compiler.h
include/stdarg.h
lib/libc/posix/_execl.c
lib/libc/posix/_execle.c
lib/libc/posix/_execlp.c
lib/libc/posix/_execve.c
lib/libc/posix/_execvp.c

index a5ab4db10b2af41def816f404924f25a2ab717a6..cb6e035a5ce2f7aaf1a594aa9f5400be43a61e76 100644 (file)
@@ -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 */
index 25732d156c511637f08e3455550d5d730031654c..75b5d6350261eb6477a49bdeecf163c4a890d557 100644 (file)
@@ -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
 #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 */
index c5ea6b9f4621e909fbdb202d41fe8ca2147af848..40a4298f8229343b83f6e1c1c663c43c3d0b6e38 100644 (file)
@@ -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 */
 
index 4592d0731c3a452bc63eb9269c0967e27b95c704..9337e59ae637c552d3032c68b00e124934ad4298 100644 (file)
@@ -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 <unistd.h>
+#include <minix/compiler.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <alloca.h>
+#include <lib.h>
 
 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 *) &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.
         */
-       return execve(path, (char * const *) &arg1, *_penviron);
+       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
 }
+
index 10a814dcc64519199f794eb5426956417a8929f9..bb9fe198748098255f73aab5ca2f1048f1d92365 100644 (file)
@@ -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 <unistd.h>
+#include <minix/compiler.h>
+#include <errno.h>
 #include <stdarg.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <alloca.h>
+#include <lib.h>
 
 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
 }
index 73dfdc389a7ad51fae49d768e6da784a691b8e34..4d3daefd03f34e35b60e866d53c8b0e1bed109c8 100644 (file)
@@ -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 <unistd.h>
+#include <minix/compiler.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <alloca.h>
+#include <lib.h>
 
 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
 }
index 3a5b6c1069921beedf70d8d6dc588b290ec7eac1..4b2ec05ff80642814d15357ba449c52854679a7b 100644 (file)
@@ -4,7 +4,6 @@
 
 #define _MINIX_SOURCE
 
-#define nil 0
 #define execve _execve
 #define sbrk _sbrk
 #include <lib.h>
@@ -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;
index 14b768b1d714b4076efbee3f360ea646ff2ab1b8..fecb08088334bd0847e6d97b079de500bca2591e 100644 (file)
@@ -5,7 +5,6 @@
 
 #define _MINIX_SOURCE
 
-#define nil 0
 #define execve _execve
 #define execvp _execvp
 #define sbrk _sbrk
@@ -15,6 +14,7 @@
 #include <unistd.h>
 #include <errno.h>
 #include <sys/stat.h>
+#include <lib.h>
 
 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. */