[问题出自jyy老师]
[回答出自FAI]
在执行 execve 之后,动态链接的二进制文件的第一条指令通常位于 动态链接器(Dynamic Linker 或 Loader) 的入口,而不是直接进入程序的 main 函数。
执行过程分析
1. execve 加载 ELF 可执行文件
- execve 加载 ELF 头,并解析 .interp 段(如果是动态链接的 ELF)。
- 读取 .interp 段,找到动态链接器(通常是 /lib64/ld-linux-x86-64.so.2 或类似的路径)。
- 内核 不会直接执行二进制的入口点(Entry Point),而是先执行动态链接器。
2. 控制流转移到动态链接器
- 动态链接器的第一条指令在 ld.so 的 entry 处,这个地址可以通过
readelf -h /lib64/ld-linux-x86-64.so.2
查看。 - ld.so 会解析并加载二进制程序的依赖库,重定位符号,并进行 constructor 调用。
3. 最终跳转到程序入口
- 在完成动态链接后,ld.so 通过 jmp 或 call 将控制权交给可执行文件的 entry(ELF 头 e_entry 指定的地址)。
- 这个 entry 处的第一条指令通常是 _start(由 crt1.o 提供)。
- _start 负责调用 __libc_start_main,最终进入 main。
如何找到第一条执行的指令
1. 动态链接器的入口
readelf -h /lib64/ld-linux-x86-64.so.2 | grep Entry
2. 可执行文件的入口
readelf -h my_binary | grep Entry
调试 execve 后的第一条指令
3.调试execve后的第一条指令
gdb --args ./my_binary
(gdb) b _start
(gdb) r
总结
- execve 后的第一条指令通常是动态链接器 ld.so 的入口,而不是可执行文件本身的 _start。
- ld.so 负责加载共享库、解析符号,完成初始化后才会跳转到 entry 处(通常 _start)。
附录:
怎么解析二进制的 .interp 段内容?请参考:查看二进制程序内的 .interp 段