【发布时间】:2014-06-29 06:26:34
【问题描述】:
据我了解,环境变量的值直接位于内存中以 NULL 结尾的 argv 值之后。除了 env 变量之外,还存在 auxv。
环境变量的布局究竟是怎样的——这个布局是在哪里指定/记录的?它适用于哪些系统?
【问题讨论】:
据我了解,环境变量的值直接位于内存中以 NULL 结尾的 argv 值之后。除了 env 变量之外,还存在 auxv。
环境变量的布局究竟是怎样的——这个布局是在哪里指定/记录的?它适用于哪些系统?
【问题讨论】:
一个简单的答案是:程序调用时的堆栈布局由二进制格式定义定义(例如 ELF 规范:http://refspecs.linuxbase.org/elf/abi386-4.pdf,exec 上的初始堆栈布局请查看图 3-31) .
由于 Linux 不限于 ELF 可执行文件,并且可以使用其 binfmt 解释器框架支持多种二进制格式,因此 argv/envp 数据的实际处理分两个阶段进行。
首先,当sys_execve系统调用被调用时,内核会为新的进程栈创建一个虚拟内存映射。然后它将使用堆栈底部的一页或几页(最多 32 页任意限制)来存储提供的 argv/envp 参数的副本:
bprm->exec = bprm->p;
retval = copy_strings(bprm->envc, envp, bprm);
if (retval < 0)
goto out;
retval = copy_strings(bprm->argc, argv, bprm);
if (retval < 0)
goto out;
(http://code.metager.de/source/xref/linux/stable/fs/exec.c#1502)
在第二阶段,bprm 对象被传递给binfmt 解释器(连同相关的内存映射)。解释器,除其他外,会将附加信息推送到堆栈,包括参数/环境条目计数和指针。对于 elf 可执行文件,它将发生在 create_elf_tables:
/* Now, let's put argc (and argv, envp if appropriate) on the stack */
if (__put_user(argc, sp++))
return -EFAULT;
argv = sp;
envp = argv + argc + 1;
/* Populate argv and envp */
p = current->mm->arg_end = current->mm->arg_start;
while (argc-- > 0) {...
(http://code.metager.de/source/xref/linux/stable/fs/binfmt_elf.c#293)
这里的解释器实际上是在构建上面链接的规范中图 3-31 中概述的结构。
【讨论】: