当前位置:  技术问答>linux和unix

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

    来源: 互联网  发布时间:2016-05-13

    本文导语:  目前在看linux内核代码方面的东西,目前主要是文件系统FS这一块的内容。 在exec.c源码文件中,有一个函数 do_execve() 这个函数是会被 “系统调用”函数 sys_execve()会调用的,而sys_execve()是某进程通过“中断调用过程...

目前在看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()函数的实现是直接通过汇编写的(开头部分)。

|

我来说说:
1.sh本身是可执行程序, 和linux下其它可执行程序一样; 说他是解释程序,是因为他负责解释用户的输入,然后启动新进程来执
行用户输入的命令; sh 会解释用户的所有输入,判断他是否一个合法的命令,如果不是,会提示"找不到该命令 or 没有执行权限
等等"错误信息,如果是,那么就启动一个新进程来执行用户输入的命令,当然参数信息一起传递给execve()等系统调用. 最终进
入到内核入口函数sys_execve()等,进而执行do_execve(); 如果你要看shell的源代码,可以
去:http://www.gnu.org/software/bash/下载.

2. 当然是由sh fork()出来的, 一般来说,fork()和execve()函数族中的一个是配合使用的! fork()创建一个新进程,不过这个
是父进程(在这里就是sh)的一份copy(其实在物理上连copy都不是, 只是逻辑上是一个copy,因为内核采用写时复制技术).当调
用execve()系列函数的时候,才装入新的执行体(在你的例子中就是装入hello).

3. 子进程B在执行过程中, 只有在B的程序代码中你显示调用execve()函数,或者隐式调用了execve()系列函数(比如调用了
system()),那么才会调用到系统调用sys_execve(). 如果你在子进程B中没有这样的代码,它自己是不会无缘无故调用到sys_execve()的;

4. 首先,不明白说的init()函数是什么? init()应该是内核的一个函数, 该函数最终会启动用户空间的一个程序(通常叫做
init), 即: /sbin/init,一般来说是内核启动的第一个程序. 当然,这第一个程序你也可以通过给内核传递参数 
init=/sbin/xxx 来指定为其它程序(比如指定init=/bin/sh,那么你就可以在kernel启动之后立即获得一个shell,连用户名密码
都不需要). 通常来说, 如何得到第一个shell的呢? 大致来说一般如下: init检查/etc/inittab,并根据规则执行在inittab里
面的命令,在inittab文件中,一般会有类似"1:2345:respawn:/sbin/mingetty tty1"这样的规则, minegetty中就会调
用/bin/login, /bin/login执行就会打印出输入用户名的提示. 当用户正确输入用户名和密码之后, /bin/login就会根
据/etc/passwd文件中用户名对应的shell来启动该shell. 
这些内容比较多, 不是一两可以说的那么明了, 欢迎继续讨论!

good luck!

|
你需要把shell(如bash)跟shell程序(*.bsh)分清.

fork出来后,exec是子进程内调用的,父进程怎么可能去替换子进程的程序呢?这里也需要把进程跟可执行程序分清。

你的shell程序是否要运行完成才返回到shell来是看你是怎么运行的,哪果是加&运行就不需要等待,这里的区别只是父shell会不会wait子进程的退出状态的区别而已。



|
执行一条非shell内部命令如date如下


while(read command)
{
    fork()
   if child
   {
       find date where;
       exec date;
   }
   else //father
   {
      wait;       //wait child end;
   }
}
上面就是shell执行一条命令做的事情。

|
所以呢,这么看来,就有一点很是不理解: 
从这个示例代码看来 
while  (filename  is  executable)  
{  
    fork()  
    if  child  
    {  
            exec  filename 
    }  
    else  //father  
    {  
            wait;            //wait  child  end;  
    }  

是不是要这么理解: 
exec filename 这一代码行是子进程成功后,子进程在运行时所继续执行的代码。 
wait 这一代码行就是“创建子进程”失败后,继续由父进程在运行时所执行的代码。 
即上面这些代码是由不同的进程负责“在相关进程运行时”去执行相关代码的。 


我一直理解成了,这些代码只能是由当前一个父进程来完成执行的,而其实父进程也不会执行到exec这样的代码的. 
即这些代码是由多个进程“按需执行”一样。 

不知道这次理解是不是又出现偏差了 
]


-----------------------------------------
感觉你对fork还不是很明了,fork()有两个返回值,对父进程其返回值为子进程的pid,对子进程其返回值为0,因此通过if(fork()==0){exec filename;}else {wait;}父进程和子进程各自执行了一个操作,子进程exec了filename,而父进程wait子进程的返回状态。

|
sh只是一个命令集合而已 它会被shell解析 执行 实际的执行过程还是一个一个命令进行的
当然其中很多变量是由shell解析出来然后执行的

|


所以说你要明白进程跟执行程序的区别, "shell 即调用了 fork() 函数来创建一个子进程,然后也调用了 execve() 函数来加载并运行“待执行程序文件”"。这个exec明明就是在子进程里调用的啊. 不理解fork()?

