实验步骤
1. 更新menu,用test.c覆盖test_exec.c
2. 把init 和 hello 放到了rootfs.img目录下,执行exec命令的时候自动加载了hello程序
3. 执行exec
4. 运行stopped的menu
5. gdb进行跟踪分析
总结
1. 创建新进程
2. 新进程调用execve()系统调用执行指定的ELF文件
3. 调用内核的入口函数sys_execve(),sys_execve()服务例程修改当前进程的执行上下文;
当ELF被load_elf_binary()装载完成后,函数返回至do_execve()在返回至sys_execve()。ELF可执行文件的入口点取决于程序的链接方式:
1. 静态链接:elf_entry就是指向可执行文件里边规定的那个头部,即main函数处。
2. 动态链接:可执行文件是需要依赖其它动态链接库,elf_entry就是指向动态链接器的起点。
预处理、编译、链接和目标文件的格式
1.预处理阶段 :编译器将C源代码中包含的头文件编译进来和执行宏替换等工作。
gcc -E -o XX.cpp XX.c -m32 (XX.cpp是预处理文件)
2.编译器生成汇编代码阶段:gcc首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,gcc把代码翻译成汇编语言。
gcc -x cpp-output -S -o hello.s hello.cpp -m32 (XX.s是汇编代码)
3.汇编器生成目标代码阶段:把编译阶段生成的XX.S文件转成二进制目标代码。
gcc -x assembler -c hello.s -o hello.o -m32 (XX.o是目标代码)
4.链接器生成可执行文件阶段(将编译输出XX.o文件链接成最终的可执行文件)。
gcc -o hello.static hello.c -m32 -static
5.运行(若链接没有-o指明,则生成可执行文件默认为a.out)
./a.out
目标文件的格式ELF:
A.out是最古老的可执行文件,目前Windows系统上多是PE,Linux系统上多是ELF。ELF文件已经是适应到某一种CPU体系结构的二进制兼容文件了
ELF格式分类:
可重定位文件.o,用来和其他object文件一起创建可执行文件和共享文件
可执行文件,指出应该从哪里开始执行
共享文件,主要是.so文件,用来被链接编辑器和动态链接器链接
对ELF头的描述告诉系统如何创建一个进程的内存映像,section头表包含了描述文件sections的信息。当创建或增加一个进程映像时,理论上它会把程序段拷贝到虚拟内存中某个段
ELF文件的头部规定了许多与二进制兼容性相关的信息。所以在加载ELF文件的时候,必须先加载头部,分析ELF的具体信息
entry代表刚加载过新的可执行文件之后的程序的入口地址,头部后是代码和数据,进程的地址空间是4G,上面的1G是内核用,下面的3G是程序使用。默认的ELF头加载地址是0x8048000
在创建一个新的用户态堆栈的时候,实际上是把命令行参数的内容和环境变量的内容通过指针的方式传递到系统调用的内核处理函数的,内核处理函数在创建一个新的可执行堆栈的时候会将命令行参数的内容和环境变量的内容拷贝到用户态堆栈里面来初始化新的可执行程序执行的上下文环境
作者: 王雪铖
原创作品转载请注明出处
《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000