第七周
姬梦馨
原创作品
《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
第七周 Linux内核如何装载和启动一个可执行程序
一:1.可执行程序如何产生的?
linux系统中,可执行程序一般要经过预处理、编译、汇编、链接、执行等步骤。
编译过程 预处理:gcc –E hello.c –o hello.i; gcc –E调用cpp 生成中间文件 编 译:gcc –S hello.i –o hello.s; gcc –S调用ccl 翻译成汇编文件 汇 编:gcc –c hello.s –o hello.o; gcc -c 调用as 翻译成可重定位目标文件 链 接:gcc hello.o –o hello ; gcc -o 调用ld** 创建可执行目标文件
64位机可用参数-m32
cpp是指预处理编译文件
2.目标文件格式ELF
ELF文件已经是适应到某一种CPU体系结构的二进制兼容文件了。
默认的ELF头加载地址是0x8048000,头部大概要到0x48100处或者0x483000处,也就是可执行文件加载到内存之后
执行的第一条代码地址
查看一个可执行文件头部内容:readelf -h;头部后是代码和数据。
.o文件,可执行文件,都是目标文件,一般使用相同的文件格式。
常用文件格式:
a.out COFF PE - WINDOWS上 ELF - LINUX上
ABI:应用程序二进制接口
ELF文件格式中有三种主要的文件格式:
1:可重定位文件 主要是.o文件,保存有代码和适当数据,和其他的object文件一起来创建一个可执行文件或者共享文件 2:可执行文件 保存着一个用来执行的程序,指出exec(BA_OS)如何创建程序进程映象。 3:共享目标文件 保存代码和合适的数据,用来和链接器链接。 链接器分为动态和静态: 链接编辑器,静态链接,和其他的可重定位、共享目标文件创建其他的目标文件 动态链接器,连喝一个可执行文件和其他的共享目标文件来创建一个进程映像
文件格式
Object文件参与程序的联接(创建一个程序)和程序的执行(运行一个程序)。
object 文件格式提供了一个方便有效的方法并行的视角看待文件的内容。
3 静态链接的ELF可执行文件与进程的地址空间
32位x86进程地址空间共4G,1G是内核空间。
一般静态链接会将所有代码放在一个代码段;动态链接的进程会有多个代码段。
二、可执行程序、共享库和动态链接
1:新的可执行程序起点:
地址空间为0x8048000或0x8048300。
装载可执行程序之前的工作: Shell本身不限制命令行参数的个数,命令行参数的个数受限于命令自身。 Shell会调用execve将命令行参数和环境参数传递给可执行程序的main函数,传递和保存命令行参数 和环境变量。
2:命令行参数和环境变量是如何进入新程序的堆栈的?
execve: main函数需要构造他的执行环境,执行可执行程序;令行参数和环境变量通过系统调用传递到内核处理函数,然后内核处理函数构造新的可执行文件,来初始化新的可执行程序的堆栈,返回到新的可执行程序。
3:静态链接的可执行程序和动态链接的可执行程序execve系统调用返回时不同
静态链接:elf_entry指向可执行文件的头部,一般是main函数;
动态链接:elf_entry指向ld的起点。
4:sys_execve内部处理过程
int do_execve(struct filename *filename, 在函数返回中做一个do_execve const char __user *const __user *__argv, { struct user_arg_ptr argv = { .ptr.native = __argv }; struct user_arg_ptr envp = { .ptr.native = __envp }; return do_execve_common(filename, argv, envp); } SYSCALL_DEFINE3(execve, const char __user *, filename, const char __user *const __user *, argv, const char __user *const __user *, envp) { return do_execve(getname(filename), argv, envp); 转到do _ execve _ common函数 } #ifdef CONFIG_COMPAT COMPAT_SYSCALL_DEFINE3(execve, const char __user *, filename, const compat_uptr_t __user *, argv, const compat_uptr_t __user *, envp) { return compat_do_execve(getname(filename), argv, envp); } #endif if (!try_module_get(fmt->module)) continue; read_unlock(&binfmt_lock); bprm->recursion_depth++; retval = fmt->load_binary(bprm); read_lock(&binfmt_lock); put_binfmt(fmt); bprm->recursion_depth--; 在这个循环里寻找能够解析这个当前可执行文件
三:实验 GDB跟踪sys_execve内核函数处理过程
1: 内核启动 环境搭建 更新命令
2:在exec函数中执行了动态链接代码
3:hello.c
4:GDB 内核跟踪及设置断点
实验总结
动态链接的过程主要是动态链接器在起作用,而不是内核.
动态链接分为可执行程序装载时动态链接和运行时动态链接
新的程序开始执行,ELF可执行文件装载完成。