欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 房产 > 建筑 > 【Linux系统】Linux中可执行程序的真正起始位置是 main ?

【Linux系统】Linux中可执行程序的真正起始位置是 main ?

2025/2/24 0:59:09 来源:https://blog.csdn.net/2301_79499548/article/details/145260250  浏览:    关键词:【Linux系统】Linux中可执行程序的真正起始位置是 main ?




在这里插入图片描述



查看 <_start> <main>

我将我们的可执行程序 main.exe 反汇编后,看一下会汇编层面的可执行程序

命令 objdump -S main.exe

命令 objdump -S main.exe > main.s :为了后续容易查询该反汇编代码,重定向放到 main.s

在这里插入图片描述



如图,main.s 文件中存储着可执行程序 main.exe 的反汇编程序

在可执行程序文件中,存储执行程序的区域是 .text

我们可以查看一下 .text

在这里插入图片描述


我们再查看一下该数据节 .textmain 部分:

在这里插入图片描述



<_start> <main> 的区别


数据节 .text<_start> ,这个才是 Linux 中程序执行的真正起始,而并不是从 main 函数开始执行,准确来说 ,main 函数是语言用户层面的程序执行起始点。

_start 是由编译器和链接器生成的一个特殊的入口点,负责设置程序的运行环境,然后调用 main 函数。这个过程通常被称为程序的初始化阶段。

_startmain 的关系

1、_start 入口点

  • _start 是 ELF 可执行文件的真正入口点。
  • 它是由编译器和链接器生成的,通常位于 CRT(C Runtime)代码中。
  • _start 负责设置程序的运行环境,包括初始化全局变量、设置栈指针、传递命令行参数等。

2、main 函数

  • main 函数是用户编写的程序的起点。
  • _start 完成初始化后,控制权会传递给 main 函数。



既然我们认识到,<_start> 程序才是一个可执行程序执行的入口起始位置,

那么 CPU 是如何知道我应该从 <_start> 开始执行该程序?同时又是如何开始进入并执行 <main> 函数的代码?



_start 函数中的初始化操作


_start 函数中,会执行一系列初始化操作,这些操作包括:

1、设置堆栈:为程序创建一个初始的堆栈环境。

2、初始化数据段:将程序的数据段(如全局变量和静态变量)从初始化数据段复制到相应的内存位置,并清零未初始化的数据段。

3、动态链接:这是关键的一步,_start 函数会调用动态链接器的代码来解析和加载程序所依赖的动态库(shared libraries)。动态链接器会处理所有的符号解析和重定位,确保程序中的函数调用和变量访问能够正确地映射到动态库中的实际地址。


动态链接器:

  • 动态链接器(如 ld-linux.so)负责在程序运行时加载动态库。
  • 当程序启动时,动态链接器会解析程序中的动态库依赖,并加载这些库到内存中。

环境变量和配置文件:

  • Linux 系统通过环境变量(如 LD_LIBRARY_PATH)和配置文件(如 /etc/ld.so.conf 其子配置文件)来指定动态库的搜索路径。
  • 些路径会被动态链接器在加载动态库时搜索。

缓存文件:

  • 为了提高动态库的加载效率,Linux 统会维护一个名为 /etc/ld.so.cache 的缓存文件。
  • 该文件包含了系统中所有已知动态库的路径和相关信息,动态链接器在加载动态库时会首先搜索这个缓存文件。

4、调用 __libc_start_main:一旦动态链接完成,_start 函数会调用 __libc_start_main,从而最终跳转到 main 函数开始执行程序的主要逻辑。

5、调用 main 数:最后,__libc_start_main 函数会调用程序的 main 函数,此时程序的执行控制权才正式交给用户编写的代码。

6、理 main 函数的返回值:当 main 数返回时,__libc_start_main 会负责处理这个返回值,并最终调用 _exit 函数来终止程序。

上述过程描述了 C/C++ 程序在 main 函数之前执行的一系列操作,但这些操作对于大多数程序员来说是透明的。程序员通常只需要关注 main 数中的代码,而不需要关心底层的初始化过程。然而,了解这些底层细节有助于更好地理解程序的执行流程和调试问题。



可执行程序的入口地址 Entry point address

前置知识:

1、可执行程序是一种 ELF 格式的文件,该格式文件的文件头 ELF Headers 中记录着一个属性: Entry point address

2、 Entry point address 指向汇编代码中 <_start> 的起始地址,说明该属性就存储着本程序的执行入口

3、CPU 中存在一个 PC 指针,该指针通过接收进程程序的地址,来识别并执行该指令,进而运行该程序



正文:

在可执行程序 main.exeELF格式中的 Entry point address ,就代表该程序的真正入口!

指向汇编代码中 <_start> 的起始地址,因此也证明了 <_start> 才是一个可执行程序的真正入口。

在程序 <_start> 里面,会发现调用 main函数 的指令,这也证明了:一个程序在进入 main函数 执行语言层面的指令之前,会在程序 <_start> 里面,做一些初始化配置工作。

在这里插入图片描述

系统只需要将 Entry point address 的值给 CPUPC 指针, CPU 就能从 PC 指针的值开始执行对对于的代码,真正开始运行一个程序。


另外,因为 Entry point address 记录的汇编代码中 <_start> 的起始地址,本质上也是虚拟地址,

因此 CPU 拿到并执行的 Entry point address ,也当然是虚拟地址!!

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词