不久前,我正在使用 GDB 探索一个简单的 C 程序的 ELF 二进制文件。我看到printenv
在终端中运行时打印的环境变量也出现在我在该终端中运行的 C 程序二进制文件的堆栈顶部。
Bash 是如何实际执行程序并同时将所有环境变量添加到新进程的堆栈中的?简而言之,当我运行这样的程序时,一步一步会发生什么:
./myprogram
答案1
Linux 程序是通过execve
系统调用来执行的。execve
有以下签名:
int execve(const char *filename, char *const argv[], char *const envp[]);
最后一个参数envp
,用于将环境作为字符串数组传递给进程,每个字符串的形式为 key=value。按照惯例,相同的环境会从一个进程传递到另一个进程,除非调用进程对其进行一些更改。内核安排新程序接收堆栈上的环境,就像传递程序参数一样。
库函数execl
、execlp
、execv
和execvp
不带参数envp
(但execle
和execvpe
函数带参数)。这些函数从environ
调用过程中的全局变量获取环境。这样,使用该execle
函数启动另一个程序的程序就不必担心传递环境,但库函数会自动“在幕后”执行此操作。
所有提到的库函数最终都会调用execve
系统调用,并在参数中传递环境envp
。