1 /* Utilities to generate a proper C stack.
3 * Author: Lionel A. Sambuc.
15 #include <sys/exec_elf.h>
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.
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.
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
28 * The following stack layout is expected by _rtld():
30 * | XXXXXXXXXX | 0x0000_00000
32 * | ... | Top of the stack
34 * | *argv1 | points to the first char of the argv1
45 * | AuxExecName| fully resolve executable name, as an ASCIIZ string,
46 * at most PMEF_EXECNAMELEN1 long.
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...
52 * | strings | Maybe followed by some padding to word-align.
54 * | argc | +---> ps_string structure content.
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.
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 \
68 sizeof(int) + sizeof(void *) * 2 + \
69 sizeof(AuxInfo) * PMEF_AUXVECTORS + PMEF_EXECNAMELEN1 + \
70 sizeof(struct ps_strings) \
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
)
80 size_t const min_size
= STACK_MIN_SZ
;
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 */
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;
91 if (*stack_size
< n
) {
97 for (p
= envp
; p
&& *p
!= NULL
; p
++) {
98 size_t const n
= sizeof(*p
) + strlen(*p
) + 1;
100 if (*stack_size
< n
) {
106 /* Compute the aligned frame size. */
107 *stack_size
= (*stack_size
+ sizeof(void *) - 1) &
108 ~(sizeof(void *) - 1);
110 if (*stack_size
< min_size
) {
111 /* This is possible only in case of overflow. */
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
)
125 /* Frame pointers (a.k.a stack pointer within the buffer in current
127 char *fp
; /* byte aligned */
128 char **fpw
; /* word aligned */
130 size_t const min_size
= STACK_MIN_SZ
;
132 /* Virtual address of the stack pointer, in new memory space. */
133 *vsp
= minix_get_user_sp() - stack_size
;
135 /* Fill in the frame now. */
136 fpw
= (char **) frame
;
137 *fpw
++ = (char *) argc
;
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 *);
144 /* Fill in argv and the environment, as well as copy the strings
146 for (p
= argv
; *p
!= NULL
; p
++) {
147 size_t const n
= strlen(*p
) + 1;
148 *fpw
++= (char *)(*vsp
+ (fp
- frame
));
154 for (p
= envp
; p
&& *p
!= NULL
; p
++) {
155 size_t const n
= strlen(*p
) + 1;
156 *fpw
++= (char *)(*vsp
+ (fp
- frame
));
162 /* Padding, because of the stack alignement. */
163 while ((size_t)fp
% sizeof(void *)) *fp
++= 0;
165 /* Fill in the ps_string struct*/
166 *psp
= (struct ps_strings
*) fp
;
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
;