xref: /minix3/minix/lib/libc/sys/stack_utils.c (revision 20054ae93f6e47654fed4974be64f313fdd85de6)
1433d6423SLionel Sambuc /* Utilities to generate a proper C stack.
2433d6423SLionel Sambuc  *
3433d6423SLionel Sambuc  * Author: Lionel A. Sambuc.
4433d6423SLionel Sambuc  */
5433d6423SLionel Sambuc 
6433d6423SLionel Sambuc #define _MINIX_SYSTEM
7433d6423SLionel Sambuc 
8433d6423SLionel Sambuc #include <sys/cdefs.h>
9433d6423SLionel Sambuc #include "namespace.h"
10433d6423SLionel Sambuc #include <lib.h>
11433d6423SLionel Sambuc 
12433d6423SLionel Sambuc #include <unistd.h>
13433d6423SLionel Sambuc #include <string.h>
14433d6423SLionel Sambuc #include <stddef.h>
15433d6423SLionel Sambuc #include <sys/exec_elf.h>
16433d6423SLionel Sambuc #include <sys/exec.h>
17433d6423SLionel Sambuc 
18433d6423SLionel Sambuc /* Create a stack image that only needs to be patched up slightly by
19433d6423SLionel Sambuc  * the kernel to be used for the process to be executed.
20433d6423SLionel Sambuc  *
21433d6423SLionel Sambuc  * Every pointers are stored here as offset from the frame base, and
22433d6423SLionel Sambuc  * will be adapted as required for the new process address space.
23433d6423SLionel Sambuc  *
24433d6423SLionel Sambuc  * The following parameters are passed by register to either __start
25433d6423SLionel Sambuc  * for static binaries, or _rtld_start for dynamic ones:
26433d6423SLionel Sambuc  *     *fct, *ObjEntry, *ps_string
27433d6423SLionel Sambuc  *
28433d6423SLionel Sambuc  * The following stack layout is expected by _rtld():
29433d6423SLionel Sambuc  *
30433d6423SLionel Sambuc  * | XXXXXXXXXX | 0x0000_00000
31433d6423SLionel Sambuc  * |  ...       |
32433d6423SLionel Sambuc  * |  ...       | Top of the stack
33433d6423SLionel Sambuc  * | argc       |
34433d6423SLionel Sambuc  * | *argv1     | points to the first char of the argv1
35433d6423SLionel Sambuc  * |  ...       |
36433d6423SLionel Sambuc  * | *argvN     |
37433d6423SLionel Sambuc  * | NULL       |
38433d6423SLionel Sambuc  * | *env1      |
39433d6423SLionel Sambuc  * |  ...       |
40433d6423SLionel Sambuc  * | *envN      |
41433d6423SLionel Sambuc  * | NULL       |
42433d6423SLionel Sambuc  * | ElfAuxV1   |
43433d6423SLionel Sambuc  * |  ...       |
44433d6423SLionel Sambuc  * | ElfAuxVX   |
45433d6423SLionel Sambuc  * | AuxExecName| fully resolve executable name, as an ASCIIZ string,
46433d6423SLionel Sambuc  *                at most PMEF_EXECNAMELEN1 long.
47433d6423SLionel Sambuc  *
48433d6423SLionel Sambuc  * Here we put first the strings, then word-align, then ps_strings, to
49433d6423SLionel Sambuc  * comply with the expected layout of NetBSD. This seems to matter for
50433d6423SLionel Sambuc  * the NetBSD ps command, so let's make sure we are compatible...
51433d6423SLionel Sambuc  *
52433d6423SLionel Sambuc  * | strings    | Maybe followed by some padding to word-align.
53433d6423SLionel Sambuc  * | **argv     | \
54433d6423SLionel Sambuc  * | argc       |  +---> ps_string structure content.
55433d6423SLionel Sambuc  * | **env      |  |
56433d6423SLionel Sambuc  * | envc       | /
57433d6423SLionel Sambuc  * | sigcode    | On NetBSD, there may be a compatibility stub here,
58433d6423SLionel Sambuc  * +------------+    for native code, it is not present.
59433d6423SLionel Sambuc  *   Stack Base , 0xF000_0000, descending stack.
60433d6423SLionel Sambuc  */
61433d6423SLionel Sambuc 
62433d6423SLionel Sambuc /* The minimum size of the frame is composed of:
63433d6423SLionel Sambuc  * argc, the NULL terminator for argv as well as one for
64433d6423SLionel Sambuc  * environ, the ELF Aux vectors, executable name and the
65433d6423SLionel Sambuc  * ps_strings struct. */
66433d6423SLionel Sambuc #define STACK_MIN_SZ \
67433d6423SLionel Sambuc ( \
68433d6423SLionel Sambuc 	sizeof(int) + sizeof(void *) * 2 + \
69433d6423SLionel Sambuc 	sizeof(AuxInfo) * PMEF_AUXVECTORS + PMEF_EXECNAMELEN1 + \
70433d6423SLionel Sambuc 	sizeof(struct ps_strings) \
71433d6423SLionel Sambuc )
72433d6423SLionel Sambuc 
73433d6423SLionel Sambuc /*****************************************************************************
74433d6423SLionel Sambuc  * Computes stack size, argc, envc, for a given set of path, argv, envp.     *
75433d6423SLionel Sambuc  *****************************************************************************/
minix_stack_params(const char * path,char * const * argv,char * const * envp,size_t * stack_size,char * overflow,int * argc,int * envc)76433d6423SLionel Sambuc void minix_stack_params(const char *path, char * const *argv, char * const *envp,
77433d6423SLionel Sambuc 	size_t *stack_size,  char *overflow, int *argc, int *envc)
78433d6423SLionel Sambuc {
79433d6423SLionel Sambuc 	char * const *p;
80433d6423SLionel Sambuc 	size_t const min_size = STACK_MIN_SZ;
81433d6423SLionel Sambuc 
82433d6423SLionel Sambuc 	*stack_size = min_size;	/* Size of the new initial stack. */
83433d6423SLionel Sambuc 	*overflow = 0;		/* No overflow yet. */
84433d6423SLionel Sambuc 	*argc = 0;		/* Argument count. */
85433d6423SLionel Sambuc 	*envc = 0;		/* Environment count */
86433d6423SLionel Sambuc 
87433d6423SLionel Sambuc 	/* Compute and add the size required to store argv and env. */
88433d6423SLionel Sambuc 	for (p = argv; *p != NULL; p++) {
89433d6423SLionel Sambuc 		size_t const n = sizeof(*p) + strlen(*p) + 1;
90433d6423SLionel Sambuc 		*stack_size += n;
91433d6423SLionel Sambuc 		if (*stack_size < n) {
92433d6423SLionel Sambuc 			*overflow = 1;
93433d6423SLionel Sambuc 		}
94433d6423SLionel Sambuc 		(*argc)++;
95433d6423SLionel Sambuc 	}
96433d6423SLionel Sambuc 
97433d6423SLionel Sambuc 	for (p = envp; p && *p != NULL; p++) {
98433d6423SLionel Sambuc 		size_t const n = sizeof(*p) + strlen(*p) + 1;
99433d6423SLionel Sambuc 		*stack_size += n;
100433d6423SLionel Sambuc 		if (*stack_size < n) {
101433d6423SLionel Sambuc 			*overflow = 1;
102433d6423SLionel Sambuc 		}
103433d6423SLionel Sambuc 		(*envc)++;
104433d6423SLionel Sambuc 	}
105433d6423SLionel Sambuc 
106433d6423SLionel Sambuc 	/* Compute the aligned frame size. */
107433d6423SLionel Sambuc 	*stack_size = (*stack_size + sizeof(void *) - 1) &
108433d6423SLionel Sambuc 		 ~(sizeof(void *) - 1);
109433d6423SLionel Sambuc 
110433d6423SLionel Sambuc 	if (*stack_size < min_size) {
111433d6423SLionel Sambuc 		/* This is possible only in case of overflow. */
112433d6423SLionel Sambuc 		*overflow = 1;
113433d6423SLionel Sambuc 	}
114433d6423SLionel Sambuc }
115433d6423SLionel Sambuc 
116433d6423SLionel Sambuc /*****************************************************************************
117433d6423SLionel Sambuc  * Generate a stack in the buffer frame, ready to be used.                   *
118433d6423SLionel Sambuc  *****************************************************************************/
minix_stack_fill(const char * path,int argc,char * const * argv,int envc,char * const * envp,size_t stack_size,char * frame,int * vsp,struct ps_strings ** psp)119433d6423SLionel Sambuc void minix_stack_fill(const char *path, int argc, char * const *argv,
120433d6423SLionel Sambuc 	int envc, char * const *envp, size_t stack_size, char *frame,
121433d6423SLionel Sambuc 	int *vsp, struct ps_strings **psp)
122433d6423SLionel Sambuc {
123433d6423SLionel Sambuc 	char * const *p;
124433d6423SLionel Sambuc 
125433d6423SLionel Sambuc 	/* Frame pointers (a.k.a stack pointer within the buffer in current
126433d6423SLionel Sambuc 	 * address space.) */
127433d6423SLionel Sambuc 	char *fp;	/* byte aligned */
128433d6423SLionel Sambuc 	char **fpw;	/* word aligned */
129433d6423SLionel Sambuc 
130433d6423SLionel Sambuc 	size_t const min_size = STACK_MIN_SZ;
131433d6423SLionel Sambuc 
132433d6423SLionel Sambuc 	/* Virtual address of the stack pointer, in new memory space. */
133*20054ae9SDavid van Moolenbroek 	*vsp = minix_get_user_sp() - stack_size;
134433d6423SLionel Sambuc 
135433d6423SLionel Sambuc 	/* Fill in the frame now. */
136433d6423SLionel Sambuc 	fpw = (char **) frame;
137433d6423SLionel Sambuc 	*fpw++ = (char *) argc;
138433d6423SLionel Sambuc 
139433d6423SLionel Sambuc 	/* The strings themselves are stored after the aux vectors,
140433d6423SLionel Sambuc 	 * cf. top comment. */
141433d6423SLionel Sambuc 	fp = frame + (min_size - sizeof(struct ps_strings)) +
142433d6423SLionel Sambuc 		(envc + argc) * sizeof(char *);
143433d6423SLionel Sambuc 
144433d6423SLionel Sambuc 	/* Fill in argv and the environment, as well as copy the strings
145433d6423SLionel Sambuc 	 * themselves. */
146433d6423SLionel Sambuc 	for (p = argv; *p != NULL; p++) {
147433d6423SLionel Sambuc 		size_t const n = strlen(*p) + 1;
148433d6423SLionel Sambuc 		*fpw++= (char *)(*vsp + (fp - frame));
149433d6423SLionel Sambuc 		memcpy(fp, *p, n);
150433d6423SLionel Sambuc 		fp += n;
151433d6423SLionel Sambuc 	}
152433d6423SLionel Sambuc 	*fpw++ = NULL;
153433d6423SLionel Sambuc 
154433d6423SLionel Sambuc 	for (p = envp; p && *p != NULL; p++) {
155433d6423SLionel Sambuc 		size_t const n = strlen(*p) + 1;
156433d6423SLionel Sambuc 		*fpw++= (char *)(*vsp + (fp - frame));
157433d6423SLionel Sambuc 		memcpy(fp, *p, n);
158433d6423SLionel Sambuc 		fp += n;
159433d6423SLionel Sambuc 	}
160433d6423SLionel Sambuc 	*fpw++ = NULL;
161433d6423SLionel Sambuc 
162433d6423SLionel Sambuc 	/* Padding, because of the stack alignement. */
163433d6423SLionel Sambuc 	while ((size_t)fp % sizeof(void *)) *fp++= 0;
164433d6423SLionel Sambuc 
165433d6423SLionel Sambuc 	/* Fill in the ps_string struct*/
166433d6423SLionel Sambuc 	*psp = (struct ps_strings *) fp;
167433d6423SLionel Sambuc 
168433d6423SLionel Sambuc 	(*psp)->ps_argvstr = (char **)(*vsp + sizeof(argc));
169433d6423SLionel Sambuc 	(*psp)->ps_nargvstr = argc;
170433d6423SLionel Sambuc 	(*psp)->ps_envstr = (*psp)->ps_argvstr + argc + 1;
171433d6423SLionel Sambuc 	(*psp)->ps_nenvstr = envc;
172433d6423SLionel Sambuc }
173