PS:要转载请注明出处,本人版权所有。
PS: 这个只是基于《我自己》的理解,
如果和你的原则及想法相冲突,请谅解,勿喷。
前置说明
本文作为本人csdn blog的主站的备份。(BlogID=019)
本文发布于 2016-06-02 14:35:06,现用MarkDown+图床做备份更新。blog原图已丢失,使用csdn所存的图进行更新。(BlogID=019)
环境说明
无
前言
近段时间看一些代码,自己也写了一些。但是写着写着感觉自己迷茫了,自己对程序的结构越来越模糊,甚至都不相信自己的写的部分,或者相信自己的知识。那么现在就来终结这些想法,让自己提升一下。本系列文章主要分为两部分,(一)是分析程序在内存中的分布(二)是linux下程序的执行流程
linux下程序的执行流程
对Linux有了解的人都应该知道,在系统中只有一个pid为1的父进程(init),其他的进程都是这个进程衍生出来的子进程(fork),从而形成了以init为树根的一颗树。如图:
如果你有图形桌面,则会在初始化好了开机启动服务后,会调用图形桌面启动器lightdm,然后图形界面初始化,然后你双击鼠标运行的程序就会是图形桌面的子进程。而我们在shell下运行的程序就会是在lightdm->/usr/bin/x-term(以上图为例)下形成子进程。
当你在shell中输入
./XXXXX
这个时候,一个程序就开始执行了。现在就进入我们这篇文章要讲的重点。(一个程序要可以执行的前戏就是之前的分析)
现在我要开始执行XXXXX程序
在shell中输入上图命令,并回车后。
-
第一步:shell 会fork 出一个子进程。同时wait()子进程结束。如果在shell命令后加入&等符号,表示后台执行时,shell fork后,不会wait()子进程,而直接返回。新fork()出的子进程,将会调用一个用户态函数execve() 加载xxxxx程序的文件。(放在磁盘上的静态数据)
-
第二步:下面来分析execve()函数的执行过程。查看man手册:
execve源码:
在调用INLINE_SYSCALL宏后,
调用INTERNAL_SYSCALL()
(提示:其实以上部分就是熟知的GLIBC怎么实现用户API与系统调用结合的过程)
保存系统调用号,然后保存到寄存器,然后切换到内核态,根据调用号查询到sys_execve(),执行sys_execve()
asmlinkage int sys_execve(struct pt_regs regs)
{
int error;
char * filename;
filename = getname((char *) regs.ebx);
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
error = do_execve(filename, (char **) regs.ecx, (char **) regs.edx, ®s);
if (error == 0)
current->ptrace &= ~PT_DTRACE;
putname(filename);
out:
return error;
}
调用do_execve(),先收集信息,调用search_binary_handler()函数,根据可执行文件类型,调用不同的的处理函数去执行。(后面详细的信息可以去阅读源码,这里就不一一说明)
(由于本人水平有限,后面部分只知道个大概,就不献丑了)
这样一个程序就执行起来了。是不是非常的简单。
后记
无
参考文献
- 无
PS: 请尊重原创,不喜勿喷。
PS: 要转载请注明出处,本人版权所有。
PS: 有问题请留言,看到后我会第一时间回复。