当我使用getenv()标准C库中的函数时,我的程序从其父级继承环境变量.
例:
$ export FOO=42
$ <<< 'int main() {printf("%s\n", getenv("FOO"));}' gcc -w -xc - && ./a.exe
42
Run Code Online (Sandbox Code Playgroud)
在libc中,environ变量被声明为environ.c.我期待它在执行时是空的,但我明白了42.
更进一步getenv可以简化如下:
char * getenv (const char *name)
{
size_t len = strlen (name);
char **ep;
uint16_t name_start;
name_start = *(const uint16_t *) name;
len -= 2;
name += 2;
for (ep = __environ; *ep != NULL; ++ep)
{
uint16_t ep_start = *(uint16_t *) *ep;
if (name_start == ep_start && !strncmp (*ep + 2, name, len)
&& (*ep)[len + 2] == '=')
return &(*ep)[len + 3];
}
return NULL;
}
libc_hidden_def (getenv)
Run Code Online (Sandbox Code Playgroud)
在这里,我将获取__environ变量的内容.但是我从来没有初始化它.
所以我感到困惑,因为除非我的主要功能不是我的程序的真正切入点,否则environ应该NULL是这样.或许gcc通过添加一个_init属于标准C库的函数来勾选我.
在哪里environ初始化?
环境变量作为第三个参数main从父进程向下传递给.发现这一点的最简单方法是阅读系统调用的文档execve,特别是这一点:
Run Code Online (Sandbox Code Playgroud)int execve(const char *filename, char *const argv[], char *const envp[]);描述
execve()执行指向的程序filename.[...]argv是传递给新程序的参数字符串数组.按照惯例,这些字符串中的第一个应包含与正在执行的文件关联的文件名.envp是一个字符串数组,通常是表单的数组,key=value作为环境传递给新程序.二者argv并envp必须由NULL指针被终止.参数向量和环境可以被被调用程序的main函数访问,当它被定义为:Run Code Online (Sandbox Code Playgroud)int main(int argc, char *argv[], char *envp[])
在它调用之前,C库将envp参数复制到environ其启动代码中的某个全局变量中main:例如,GNU libc执行此操作_init并且musl libc执行此操作__init_libc.(您可能会发现musl libc的代码比GNU libc更易于跟踪.)相反,如果使用其中一个不采用显式环境向量的exec包装函数启动程序,则C库将作为第三个参数提供给.因此,环境变量的继承严格地是用户空间约定.就内核而言,每个程序都接收两个参数向量,而不关心它们中的内容.environexecve
(请注意,三参数main是C语言的扩展.C标准仅指定int main(void),int main(int argc, char **argv)但它允许实现定义其他形式(C11附件J.5.1环境参数).三个参数main是自Unix以来环境变量的工作原理如果不是更长的V7,并且也由Microsoft记录 - 请参阅C和C++中应该main()返回什么?.)
这里没有神秘感.
首先,外壳分叉.分叉过程显然具有相同的环境.然后在孩子中执行新程序.有问题的系统调用是execve,其中包括指向环境的指针.
那么,在执行二进制文件之后设置的环境完全取决于执行exec的代码.
所有这一切都可以通过运行strace轻松看出.
编辑:自编辑问题以来询问environ:
当您执行动态链接的二进制文件时,执行任何操作的第一个用户空间代码都来自加载程序.加载器和其他东西设置变量argc,argv或者environ只是main()从二进制文件调用.
再一次,所有这些的来源都是免费提供的.虽然glibc的源代码由于残酷的格式化而难以阅读,但BSD很容易在概念上等同.
http://code.metager.de/source/xref/freebsd/libexec/rtld-elf/rtld.c#389
| 归档时间: |
|
| 查看次数: |
6148 次 |
| 最近记录: |