29|C 程序的入口真的是 main 函数吗?
于航
该思维导图由 AI 生成,仅供参考
你好,我是于航。
“main 函数是所有 C 程序的起始入口”,相信对于这句话,每个同学在刚开始学习 C 语言时都很熟悉,因为这是一个被各种教材反复强调的“结论”。但事实真是如此吗?
实际上,这句话对,但也不完全对。在一段 C 代码中定义的 main 函数总是会被优先执行,这是我们在日常 C 应用开发过程中都能够轻易观察到的现象。不过,如果将目光移到那些无法直接通过 C 代码触达的地方,你会发现 C 程序的执行流程并非这样简单。
接下来,我们先通过一个简单的例子,来看看在机器指令层面,程序究竟是如何执行的。
真正的入口函数
这里,我们首先在 Linux 系统中使用命令 “gcc main.c -o main” ,来将如下所示的这段代码,编译成对应的 ELF 二进制可执行文件。
在上述代码中,由于没有使用到任何由其他共享库提供的接口,因此,操作系统内核在将其对应的程序装载到内存后,会直接执行它在 ELF 头中指定的入口地址上的指令。紧接着,使用 readelf 命令,我们可以获得这个地址。然后,通过 objdump 命令,我们可以得到这个地址对应的具体机器指令。
我将这两个命令的详细输出结果放在了一起,以方便你观察,如下图所示:
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
- 深入了解
- 翻译
- 解释
- 总结
C程序的入口并非完全是main函数,实际上是由链接器默认使用的_start符号所指代的。该符号在链接过程中被放入可执行文件的ELF头的e_entry字段中,由操作系统内核直接执行。文章详细解释了_start符号的由来和作用,以及通过GNU的C运行时库glibc为例,展示了_start的具体实现。在程序执行前,_start完成了对main函数地址、argc、argv等参数的准备工作,并调用了__libc_start_main函数,为程序的执行做了一系列前期准备工作。CRT为应用程序提供了对启动与退出、C标准库函数、IO、堆、C语言特殊实现、调试等多方面功能的实现和支持。CRT的实现是平台相关的,与具体操作系统结合得非常紧密。文章通过深入分析程序执行的底层机制,揭示了C程序入口的真相,为读者提供了深入理解程序执行过程的视角。
仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《深入 C 语言和程序运行原理》,新⼈⾸单¥59
《深入 C 语言和程序运行原理》,新⼈⾸单¥59
立即购买
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
登录 后留言
全部留言(2)
- 最新
- 精选
- 一个工匠操作系统对 Shell 的执行,是靠 Shell 解释器完成的。在操作系统运行后,Shell 解释器本身就加载并运行了。其中如 pwd,cd 这些是内部命令,本质是函数调用,可以直接使用。ls 这些是外部命令,需要 fork 一个新进程执行当前命令。一个shell脚本,有很多个这些内外部命令组成,通过 shell 解释器逐行解释完毕后执行。shell 解释器也是一个应用程序,本质是一个 C 程序,不过在该程序中,手动模拟了函数调用栈,和 JVM 有相似之处。所以 shell 解释器,也有静态库/动态库/静态链接/动态链接这些,为 shell 命令的执行保障护航。
作者回复: 回答的很赞!
2022-03-308 - 神佑小鹿shell 本身就是个程序是运行在 Linux 上的进程,shell 内部命令的执行是在对应的 shell 进程内运行的,外部命令是不同的,要 fork 一个新进程~~2022-05-151
收起评论