xref: /minix3/minix/lib/libc/sys/stack_utils.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
1*433d6423SLionel Sambuc /* Utilities to generate a proper C stack.
2*433d6423SLionel Sambuc  *
3*433d6423SLionel Sambuc  * Author: Lionel A. Sambuc.
4*433d6423SLionel Sambuc  */
5*433d6423SLionel Sambuc 
6*433d6423SLionel Sambuc #define _MINIX_SYSTEM
7*433d6423SLionel Sambuc 
8*433d6423SLionel Sambuc #include <sys/cdefs.h>
9*433d6423SLionel Sambuc #include "namespace.h"
10*433d6423SLionel Sambuc #include <lib.h>
11*433d6423SLionel Sambuc 
12*433d6423SLionel Sambuc #include <unistd.h>
13*433d6423SLionel Sambuc #include <string.h>
14*433d6423SLionel Sambuc #include <stddef.h>
15*433d6423SLionel Sambuc #include <minix/param.h>
16*433d6423SLionel Sambuc #include <sys/exec_elf.h>
17*433d6423SLionel Sambuc #include <sys/exec.h>
18*433d6423SLionel Sambuc 
19*433d6423SLionel Sambuc extern struct minix_kerninfo *_minix_kerninfo;
20*433d6423SLionel Sambuc 
21*433d6423SLionel Sambuc /* Create a stack image that only needs to be patched up slightly by
22*433d6423SLionel Sambuc  * the kernel to be used for the process to be executed.
23*433d6423SLionel Sambuc  *
24*433d6423SLionel Sambuc  * Every pointers are stored here as offset from the frame base, and
25*433d6423SLionel Sambuc  * will be adapted as required for the new process address space.
26*433d6423SLionel Sambuc  *
27*433d6423SLionel Sambuc  * The following parameters are passed by register to either __start
28*433d6423SLionel Sambuc  * for static binaries, or _rtld_start for dynamic ones:
29*433d6423SLionel Sambuc  *     *fct, *ObjEntry, *ps_string
30*433d6423SLionel Sambuc  *
31*433d6423SLionel Sambuc  * The following stack layout is expected by _rtld():
32*433d6423SLionel Sambuc  *
33*433d6423SLionel Sambuc  * | XXXXXXXXXX | 0x0000_00000
34*433d6423SLionel Sambuc  * |  ...       |
35*433d6423SLionel Sambuc  * |  ...       | Top of the stack
36*433d6423SLionel Sambuc  * | argc       |
37*433d6423SLionel Sambuc  * | *argv1     | points to the first char of the argv1
38*433d6423SLionel Sambuc  * |  ...       |
39*433d6423SLionel Sambuc  * | *argvN     |
40*433d6423SLionel Sambuc  * | NULL       |
41*433d6423SLionel Sambuc  * | *env1      |
42*433d6423SLionel Sambuc  * |  ...       |
43*433d6423SLionel Sambuc  * | *envN      |
44*433d6423SLionel Sambuc  * | NULL       |
45*433d6423SLionel Sambuc  * | ElfAuxV1   |
46*433d6423SLionel Sambuc  * |  ...       |
47*433d6423SLionel Sambuc  * | ElfAuxVX   |
48*433d6423SLionel Sambuc  * | AuxExecName| fully resolve executable name, as an ASCIIZ string,
49*433d6423SLionel Sambuc  *                at most PMEF_EXECNAMELEN1 long.
50*433d6423SLionel Sambuc  *
51*433d6423SLionel Sambuc  * Here we put first the strings, then word-align, then ps_strings, to
52*433d6423SLionel Sambuc  * comply with the expected layout of NetBSD. This seems to matter for
53*433d6423SLionel Sambuc  * the NetBSD ps command, so let's make sure we are compatible...
54*433d6423SLionel Sambuc  *
55*433d6423SLionel Sambuc  * | strings    | Maybe followed by some padding to word-align.
56*433d6423SLionel Sambuc  * | **argv     | \
57*433d6423SLionel Sambuc  * | argc       |  +---> ps_string structure content.
58*433d6423SLionel Sambuc  * | **env      |  |
59*433d6423SLionel Sambuc  * | envc       | /
60*433d6423SLionel Sambuc  * | sigcode    | On NetBSD, there may be a compatibility stub here,
61*433d6423SLionel Sambuc  * +------------+    for native code, it is not present.
62*433d6423SLionel Sambuc  *   Stack Base , 0xF000_0000, descending stack.
63*433d6423SLionel Sambuc  */
64*433d6423SLionel Sambuc 
65*433d6423SLionel Sambuc /* The minimum size of the frame is composed of:
66*433d6423SLionel Sambuc  * argc, the NULL terminator for argv as well as one for
67*433d6423SLionel Sambuc  * environ, the ELF Aux vectors, executable name and the
68*433d6423SLionel Sambuc  * ps_strings struct. */
69*433d6423SLionel Sambuc #define STACK_MIN_SZ \
70*433d6423SLionel Sambuc ( \
71*433d6423SLionel Sambuc 	sizeof(int) + sizeof(void *) * 2 + \
72*433d6423SLionel Sambuc 	sizeof(AuxInfo) * PMEF_AUXVECTORS + PMEF_EXECNAMELEN1 + \
73*433d6423SLionel Sambuc 	sizeof(struct ps_strings) \
74*433d6423SLionel Sambuc )
75*433d6423SLionel Sambuc 
76*433d6423SLionel Sambuc /*****************************************************************************
77*433d6423SLionel Sambuc  * Computes stack size, argc, envc, for a given set of path, argv, envp.     *
78*433d6423SLionel Sambuc  *****************************************************************************/
79*433d6423SLionel Sambuc void minix_stack_params(const char *path, char * const *argv, char * const *envp,
80*433d6423SLionel Sambuc 	size_t *stack_size,  char *overflow, int *argc, int *envc)
81*433d6423SLionel Sambuc {
82*433d6423SLionel Sambuc 	char * const *p;
83*433d6423SLionel Sambuc 	size_t const min_size = STACK_MIN_SZ;
84*433d6423SLionel Sambuc 
85*433d6423SLionel Sambuc 	*stack_size = min_size;	/* Size of the new initial stack. */
86*433d6423SLionel Sambuc 	*overflow = 0;		/* No overflow yet. */
87*433d6423SLionel Sambuc 	*argc = 0;		/* Argument count. */
88*433d6423SLionel Sambuc 	*envc = 0;		/* Environment count */
89*433d6423SLionel Sambuc 
90*433d6423SLionel Sambuc 	/* Compute and add the size required to store argv and env. */
91*433d6423SLionel Sambuc 	for (p = argv; *p != NULL; p++) {
92*433d6423SLionel Sambuc 		size_t const n = sizeof(*p) + strlen(*p) + 1;
93*433d6423SLionel Sambuc 		*stack_size += n;
94*433d6423SLionel Sambuc 		if (*stack_size < n) {
95*433d6423SLionel Sambuc 			*overflow = 1;
96*433d6423SLionel Sambuc 		}
97*433d6423SLionel Sambuc 		(*argc)++;
98*433d6423SLionel Sambuc 	}
99*433d6423SLionel Sambuc 
100*433d6423SLionel Sambuc 	for (p = envp; p && *p != NULL; p++) {
101*433d6423SLionel Sambuc 		size_t const n = sizeof(*p) + strlen(*p) + 1;
102*433d6423SLionel Sambuc 		*stack_size += n;
103*433d6423SLionel Sambuc 		if (*stack_size < n) {
104*433d6423SLionel Sambuc 			*overflow = 1;
105*433d6423SLionel Sambuc 		}
106*433d6423SLionel Sambuc 		(*envc)++;
107*433d6423SLionel Sambuc 	}
108*433d6423SLionel Sambuc 
109*433d6423SLionel Sambuc 	/* Compute the aligned frame size. */
110*433d6423SLionel Sambuc 	*stack_size = (*stack_size + sizeof(void *) - 1) &
111*433d6423SLionel Sambuc 		 ~(sizeof(void *) - 1);
112*433d6423SLionel Sambuc 
113*433d6423SLionel Sambuc 	if (*stack_size < min_size) {
114*433d6423SLionel Sambuc 		/* This is possible only in case of overflow. */
115*433d6423SLionel Sambuc 		*overflow = 1;
116*433d6423SLionel Sambuc 	}
117*433d6423SLionel Sambuc }
118*433d6423SLionel Sambuc 
119*433d6423SLionel Sambuc /*****************************************************************************
120*433d6423SLionel Sambuc  * Generate a stack in the buffer frame, ready to be used.                   *
121*433d6423SLionel Sambuc  *****************************************************************************/
122*433d6423SLionel Sambuc void minix_stack_fill(const char *path, int argc, char * const *argv,
123*433d6423SLionel Sambuc 	int envc, char * const *envp, size_t stack_size, char *frame,
124*433d6423SLionel Sambuc 	int *vsp, struct ps_strings **psp)
125*433d6423SLionel Sambuc {
126*433d6423SLionel Sambuc 	char * const *p;
127*433d6423SLionel Sambuc 
128*433d6423SLionel Sambuc 	/* Frame pointers (a.k.a stack pointer within the buffer in current
129*433d6423SLionel Sambuc 	 * address space.) */
130*433d6423SLionel Sambuc 	char *fp;	/* byte aligned */
131*433d6423SLionel Sambuc 	char **fpw;	/* word aligned */
132*433d6423SLionel Sambuc 
133*433d6423SLionel Sambuc 	size_t const min_size = STACK_MIN_SZ;
134*433d6423SLionel Sambuc 
135*433d6423SLionel Sambuc 	/* Virtual address of the stack pointer, in new memory space. */
136*433d6423SLionel Sambuc 	*vsp = _minix_kerninfo->kinfo->user_sp - stack_size;
137*433d6423SLionel Sambuc 
138*433d6423SLionel Sambuc 	/* Fill in the frame now. */
139*433d6423SLionel Sambuc 	fpw = (char **) frame;
140*433d6423SLionel Sambuc 	*fpw++ = (char *) argc;
141*433d6423SLionel Sambuc 
142*433d6423SLionel Sambuc 	/* The strings themselves are stored after the aux vectors,
143*433d6423SLionel Sambuc 	 * cf. top comment. */
144*433d6423SLionel Sambuc 	fp = frame + (min_size - sizeof(struct ps_strings)) +
145*433d6423SLionel Sambuc 		(envc + argc) * sizeof(char *);
146*433d6423SLionel Sambuc 
147*433d6423SLionel Sambuc 	/* Fill in argv and the environment, as well as copy the strings
148*433d6423SLionel Sambuc 	 * themselves. */
149*433d6423SLionel Sambuc 	for (p = argv; *p != NULL; p++) {
150*433d6423SLionel Sambuc 		size_t const n = strlen(*p) + 1;
151*433d6423SLionel Sambuc 		*fpw++= (char *)(*vsp + (fp - frame));
152*433d6423SLionel Sambuc 		memcpy(fp, *p, n);
153*433d6423SLionel Sambuc 		fp += n;
154*433d6423SLionel Sambuc 	}
155*433d6423SLionel Sambuc 	*fpw++ = NULL;
156*433d6423SLionel Sambuc 
157*433d6423SLionel Sambuc 	for (p = envp; p && *p != NULL; p++) {
158*433d6423SLionel Sambuc 		size_t const n = strlen(*p) + 1;
159*433d6423SLionel Sambuc 		*fpw++= (char *)(*vsp + (fp - frame));
160*433d6423SLionel Sambuc 		memcpy(fp, *p, n);
161*433d6423SLionel Sambuc 		fp += n;
162*433d6423SLionel Sambuc 	}
163*433d6423SLionel Sambuc 	*fpw++ = NULL;
164*433d6423SLionel Sambuc 
165*433d6423SLionel Sambuc 	/* Padding, because of the stack alignement. */
166*433d6423SLionel Sambuc 	while ((size_t)fp % sizeof(void *)) *fp++= 0;
167*433d6423SLionel Sambuc 
168*433d6423SLionel Sambuc 	/* Fill in the ps_string struct*/
169*433d6423SLionel Sambuc 	*psp = (struct ps_strings *) fp;
170*433d6423SLionel Sambuc 
171*433d6423SLionel Sambuc 	(*psp)->ps_argvstr = (char **)(*vsp + sizeof(argc));
172*433d6423SLionel Sambuc 	(*psp)->ps_nargvstr = argc;
173*433d6423SLionel Sambuc 	(*psp)->ps_envstr = (*psp)->ps_argvstr + argc + 1;
174*433d6423SLionel Sambuc 	(*psp)->ps_nenvstr = envc;
175*433d6423SLionel Sambuc }
176