Linux可执行程序启动流程

进程是如何启动的?

进程启动过程

示例代码

#include <stdio.h>
int main()
{
        printf("hello,world\r\n"); 
        return 0;
}

启动两个终端,使用strace命令跟踪进程启动过程strace -f -s 655000 -i -T -o output.txt -p 19510
各个选项参考strace的man手册
-f 跟踪由进程及其子进程发出的系统调用
- s 设置 strace 打印的字符串的最大长度
- i 在打印每条系统调用时,同时打印该调用的指令指针
- T 显示每次系统调用花费的时间
- o 将 strace 的输出重定向到文件中
-p 指定 strace 要跟踪的进程ID
其他选项参考man手册,截取出的有效记录如下

  • 1 19510 它是bin/bash程序启动的 19510它是进程的标识
  • 19510 [00007ffb18a075e2] clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7ffb1934ca10) = 19889 <0.000188>
  • 2 19510进程调用clone/fork 系统函数并执行得到了一个新的子进程,这个新的子进程是19889 ,此时19510进程调用wait4在此阻塞
  • 19510 [00007ffb18a0725b] wait4(-1, <unfinished ...>
  • 3 新进程19889此时调用相关系统函数函数 execve 加载ELF可执行文件 demo2,[“./demo2”] 是命令行参数【执行参数】
    0x55c2a06d6690 /* 32 vars */ 是环境表 【环境参数】 是公共的,在Linux是供所有应用程序可以使用的公共数据
  • 19889 [00007ffb18a086fb] setpgid(19889, 19889) = 0 <0.000004> 19889 [00007ffb18a0782b] execve("./demo2", ["./demo2"], 0x55c2a06d6690 /* 32 vars */) = 0 <0.000394>
  • 4 加载所依赖的相关库文件 libc.so.6文件 ELF 文件 共享目标文件 共享库 【动态库】
  • 19889 [00007f551f604af1] openat(AT_FDCWD, "/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3 <0.000009>
  • 19889 [00007f551f604bb8] read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\2009\2\0\0\0\0\0@\0\0\0\0\0\0\0\200_[\0\0\0\0\0\0\0\0\0@\08\0\v\0@\0L\0K\0\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0h\2\0\0\0\0\0\0h\2\0\0\0\0\0\0\10\0\0\0\0\0\0\0\3\0\0\0\4\0\0\0\260\347\30\0\0\0\0\0\260\347\30\0\0\0\0\0\260\347\30\0\0\0\0\0\34\0\0\0\0\0\0\0\34\0\0\0\0\0\0\0\20\0\0\0\0\0\0\0\1\0\0\0\5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\334\217\33\0\0\0\0\0\334\217\33\0\0\0\0\0\0\0 \0\0\0\0\0\1\0\0\0\6\0\0\0(\226\33\0\0\0\0\0(\226;\0\0\0\0\0(\226;\0\0\0\0\0XR\0\0\0\0\0\0\370\221\0\0\0\0\0\0\0\0 .....
  • 5 进程执行调用系统函数write向屏幕输出 字符串 “hello,world"的内容 上层的应用函数是printf 【打印函数,是标准库stdio.h头文件声明的】
    write在libc.so.6库里
  • 19889 [00007f551f312e18] write(1, "hello,world\r\n", 13) = 13 <0.000105>
  • 6 此时子进程19889调用系统函数exit_group(0) 退出进程 这个0它是进程退出状态码
  • 19889 [00007f551f2ee7f6] exit_group(0) = ? 19889 [????????????????] +++ exited with 0 +++
  • 7 父进程19510调用wait4回收退出的子进程 [{WIFEXITED(s) && WEXITSTATUS(s) == 0}] WIFEXITED 这是一个宏函数 WEXITSTATUS 拿到退出状态码
    0 退出状态码 19889 退出的子进程标识符 并且回收退出进程的内存资源 ,经过这些流程整个进程执行结束
  • 19510 [00007ffb18a0725b] <... wait4 resumed>[{WIFEXITED(s) && WEXITSTATUS(s) == 0}], WSTOPPED|WCONTINUED, NULL) = 19889 <0.002737>

总结

  • 在bin/bash或者其他解释器脚本中执行可执行文件,解释器脚本会调用clone/fork生成一个子进程,父进程等待子进程退出,子进程调用execve加载ELF可执行文件(.txt、.data、.bss段以及环境表)覆盖原有的参数,随意调用_libc_start_main启动主函数,子进程执行完成后,父进程resumed等到子进程的退出状态码
  • 7
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值