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