Module Name: src Committed By: uebayasi Date: Sat Apr 12 05:25:23 UTC 2014
Modified Files: src/sys/kern: kern_exec.c Log Message: execve_runproc: Unbreak __MACHINE_STACK_GROWS_UP machines. Clarify the stack address allocation code. Summarize an awful big comment about the _rtld() "gap". (The log message in Rev. 1.384 was wrong; the new stack address is passed not via the 3rd register argument, but via the SP. The 3rd is for ps_strings.) To generate a diff of this commit: cvs rdiff -u -r1.385 -r1.386 src/sys/kern/kern_exec.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/kern/kern_exec.c diff -u src/sys/kern/kern_exec.c:1.385 src/sys/kern/kern_exec.c:1.386 --- src/sys/kern/kern_exec.c:1.385 Fri Apr 11 18:02:33 2014 +++ src/sys/kern/kern_exec.c Sat Apr 12 05:25:23 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: kern_exec.c,v 1.385 2014/04/11 18:02:33 uebayasi Exp $ */ +/* $NetBSD: kern_exec.c,v 1.386 2014/04/12 05:25:23 uebayasi Exp $ */ /*- * Copyright (c) 2008 The NetBSD Foundation, Inc. @@ -59,7 +59,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: kern_exec.c,v 1.385 2014/04/11 18:02:33 uebayasi Exp $"); +__KERNEL_RCSID(0, "$NetBSD: kern_exec.c,v 1.386 2014/04/12 05:25:23 uebayasi Exp $"); #include "opt_exec.h" #include "opt_execfmt.h" @@ -243,6 +243,7 @@ struct execve_data { int ed_szsigcode; long ed_argc; long ed_envc; + vaddr_t ed_newstack; }; /* @@ -778,7 +779,7 @@ execve_loadvm(struct lwp *l, const char * Calculate the new stack size. */ - const size_t psstrauxlen = + const size_t nargenvptrs = data->ed_argc + /* char *argv[] */ 1 + /* \0 */ data->ed_envc + /* char *env[] */ @@ -804,21 +805,31 @@ execve_loadvm(struct lwp *l, const char #endif #ifdef __MACHINE_STACK_GROWS_UP -/* See big comment lower down */ +/* + * copyargs() fills argc/argv/envp from the lower address even on + * __MACHINE_STACK_GROWS_UP machines. Reserve a few words just below the SP + * so that _rtld() use it. + */ #define RTLD_GAP 32 #else #define RTLD_GAP 0 #endif - const size_t stacklen = + const size_t argenvlen = + RTLD_GAP + /* reserved for _rtld() */ sizeof(int) + /* XXX argc in stack is long, not int */ - (psstrauxlen * ptrsz) + /* XXX auxinfo multiplied by ptr size? */ + (nargenvptrs * ptrsz); /* XXX auxinfo multiplied by ptr size? */ + + const size_t sigcode_psstr_sz = + data->ed_szsigcode + /* sigcode */ + data->ed_ps_strings_sz + /* ps_strings */ + STACK_PTHREADSPACE; /* pthread space */ + + const size_t stacklen = + argenvlen + argenvstrlen + aslrgap + - RTLD_GAP + - data->ed_szsigcode + - data->ed_ps_strings_sz + - STACK_PTHREADSPACE; + sigcode_psstr_sz; /* make the stack "safely" aligned */ const size_t aligned_stacklen = STACK_LEN_ALIGN(stacklen, STACK_ALIGNBYTES); @@ -1117,39 +1128,36 @@ execve_runproc(struct lwp *l, struct exe data->ed_arginfo.ps_nenvstr = data->ed_envc; { - char *stack; - - stack = (char *)STACK_ALLOC(STACK_GROW(vm->vm_minsaddr, - STACK_PTHREADSPACE + data->ed_ps_strings_sz + data->ed_szsigcode), - epp->ep_ssize - (data->ed_ps_strings_sz + data->ed_szsigcode)); - -#ifdef __MACHINE_STACK_GROWS_UP /* - * The copyargs call always copies into lower addresses - * first, moving towards higher addresses, starting with - * the stack pointer that we give. When the stack grows - * down, this puts argc/argv/envp very shallow on the - * stack, right at the first user stack pointer. - * When the stack grows up, the situation is reversed. - * - * Normally, this is no big deal. But the ld_elf.so _rtld() - * function expects to be called with a single pointer to - * a region that has a few words it can stash values into, - * followed by argc/argv/envp. When the stack grows down, - * it's easy to decrement the stack pointer a little bit to - * allocate the space for these few words and pass the new - * stack pointer to _rtld. When the stack grows up, however, - * a few words before argc is part of the signal trampoline, XXX - * so we have a problem. + * Allocate the stack address passed to the newly execve()'ed process. * - * Instead of changing how _rtld works, we take the easy way - * out and steal 32 bytes before we call copyargs. - * This extra space was allowed for when 'pack.ep_ssize' was calculated. + * The new stack address will be set to the SP (stack pointer) register + * in setregs(). */ - stack += RTLD_GAP; -#endif /* __MACHINE_STACK_GROWS_UP */ - - /* Now copy argc, args & environ to new stack */ + + const size_t sigcode_psstr_sz = + data->ed_szsigcode + /* sigcode */ + data->ed_ps_strings_sz + /* ps_strings */ + STACK_PTHREADSPACE; /* pthread space */ + + char *stack; + + /* Top of the stack address space. */ + stack = vm->vm_minsaddr; + + /* Skip pthread space, ps_strings, and sigcode. */ + stack = STACK_GROW(stack, sigcode_psstr_sz); + + /* Allocate the gap for _rtld() and arguments to be filled by copyargs(). */ + stack = STACK_ALLOC(stack, epp->ep_ssize - sigcode_psstr_sz); + + /* Skip a few words reserved for _rtld(). */ + stack = STACK_GROW(stack, RTLD_GAP); + + /* Remember the new stack address for setregs(). */ + data->ed_newstack = (vaddr_t)stack; + + /* Now copy argc, args & environ to the new stack. */ error = (*epp->ep_esch->es_copyargs)(l, epp, &data->ed_arginfo, &stack, data->ed_argp); @@ -1326,17 +1334,10 @@ execve_runproc(struct lwp *l, struct exe doexechooks(p); - { - char * const stack = (char *)STACK_GROW( - (void *)epp->ep_minsaddr, epp->ep_ssize); - /* setup new registers and do misc. setup. */ - (*epp->ep_esch->es_emul->e_setregs)(l, epp, - (vaddr_t)stack); + (*epp->ep_esch->es_emul->e_setregs)(l, epp, data->ed_newstack); if (epp->ep_esch->es_setregs) - (*epp->ep_esch->es_setregs)(l, epp, - (vaddr_t)stack); - } + (*epp->ep_esch->es_setregs)(l, epp, data->ed_newstack); /* Provide a consistent LWP private setting */ (void)lwp_setprivate(l, NULL);