这个作业属于哪个课程 | <2020-2021-1Linux内核原理与分析)> |
---|---|
这个作业要求在哪里 | <2020-2021-1Linux内核原理与分析第八周作业> |
这个作业的目标 | 学习Linux内核如何装载和启动一个可执行程序 |
作业正文 | https://www.cnblogs.com/dyyblog/p/14027636.html |
一.基本概念
1.1ELF文件格式
1.2ELF文件程序编译
ELF文件头中定义了ELF魔数,文件机器字节长度,数据存储方式,版本,运行平台,ABI版本,ELF重定位类型,硬件平台,硬件平台版本,入口地址,程序头入口和长度,段表的位置和长度,段的数量。
- 预处理:编译器将C程序的头文件编译进来,还有宏的替换,可以用gcc的参数-E来参看。
- 编译:这个阶段编译器主要做词法分析、语法分析、语义分析等,在检查无错误后后,把代码翻译成汇编语言。可用gcc的参数-S来参看。
- 汇编:汇编器as将louhao.s 翻译成机器语言保存在louhao.o 中(二进制文本形式)。
- 链接:链接器负责处理多个.o文件的并入,结果得到louhao文件,它就是一个可执行的目标文件。
1.3 静态链接和动态链接
静态链接就是在装载之前,就完成所有的符号引用的一种链接方式。静态链接的处理过程分为2个步骤:
(1)空间与地址的分配。扫描所有的目标文件,合并相似段,收集当中所有的符号信息。
(2)符号解析与重定位。调整代码位置
静态链接的优点简单,缺点浪费内存空间。在多进程的操作系统下,同一时间,内存中可能存在多个相同的公共库函数。
程序的开发与发布流程受模块制约。 只要有一个模块更新,那么就需要重新编译打包整个代码。
为了解决以上2个问题,就诞生了动态链接。
动态链接的基本思想就是将对符号的重定位推迟到程序运行时才进行。只要推迟到运行时进行符号的重定位,就能解决静态链接的两个缺点。对于第一个缺点:在运行时重定位,如果在运行过程中调用了公共库函数或者其他模块的函数,系统只需要在内存中维护一份公共库代码即可,只要将不同应用程序对公共库函数的调用地址设置成相同即可。对于第二个缺点:理论上只要将需要替换的模块更新,无需将整个应用程序打包。对于静态链接来说,系统只需要加载一个文件(可执行文件)到内存即可,但是在动态链接下,系统需要映射一个主程序和多个动态链接模块,因此,相比于静态链接,动态链接使得内存的空间分布更加复杂。不同模块在内存中的装载位置一定要保证不一样。
二.实验过程
将menu目录删除,利用git命令克隆一个新的menu目录,然后用test_exec.c覆盖test.c:
查看exec命令是否添加进入内核
水平线分割进行gdb调试
gdb设置断点
实验结果
输入redelf -h hello查看hello的EIF头部
exec()函数分析
int do_execve(struct filename *filename,
const char __user *const __user *__argv,
const char __user *const __user *__envp)
{
return do_execve_common(filename, argv, envp);
}
static int do_execve_common(struct filename *filename,
struct user_arg_ptr argv,
struct user_arg_ptr envp)
{
// 检查进程的数量限制
// 选择最小负载的CPU,以执行新程序
sched_exec();
// 填充 linux_binprm结构体
retval = prepare_binprm(bprm);
// 拷贝文件名、命令行参数、环境变量
retval = copy_strings_kernel(1, &bprm->filename, bprm);
retval = copy_strings(bprm->envc, envp, bprm);
retval = copy_strings(bprm->argc, argv, bprm);
// 调用里面的 search_binary_handler
retval = exec_binprm(bprm);
// exec执行成功
}
static int exec_binprm(struct linux_binprm *bprm)
{
// 扫描formats链表,根据不同的文本格式,选择不同的load函数
ret = search_binary_handler(bprm);
// ...
return ret;
}