问题的由来
我们知道,普通的C程序可以从命令行上接收参数,也可以使用、设置SEHLL环境变量(getenv,setenv),
/*一个简单的C例子 test.c*/
#include "stdio.h"
extern char** environ; /*C库定义的全局变量,环境变量字符串数组的起始地址*/
int main(int argc, char* argv[])
{
int i;
char** p = environ;
for(i=0; i<argc; i++)
printf("argv[%d]: %s\n", i, argv[i]);
printf("\n\nEnviroment Varibles\n\n");
while(*p != NULL)
printf("%s\n", *(p++));
return 0;
}
编译后在命令行上运行
:
./test arg1 arg2.
可以将运行结果与env输出结果比较
执行普通的C程序时,因为有SHELL的存在,命令行参数和环境变量可以由SHELL传给C程序,这一点似乎容易理解。然而,对于Linux系统启动时运行的第一个用户程序init来说情况变得有些特别。init不是由用户在命令行上启动的(这时候根被还没有SHELL),而是由内核启动的,init程序里也使用了命令行参数和环境变量。
/*Busybox-1.19.3/init/init.c*/
int init_main(int argc UNUSED_PARAM, char **argv)
{
if (argv[1] && strcmp(argv[1], "-q") == 0) {
return kill(1, SIGHUP);
}
//……
console_init();
//……
}
static void console_init(void)
{
//.......
s = getenv("CONSOLE");
s = getenv("TERM");
//......
}
从上面的代码片段里可以看到init程序和普通应用程序一样,也使用到了命令行参数和环境变量,既然这个时候还没有SHELL,那么init使用的命令行参数和环境变量保存在何处、从何而来?
保存在何处
Linux采用了虚拟内存技术,进程里使用的均是虚拟地址,内核通过为进程建立不同的页表,可以将两个相互独立的进程的相同的虚拟地址映射到不同的物理地址上,因此,Linux下所有可执行文件运行时在地址空间里的映像布局结构是一样的,这简化了系统设计。
下图是C