Linux内核如何装载和启动一个可执行程序
2016-04-10 21:38
387 查看
在了解Linux内核是如何装载和启动一个可执行程序的之前,我们首先要知道可执行文件的创建顺序,
可执行文件的创建顺序是先进行预处理,然后进行编译,再进行目标文件的连接,最后生成可执行文件。
接下来我们需要了解execve这个函数:
可执行程序的装载
命令行参数和shell环境,一般我们执行一个程序的Shell环境,我们的实验直接使用execve系统调用。
Shell本身不限制命令行参数的个数, 命令行参数的个数受限于命令自身
例如,int main(int argc, char *argv[])
又如, int main(int argc, char *argv[], char *envp[])
Shell会调用execve将命令行参数和环境参数传递给可执行程序的main函数
int execve(const char * filename,char * const argv[ ],char * const envp[ ]);
库函数exec*都是execve的封装例程
sys_execve内部会解析可执行文件格式
do_execve -> do_execve_common -> exec_binprm
search_binary_handler符合寻找文件格式对应的解析模块,如下:
1369 list_for_each_entry(fmt, &formats, lh) {
1370 if (!try_module_get(fmt->module))
1371 continue;
1372 read_unlock(&binfmt_lock);
1373 bprm->recursion_depth++;
1374 retval = fmt->load_binary(bprm);
1375 read_lock(&binfmt_lock);
对于ELF格式的可执行文件fmt->load_binary(bprm);执行的应该是load_elf_binary其内部是和ELF文件格式解析的部分需要和ELF文件格式标准结合起来阅读。
接下来我们通过实验来了解Linux内核是如何装载和启动一个可执行程序的。
首先我们先设三个断点sys_execve,load_elf_binary和start_threaad。
接下来开始跟踪整个流程,先在sys_execve处观察流程走向。
我们可以看到在sys_execve处主要是将命令行参数和环境变量传递到内核堆栈中去。
接下来看load_elf_binary处的程序,
这部分的代码主要是将elf二进制文件加载到内核。
再看start_thread,
可以看到,这部分代码的主要功能是修改内核堆栈,创建新堆栈,然后将命令行参数和环境变量拷贝到新程序堆栈中,再进行任务调度,运行新程序。而新程序的起始入口为elf_entry。
在实验中我们还能观测到新程序的入口地址为0x8048d0a。
实验总结:
对于Linux内核如何装载和启动一个可执行程序的,首先是通过sys_execve将函数的命令行参数和环境变量传递到内核堆栈中去,再由load_elf_binary将二进制文件加载到内核中去,再通过start_thread修改内核堆栈,创建新堆栈,然后将命令行参数和环境变量拷贝到新程序堆栈中,再进行任务调度,运行新程序。而新程序的起始入口为elf_entry。
作者 叶涛
《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
可执行文件的创建顺序是先进行预处理,然后进行编译,再进行目标文件的连接,最后生成可执行文件。
接下来我们需要了解execve这个函数:
可执行程序的装载
命令行参数和shell环境,一般我们执行一个程序的Shell环境,我们的实验直接使用execve系统调用。
Shell本身不限制命令行参数的个数, 命令行参数的个数受限于命令自身
例如,int main(int argc, char *argv[])
又如, int main(int argc, char *argv[], char *envp[])
Shell会调用execve将命令行参数和环境参数传递给可执行程序的main函数
int execve(const char * filename,char * const argv[ ],char * const envp[ ]);
库函数exec*都是execve的封装例程
sys_execve内部会解析可执行文件格式
do_execve -> do_execve_common -> exec_binprm
search_binary_handler符合寻找文件格式对应的解析模块,如下:
1369 list_for_each_entry(fmt, &formats, lh) {
1370 if (!try_module_get(fmt->module))
1371 continue;
1372 read_unlock(&binfmt_lock);
1373 bprm->recursion_depth++;
1374 retval = fmt->load_binary(bprm);
1375 read_lock(&binfmt_lock);
对于ELF格式的可执行文件fmt->load_binary(bprm);执行的应该是load_elf_binary其内部是和ELF文件格式解析的部分需要和ELF文件格式标准结合起来阅读。
接下来我们通过实验来了解Linux内核是如何装载和启动一个可执行程序的。
首先我们先设三个断点sys_execve,load_elf_binary和start_threaad。
接下来开始跟踪整个流程,先在sys_execve处观察流程走向。
我们可以看到在sys_execve处主要是将命令行参数和环境变量传递到内核堆栈中去。
接下来看load_elf_binary处的程序,
这部分的代码主要是将elf二进制文件加载到内核。
再看start_thread,
可以看到,这部分代码的主要功能是修改内核堆栈,创建新堆栈,然后将命令行参数和环境变量拷贝到新程序堆栈中,再进行任务调度,运行新程序。而新程序的起始入口为elf_entry。
在实验中我们还能观测到新程序的入口地址为0x8048d0a。
实验总结:
对于Linux内核如何装载和启动一个可执行程序的,首先是通过sys_execve将函数的命令行参数和环境变量传递到内核堆栈中去,再由load_elf_binary将二进制文件加载到内核中去,再通过start_thread修改内核堆栈,创建新堆栈,然后将命令行参数和环境变量拷贝到新程序堆栈中,再进行任务调度,运行新程序。而新程序的起始入口为elf_entry。
作者 叶涛
《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
相关文章推荐
- Linux 下wifi 驱动开发(四)—— USB接口WiFi驱动浅析
- Linux 系统链接装载可执行程序
- 嵌入式Linux使用Busybox init进程启动过程分析
- samba服务器搭建
- Linux运维实战之DNS(bind)服务器的安装与配置
- Linux下MySQL导入导出数据
- Centos 7 远程桌面客户端
- Linux内核如何装载和启动一个可执行程序
- Linux之ssh连接保持与重用
- Linux 控制 配置 减少 交换分区 SWAP 虚拟内存使用
- Linux jar包 后台运行
- Linux jar包 后台运行
- linux进程调度策略
- linux 《vmware下克隆的centos无法配置固定ip》
- linux内核分析 第七周读书笔记
- linux ssh -l 命令运用
- Centos7 Ansible安装
- CentOS 6的系统启动流程
- lab7:Linux内核如何装载和启动一个可执行程序
- Linux学习(3)——文件管理命令