shell程序、fork()函数、execve()函数之间什么关系?

xufeiyunwindows 2008-11-28 11:29:39
加精
目前在看linux内核代码方面的东西,目前主要是文件系统FS这一块的内容。
在exec.c源码文件中,有一个函数 do_execve() 这个函数是会被 “系统调用”函数 sys_execve()会调用的,而sys_execve()是某进程通过“中断调用过程”(int 0x80, 功能号为__NR__EXECVE)被调用的,即sys_execve()函数的实现是直接通过汇编写的,如下:
####这是 sys_execve() 系统调用。取中断调用程序的代码指针作为参数调用C函数(do_execve())
[本人附加说明:sys_execve()被编译中汇编后,在汇编代码中对应的该函数“入口地址”就是指 标号“_sys_execve”处的地址]
# do_execve()在(fs/exec.c,182)。
.align 2
_sys_execve:
lea EIP(%esp),%eax
pushl %eax
call _do_execve
addl $4,%esp # 丢弃调用时压入栈的EIP值
ret

现在问题是,在linux下,如果要执行一个特定的可执行程序(假如是 hello 可执行程序),我们一般会在命令行中直接输入 hello 后回车,这时命令行所在的进程(即父进程,这个父进程一般应该是 /bin/sh,也可能是别的shell程序,如csh,bash等,但这里就以 sh 为例),然后这个父进程会通过fork()函数“创建”出一个子进程(假如以B表示该子进程吧)来,然后在B中执行 hello 这个程序(即子进程会调用execve()函数加载 hello 程序,然后在子进程空间中“转向”去执行这个程序),这样子进程B就是hello程序的进程了。
这里就有以下问题:
1、sh本身是可执行程序吗?(很多地方说,sh是解释程序)如果是解释程序?sh有源码吗?或是说 sh会解释命令行中的参数信息吧(因为 do_execve()中的参数莫名其妙地被传入了)。 sh做了些什么工作呢?
2、子进程B是在 sh 程序内部被 fork() 出来的吗?也就是说,sh程序会调用 fork() 函数吗?还做了其他什么工作呢?
3、子进程B在执行过程中,会在什么时候调用“系统调用函数”sys_execve()呢? (调用方式可能是通过“系统中断调用”int 0x80,功能号为__NR_execve (值为11)也可能是直接通过 execve() 而“转向”调用“系统中断调用”)
4、init()函数中fork()出了一个子进程,该子进程负责execve() sh解释程序,即sh程序也是通过 execve() 函数完成被加载及运行的,sh一直在运行,所以我们可以看到命令行界面的。

init()程序中执行sh的代码如下所示:

[说明:前面的省略了]
// 关闭了句柄0(stdin),以只读方式打开/etc/rc 文件,并执行/bin/sh 程序,所带参数和

// 环境变量分别由argv_rc 和envp_rc 数组给出。参见后面的描述。

if (!(pid = fork ()))
{
close (0);
if (open ("/etc/rc", O_RDONLY, 0))
_exit (1);// 如果打开文件失败,则退出(/lib/_exit.c,10)。
execve ("/bin/sh", argv_rc, envp_rc); // 装入/bin/sh 程序并执行。

_exit (2); // 若execve()执行失败则退出(出错码2,“文件或目录不存在”)。

}
[后面省略了]

即/bin/sh这个解释程序一直在运行着,然后等待着用户在命令行中输入信息。
假如就是 hello 程序,这样就回到了前面的问题了。

赵博士的《linux内核完全剖析》一书中在exec.c程序中有这样的描述:
“当一个程序使用fork()函数创建了一个子进程时,通过会在该子进程中调用exec()函数簇之一以加载执行另一个新程序。”
这里的“exec()函数簇之一”应该就是指:execve() 函数了,而这个execve()函数是通过宏定义来实现的,宏定义中就是
通过汇编完成“系统中断调用”,对应的中断向量号是0x80,采用的调用功能号是 __NR__EXECVE ,代码如下:

通过宏来完成对execve()函数的定义:

_syscall3 (int, execve, const char *, file, char **, argv, char **, envp)

#define _syscall3(type,name,atype,a,btype,b,ctype,c) \
type name(atype a,btype b,ctype c) \
{ \
long __res; \
__asm__ volatile ( "int $0x80" \
: "=a" (__res) \
: "" (__NR_##name), "b" ((long)(a)), "c" ((long)(b)), "d" ((long)(c))); \
if (__res>=0) \
return (type) __res; \
errno=-__res; \
return -1; \
}

所以调用 execve() 函数时,就会调用用C声明的sys_execve()函数,而sys_execve()函数的实现是直接通过汇编写的(开头部分)。
...全文
8245 61 打赏 收藏 转发到动态 举报
写回复
用AI写文章
61 条回复
切换为时间正序
请发表友善的回复…
发表回复
yaya_lucky 2012-09-11
  • 打赏
  • 举报
回复
mark
chenmo074639 2012-05-03
  • 打赏
  • 举报
回复
想研究,不过还没入门
jsy5211 2012-04-19
  • 打赏
  • 举报
回复
==晚上有时间 在研究
爱若一生 2012-04-12
  • 打赏
  • 举报
回复
每天回帖即可获得10分可用分!小技巧
zmkkobe 2012-03-26
  • 打赏
  • 举报
回复
讲解的很精细啊,呵呵
maofeisj 2011-12-21
  • 打赏
  • 举报
回复
同意二楼的说法
hellochick 2011-10-20
  • 打赏
  • 举报
回复
学习了,精彩
wlqiuxing 2011-09-23
  • 打赏
  • 举报
回复
把人说晕了大哥们。。。
flylee 2011-08-10
  • 打赏
  • 举报
回复
mark,学习
elitor 2011-07-17
  • 打赏
  • 举报
回复
up。
大道曙光 2011-07-13
  • 打赏
  • 举报
回复
mark study
Quietly 2011-06-10
  • 打赏
  • 举报
回复
学习了……
xchl1127 2011-04-26
  • 打赏
  • 举报
回复
看了一早晨,高手过招,厉害,学习了
zhanglibin_1222 2011-04-21
  • 打赏
  • 举报
回复
我是恐龙,我怕谁
zhanglibin_1222 2011-04-21
  • 打赏
  • 举报
回复
mark
mark
mark
mark
mark
LBen6501 2011-03-11
  • 打赏
  • 举报
回复
mark!
在这找到答案了~
a_liang_me 2011-01-23
  • 打赏
  • 举报
回复
ding.............
yutaooo 2010-10-14
  • 打赏
  • 举报
回复

mark 一会拜读。
long2015 2010-09-24
  • 打赏
  • 举报
回复
MARK
sleepsheep79 2010-09-17
  • 打赏
  • 举报
回复
MARK
加载更多回复(40)

4,436

社区成员

发帖
与我相关
我的任务
社区描述
Linux/Unix社区 内核源代码研究区
社区管理员
  • 内核源代码研究区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