1. Shell终端中执行可执行文件过程简述:
(1)读取用户由键盘输入的命令行。
(2)分析命令,以命令名作为文件名,并将其它参数改造为系统调用execve()内部处理所要求的形式。
(3)终端进程调用fork()建立一个子进程。
(4)终端进程本身用系统调用wait4()来等待子进程完成(如果是后台命令,则不等待)。当子进程运行时调用execve(),子进程根据文件名(即命令名)到目录中查找有关文件(这是命令解释程序构成的文件),将它调入内存,执行这个程序(解释这条命令)。
(5)如果命令末尾有&号(后台命令符号),则终端进程不用系统调用wait4()等待,立即发提示符,让用户输入下一个命令,转(1)。如果命令末尾没有&号,则终端进程要一直等待,当子进程(即运行命令的进程)完成处理后终止,向父进程(终端进程)报告,此时终端进程醒来,在做必要的判别等工作后,终端进程发提示符,让用户输入新的命令,重复上述处理过程。
2. 进程地址空间中用户栈的分配
进程地址空间由mm_struct结构描述,每个进程只存在一个地址空间。该结构伴随着进程的创建而创建。其中用start_stack来表示用户栈的起始地址。
(1) 进程创建,并建立进程地址空间。
do_fork
|- > copy_process
|- > dup_task_struct
|- > copy_mm
(2) 通过系统调用execve执行可执行程序,并重新分配用户栈。
基本处理流程:
do_execve_common - > exec_binprm - > search_binary_handler - > load_binary===load_elf_binary
在load_elf_binary 函数中,完成用户栈 start_stack 的初始化, bpr->p 在setup_arg_pages中赋值 。
其中:
♦ personality 中默认是没有设置ADDR_NO_RANDOMIZE。
randomize_va_space是由/proc/sys/kernel/randomize_va_space决定,
通过查看目前设置为 2.
♦ randomize_stack_top函数:
♦ setup_arg_pages函数:
int setup_arg_pages(struct linux_binprm *bprm, unsigned long stack_top, int executable_stack)
{
.....
#ifdef CONFIG_STACK_GROWSUP // 没有配置
....
#else
stack_top = arch_align_stack(stack_top);
stack_top = PAGE_ALIGN(stack_top);
if (unlikely(stack_top < mmap_min_addr) ||
unlikely(vma->vm_end - vma->vm_start >= stack_top - mmap_min_addr))
return -ENOMEM;
stack_shift = vma->vm_end - stack_top;
bprm->p -= stack_shift;
mm->arg_start = bprm->p;
#endif
.....
}
3. 实验验证