网易公开课《Linux内核分析》学习心得-Linux内核如何装载和启动一个可执行程序

杨怡泽 原创作品转载请注明出处《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

实验

设置断点sys_execeve,并继续
这里写图片描述
代码执行到了SyS_execve。在QEMU中执行exec,可以看到只能出现两句,没有完全执行完毕。
这里写图片描述
设置断点load_elf_binary和start_thread,并执行,可以看到代码停在了两个断点处。
这里写图片描述
在代码停到SyS_execve处时候,list进入代码

1599            old = ACCESS_ONCE(mm->flags);
1600            new = (old & ~MMF_DUMPABLE_MASK) | value;
1601        } while (cmpxchg(&mm->flags, old, new) != old);
1602    }
1603    
1604    SYSCALL_DEFINE3(execve,
1605            const char __user *, filename,
1606            const char __user *const __user *, argv,
1607            const char __user *const __user *, envp)
1608    {

这段代码中DEFINE3中的filename对应文件名,argv对应环境变量,envp对应命令行
这里写图片描述
继续执行,进入do_execve的内部
这里写图片描述
继续执行直到start_thread,显示的po new_ip中的内存地址是0x8048d0a。同时新开终端在menu文件中执行readelf -h hello命令,可以发现入口点地址同样是0x8048d0a。
这里写图片描述
继续执行直到代码执行完毕
这里写图片描述
这里写图片描述
这里写图片描述

分析

ELF

Linux的标准可执行格式是ELF,其格式为

:name:type:offset:string:mask:interpreter:flags

exec函数

所有的exec函数都是C库定义的封装例程,并利用execve()系统调用,也是Linux所提供的处理程序执行的唯一系统调用。ELF文件会被默认映射到0x8048000这个地址。

sys_execve()服务例程接受下列参数:
- 可执行文件路径名的地址
- 以NULL结束的字符串指针数组的地址。每个字符串表示一个命令行参数。
- 以NULL结束的字符串指针数组的地址。每个字符串表示一个命令行参数。每个字符串以NAME=value形式表示一个环境变量。

sys_execve()依次执行以下操作:
1. 动态地分配一个linux_binprm数据结构,并用新的可执行文件的数据填充这个结构。
2. 调用path_lookup(),dentry_open()和path_release(),以获得与可执行文件相关的目录项对象,文件对象和索引节点对象。
3. 检查是否可以由当前的进程执行该文件,再检查索引节点的i_writecount字段,以确定可执行文件没有被写入。
4. 在多处理器系统中,调用sched_exec()函数来确定最小负载CPU以执行程序。
5. 调用init_new_context()检查当前进程是否使用自定义局部描述符表。
6. 调用prepare_binprm()函数填充linux_binprm()数据结构。
7. 把文件路径名、命令行参数及环境串拷贝到一个或多个新分配叶框中。
8. 调用search_binary_handler()函数对formats链表进行扫描,并尽力应用每个元素的load_binary方法,把Linux_binprm数据结构传递给这个函数。只要load_binary方法成功应答了文件的可执行格式,对formats的扫描就终止。
9. 如果在formats链表中,就释放所分配的所有页框并返回错误代码。
10. 否则,函数释放linux_binprm数据结构,返回从这个文件可执行格式的load_binary方法中所获得的代码。

如果可执行文件是静态链接,可执行文件对应的load_binary()需要将程序的正文段,数据段,bss段和堆栈段映射到进程线性区,然后把用户态eip寄存器的内容设置为新程序的入口。

总结

程序是以可执行文件的形式放到磁盘上的,可执行文件既包括执行函数的目标代码,也包括这些函数所使用的数据。当装入一个程序的时候,用户可以提供影响程序执行方式的环境变量和命令行参数两种信息。
当execve()终止时,系统调用的代码不复存在,要执行的新成效已经被映射到进程的地址空间。这样程序就可以成功运行了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值