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