|
你没有理解fork哦,不要以为一份代码就只是一个进程.fork后就分支了,后面根据fork的返回值分别进入了父进程跟子进程. wait是等待子进程执行结束,跟创建子进程是否成功无关,还是先去看看unix程序设计进程控制相关的内容吧

|
yes you got it

|
单从进程控制的角度看,fork后子进程复制了父进程的进程存储空间,因此在子进程exec之前两个进程的代码段是相同的,都要从if语句开始,至于是父进程先执行还是子进程先执行,这要看内核的调度算法了。

|
mark,一直没有勇气去内核。

|
up

|
mark

    
 
 

您可能感兴趣的文章:

  • shell 函数中的用exit时,什么情况下仅仅退出函数,什么情况下退出整个shell程序?
  • shell脚本如何调用另外一个shell脚本的函数?
  • 很菜,shell脚本中怎么写函数,怎么使用带参数的函数???
  • shell函数如何load?
  • 急:unix的shell脚本中,定义了一个函数getDate(),在后面的执行命令参数用要使用这个函数的返回值,应该怎么写?
  • shell脚本里的函数怎么调用??
  • shell函数如何返回字符串
  • 有关在makefile中使用shell函数的问题
  • shell获取main函数的返回值
  • 求救!makefile 中shell函数
  • shell函数求救
  • shell中函数的使用
  • shell内能不能写入函数?
  • PHP中exec函数和shell_exec函数的区别
  • Unix下System函数实现中为何要使用shell去调用执行程序?
  • 函数调用Shell命令问题
  • shell 函数返回值
  • shell 编程:写一个功能函数,打印根目录下所有文件大小
  • 很菜的,能否在我的C函数里调用SHELL吗?
  • linux下system函数调用shell命令后,怎样让主进程不等子进程返回,接着执行(在线)?
  • 帮我理清楚一下shell和perl之间的关系。
  • 不同的shell之间到底有何区别,与命令有关系吗
  • 关于QT与SHELL之间的问题
  • 问题:在linux系统中,怎么使用shell脚本,在文件的第三行和第四行之间新增一行(插入一段字符,或者一个变量的值)?
  • 请教大虾们:在shell脚本中如何用expr连续进行多个变量之间的计算
  • shell和c之间的变量传递问题,请教!
  • 在linux系统下,怎样编写shell脚本把当前目录下的文件(文件日期要求是2011年9月14日01点至2011年9月15日01点之间。。。。
  •  
    本站(WWW.)旨在分享和传播互联网科技相关的资讯和技术,将尽最大努力为读者提供更好的信息聚合和浏览方式。
    本站(WWW.)站内文章除注明原创外,均为转载、整理或搜集自网络。欢迎任何形式的转载,转载请注明出处。












  • 相关文章推荐
  • 傻瓜问题,请问shell编程和shell脚本编程的关系
  • bash 与shell 什么关系?
  • redhatlinux中shell和konsole是什么关系
  • C编程与shell编程有什么区别,两者有没有从属关系?
  • 请问在B Shell中如何表示以下关系:a=0 or 0<a<7啊?a=0 and a=11?哪里有Shell编程的详细资料下载啊?
  • Centos6下安装Shell下文件上传下载rz,sz命令
  • 不同类型的shell*(K SHELL , C SHELL) 用命令怎么切换?
  • linux bash shell命令:grep文本搜索工具简介
  • 我在执行shell时,想在shell里直接向mysql数据库插入数据,我该如何写shell。
  • Linux下指定运行时加载动态库路径及shell下执行程序默认路径
  • 菜鸟问问题:shell是什么呢?普通的ls、cp、pwd这些命令算不算shell呢?如何把自己写的文件变成shell呢?
  • 移动开发 iis7站长之家
  • shell变量和子shell的问题请教
  • linux bash shell命令:文本搜索工具Grep命令选项及实例
  • 请问“当前shell”和“子shell”的区别?
  • linux bash shell命令:文本搜索工具grep正则表达式元字符集(基本集)
  • 怎么知道当前是B_SHELL 还是C_SHELL
  • 用户登陆后运行某SHELL退出SHELL就回到LOGIN是怎么作到的?
  • 怎么写shell代码 写好shell怎么运行?
  • 请问一个shell中如何获取这个shell自身抛出的错误?
  • 非登录shell是什么 意思,和登录shell有什么区别啊
  • Solaris 8中修改root的shell为一个非法的Shell后怎么办?
  • 各位Shell高人,如何取得Shell的第10个入口参数?$10不行啊,急!
  • shell 编程 执行shell新建多个终端 并执行程序
  • 如何在一台机器上的shell中执行另外一台机器上的shell
  • 在shell中的交互问题,现在需要在shell结束时按某键或任意键


  • 站内导航:


    特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

    ©2012-2021,,E-mail:www_#163.com(请将#改为@)

    浙ICP备11055608号-3