execve()和环境变量

4
我有一个关于Linux如何处理传递给execve()的环境变量的问题:
execve()的概要如下: int execve(const char *filename, char *const argv[], char *const envp[]);
在调用execve()之前,我们从当前进程的内存映射中分配用于保存envs/args的内存。但是在执行完execve()之后,调用进程的所有文本/数据/bss/堆栈都被新程序覆盖,并且旧进程的所有内存映射都不被保留(包括传递的envs/args的内存)。
对于新程序来说,它从哪里读取envs/args?内核是否会复制传递的envs/args并将其放置到新的内存映射中,还是使用其他技巧?

我猜测新程序可以从main函数中的argcargv读取参数。我还猜想调用execve的程序将从其主函数返回并进入加载器,在加载器中,加载器将设置所有环境和参数,就像正常执行程序一样。这只是我的猜测,所以可能完全错误 - nhahtdh
1个回答

10

是的。

当一个进程调用exec时,内核会复制整个argvenvp 数组。然后,这些将被复制到新的进程镜像中 - 特别是,当程序开始运行时,它的堆栈看起来像:

NULL
...
envp[1]
envp[0]
NULL
argv[argc-1]
...
argv[1]
argv[0]
argc

Glibc启动代码在_start中将其转换为正确的形式以调用main。更多细节请参见从旧进程复制的内容位于linux/fs/exec.c,复制到新进程的内容位于linux/fs/binfmt_elf.c,并且程序启动在特定于架构的代码中完成,例如glibc/sysdeps/i386/start.Sglibc/sysdeps/x86_64/start.Sglibc/ports/sysdeps/arm/start.S,这些代码存在的目的仅是启动__libc_start_main以在glibc/csu/libc-start.c中启动main

4
收集这么多链接,做得不错。 - Alan Curry

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接