Linux内核设计第七周学习总结 Linux内核如何装载和启动一个可执行程序
陈巧然原创作品 转载请注明出处
《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-100002900
实验目的
使用gdb跟踪sys_execve内核函数的处理过程,分析exec*函数对应的系统调用处理过程,理解Linux内核如何装载和启动一个可执行程序。
实验过程
登陆实验楼虚拟机http://www.shiyanlou.com/courses/195
打开shell终端,执行以下命令:
cd LinuxKernel
rm -rf menu
git clone https://github.com/mengning/menu.git
cd menu
mv test_exec.c test.c
make rootfs
可以看到启动后的MenuOS已经包含了exec命令。
可以通过增加-s -S启动参数打开调试模式
qemu -kernel ../linux-3.18.6/arch/x86/boot/bzImage -initrd ../rootfs.img -s -S
打开gdb进行远程调试
gdb
file ../linux-3.18.6/vmlinux
target remote:1234
设置断点
b sys_execve
b do_execve
b do_execve_common
b exec_binprm
b search_binary_handler
b load_elf_binary
b start_thread
实验分析
通过查看源码可以看出执行exec命令是通过调用execlp函数实现的,属于库函数exec*都是execve的封装例程。
装载和启动一个可执行程序依次调用以下函数:
sys_execve() -> do_execve() -> do_execve_common() -> exec_binprm() -> search_binary_handler() -> load_elf_binary() -> start_thread()
实验总结
当linux内核或程序(例如shell)用fork函数创建子进程后,子进程往往要调用一种exec函数以执行另一个程序。
当进程调用一种exec函数时,该进程执行的程序完全替换为新程序,而新程序则从其main函数开始执行。
因为调用exec并不创建新进程,所以前后的进程ID并未改变。
exec只是用一个全新的程序替换了当前进程的正文、数据、堆和栈段。
参考资料:《UNIX环境高级编程第二版》
学习笔记
程序编译链接过程
预处理:(.c -> .cpp)
gcc -E -o hello.cpp hello.c -m32
编译:(.cpp -> .s 汇编)
gcc -x cpp-output -S -o hello.s hello.cpp -m32
编译:(.s -> .o 二进制目标代码)
gcc -x assembler -c hello.s -o hello.o -m32
链接:(.o -> a.out)共享库
gcc -o hello hello.o -m32
静态编译:
gcc -o hello.static hello.o -m32 -static
c语言main函数格式:
int main(int argc, char *argv[])
int main(int argc, char *argv[], char *envp[])
库函数exec*都是execve的封装例程
execve函数格式:
int execve(const char * filename,char * const argv[ ],char * const envp[ ])
sys_execve -> do_execve -> do_execve_common -> exec_binprm
说是exec系统调用,实际上在Linux中,并不存在一个exec()的函数形式,exec指的是一组函数,一共有6个,分别是:
int execl(const char *path, const char *arg, ...);
int execv(const char *path, char *const argv[]);
int execle(const char *path, const char *arg, ..., char * const envp[]);
int execve(const char *path, char *const argv[], char *const envp[]);
int execlp(const char *file, const char *arg, ...);
int execvp(const char *file, char *const argv[]);
其中只有execve是真正意义上的系统调用,其它都是在此基础上经过包装的库函数。
区别一:前4个取路径名作为参数,后2个取文件名作为参数;
区别二:参数表的传递(l表示list,v表示vector);
区别三:向新程序传递环境表。
动态链接:
装载时动态链接
gcc -shared shlibexample.c -o libshlibexample.so -m32
运行时动态链接
gcc -shared dllibexample.c -o libdllibexample.so -m32
主调程序
gcc main.c -o main -L /path/to/your/dir-l shlibexample -ldl -m32
Linux内核设计第七周学习总结 Linux内核如何装载和启动一个可执行程序的更多相关文章
- Linux内核分析第七周学习笔记——Linux内核如何装载和启动一个可执行程序
Linux内核分析第七周学习笔记--Linux内核如何装载和启动一个可执行程序 zl + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study. ...
- Linux内核设计第七周 ——可执行程序的装载
Linux内核设计第七周 ——可执行程序的装载 第一部分 知识点总结 一.预处理.编译.链接和目标文件的格式 1.可执行程序是怎么得来的 编译链接的过程 预处理阶段 gcc -E -o XX.cpp ...
- LINUX内核分析第七周学习总结:可执行程序的装载
LINUX内核分析第七周学习总结:可执行程序的装载 韩玉琪 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/cours ...
- LINUX内核分析第七周学习总结
LINUX内核分析第七周学习总结 标签(空格分隔): 20135328陈都 陈都 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc.study.163.c ...
- LINUX内核分析第七周学习总结——可执行程序的装载
LINUX内核分析第六周学习总结——进程的描述和进程的创建 张忻(原创作品转载请注明出处) <Linux内核分析>MOOC课程http://mooc.study.163.com/cours ...
- 20135323符运锦----第七周:Linux内核如何装载和启动一个可执行程序
可执行程序的装载 一.预处理.编译.链接和目标文件的格式 1.可执行程序是怎么得来的 ①编译器预处理 gcc -E -o XX.cpp XX.c (-m32)// 注:把include的文件包含进来, ...
- linux内核分析 第七周 Linux内核如何装载和启动一个可执行程序
一.编译链接的过程和ELF可执行文件格式 vi hello.c gcc -E -o hello.cpp hello.c -m32 //预处理.c文件,预处理包括把include的文件包含进来以及宏替换 ...
- 作业七:Linux内核如何装载和启动一个可执行程序
作业七:Linux内核如何装载和启动一个可执行程序 一.编译链接的过程和ELF可执行文件格式 可执行文件的创建——预处理.编译和链接 在object文件中有三种主要的类型. 一个可重定位(reloca ...
- 实验七:Linux内核如何装载和启动一个可执行程序
原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 题目自拟,内容围绕对Linu ...
随机推荐
- 初试Shell脚本
背景 临上线前测试比较努力,遇到闪退或者其他问题,会把日志包打给我,由于app内存限制,目前每次打包都是1m大小,所以有时查找问题的上下文比较吃力.同时由于日志比较多,根据关键词过滤的需求越来越重要. ...
- RabbitMQ和Kafka,更加便捷高效的消息队列使用方式,请放心食用
一.RabbitMQ实例介绍RabbitMQ实例由华为云分布式消息服务(DMS)团队打造,实例采用物理隔离的方式部署,租户独占RabbitMQ实例.一键式部署,完全兼容开源RabbitMQ的使用方式, ...
- PHP字符编码转换库iconv的一个细节
先来看代码 <?php $charset = 'GBK'; $str = '中华人民共和国中华人民共和国中华人民共和国中华人民共和国'; ; $str2 = iconv('UTF-8', $ch ...
- exec命令详解
基础命令学习目录首页 原文链接: exec: 在bash下输入man exec,找到exec命令解释处,可以看到有”No new process is created.”这样的解释,这就是说exec命 ...
- Python中fnmatch模块的使用
fnmatch()函数匹配能力介于简单的字符串方法和强大的正则表达式之间,如果在数据处理操作中只需要简单的通配符就能完成的时候,这通常是一个比较合理的方案.此模块的主要作用是文件名称的匹配,并且匹配的 ...
- mybatis之insert语句报错Cause: java.sql.SQLException: sql injection violation, syntax error: ERROR. token : WHERE,
报错日志:org.springframework.jdbc.UncategorizedSQLException: Error updating database. Cause: java.sql.SQ ...
- centos6 安装图形化界面
1.首先进行光盘的挂载,注意光盘挂载时不会自动建立目录的,所以需要自己建立目录 mkdir /mnt/cdrom mount /dev/cdrom /mnt/cdrom #dev目录为设备目录 2.更 ...
- git的使用(本地及关联远程,上传到远程)
前言:本想这个博客就是用来交作业的,因为作业,学习了git ,现在觉得,既然有这个博客了,就好好用一下吧,也给自己养成个好习惯,就也来记录一下吧,关于git的本地仓库上传,本地与远程的关联,从本地上传 ...
- jieba库的应用
#!/usr/bin/python# -*- coding:utf-8 -*- import imp,sys imp.reload(sys)from matplotlib.font_manager i ...
- Thinking in Java & 内部类
静态内部类可以直接创建对象new B.C(); 如果内部类不是静态的,那就得这样 B b = new B(); B.C c = b.new C(); //要想直接创建内部类的对象,不能按照想象的方式, ...