如果我使用 gcc 编译一个程序,并尝试从 bash shell 执行它,那么 bash 执行它的确切步骤顺序是什么?
我知道涉及到fork()
,,,,(和其他事情),但是有人可以给出准确的步骤顺序和一些合适的阅读参考吗execve()
?loader
dynamic linker
编辑:
从答案来看,这个问题似乎蕴含着多种可能性。我想缩小范围到一个简单的情况:
(test.c 只是打印 hello world)
$ gcc test.c -o test
$ ./test
上述情况( )中的步骤是什么./test
,特别是在某些子进程中启动 bash 程序,进行加载、链接等?
答案1
嗯,确切的顺序可能会有所不同,因为可能有一个 shell 别名或函数在执行实际程序之前首先被扩展/解释,然后限定文件名 ( /usr/libexec/foo
) 与将在所有目录中查找的文件名之间存在差异环境PATH
变量(只是foo
)。此外,执行的细节可能会使事情变得复杂,因为foo | bar | zot
需要 shell 进行更多工作(一些fork(2)
、dup(2)
、当然还有 ,pipe(2)
以及其他系统调用),而类似的exec foo
工作则要少得多,因为 shell 只是将其自身替换为新程序(即,它没有fork
)。同样重要的是进程组(尤其是前台进程组,SIGINT
当有人开始混搭Ctrl+时,其所有 PID 都会被占用) C、会话以及作业是否将在后台运行、受监视 ( foo &
) 或后台被忽略 ( foo & disown
)。 /O 重定向细节也会改变一些事情,例如,标准输入是否被 shell ( foo <&-
) 关闭,或者文件是否作为 stdin ( foo < blah
) 打开。
strace
或类似的信息将提供有关此过程中进行的特定系统调用的信息,并且每个调用都应该有手册页。合适的系统级阅读可以是 Stevens 的“UNIX 环境中的高级编程”中的任意章节,而 shell 书籍(例如“从 Bash 到 Z Shell”)将更详细地介绍 shell 方面的内容。
答案2
假设教科书示例 shell(为了代码清晰)已经运行(因此动态链接器已完成),您提到的命令将要求 shell 进行以下系统调用:
- 读取:在本例中获取下一个命令 gcc
- fork:需要两个进程,我们假设父进程的 pid 为 500,子进程用于说明。
- 父进程将调用 wait(501),同时子进程将调用 exec。此时,shell 不再在 pid 501 上运行。gcc 进行大量系统调用,至少包括 open、close、read、write、chmod、fork、exec、wait 和 exit。
- 当gcc调用exit时,wait会返回,调用write来显示提示符,然后重复该过程。
当然,更复杂的命令会增加这个基本序列的复杂性。基本复杂性的两个简单示例是基本 io 重定向,其中在 fork 与 exec 和后台进程之间插入打开、关闭、dup 序列,其中跳过等待(并将另一个等待添加到 sigchld 处理程序)。
答案3
我建议阅读部分8.4.6 使用fork和execve运行程序
在 http://www.groupes.polymtl.ca/inf2610/documentation/ComputerSystemBook.pdf