专业的编程技术博客社区

网站首页 > 博客文章 正文

[Linux C/C++]Hello world程序的入口点到底是什么?

baijin 2024-10-20 04:09:25 博客文章 11 ℃ 0 评论

程序的入口点是程序在内存中开始执行的首地址。当操作系统加载一个可执行文件时,它会将程序的代码和数据加载到内存中,并跳转到程序的入口点的地址开始执行程序。

在Linux平台上,我们以如下经典的hello world程序为例:

[root:~/work/v1/hello]# cat hello.c
//File Name: hello.c
//The hello world program
#include <stdio.h>
int main()
{
      printf("hello, world\n");
      return 0;
}
[root:~/work/v1/hello]#

假设这个hello.c源程序经过GCC编译后的可执行程序为hello。那么这个简单程序在编译后,其运行的入口点到底是什么呢?很多同学可能认为是main函数,也有同学说是hello ELF文件的_start的地址。

其实hello程序的入口点与对hello.c进行动态链接还是静态链接有关系。

  • 对于静态链接的程序,程序开始执行的入口点是hello程序的_start符号的地址。
  • 对于动态链接的程序,其在执行前需要加载器动态链接库文件,并进行动态重定位,这些工作都是由动态链接器ld.so来完成。对于动态链接的可执行程序,需要首先执行ld.so,所以其入口点为动态链接器ld.so的入口点(_start)。

对于静态链接的程序,其执行过程如下图所示:

对于动态链接的程序,其执行过程如下图所示:

如何查看程序运行的入口点呢?

GDB有一个starti指令,starti指令用于启动程序并停止在程序的第一条指令上。

(gdb) help starti
Start the debugged program stopping at the first instruction.

通过gdb启动hello程序,然后通过starti指令让程序运行并停止在程序的第一条指令上。

检查静态链接的hello程序的入口

编译:

[root:~/work/v1/hello]# gcc -static -g -o hello hello.c
[root:~/work/v1/hello]# file hello
hello: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, BuildID[sha1]=7abb97dc49af6aeaac3d0c5c5a532d6f17c77eca, for GNU/Linux 3.2.0, with debug_info, not stripped
[root:~/work/v1/hello]#

检查入口点:

[root:~/work/v1/hello]# gdb ./hello
Reading symbols from ./hello...
(gdb) starti
Starting program: /root/work/v1/hello/hello

Program stopped.
0x0000000000401be0 in _start ()
(gdb)

检查hello文件中的_start符号:

[root:~/work/v1/hello]# readelf -s hello | grep -w _start
1295: 0000000000401be0 47 FUNC GLOBAL DEFAULT 7 _start
[root:~/work/v1/hello]#

通过反汇编查看hello程序中的_start:

objdump -d hello > hello_static.dump

然后可以在hello_static.dump中找到_start符号:

0000000000401be0 <_start>:
401be0: f3 0f 1e fa endbr64
401be4: 31 ed xor %ebp,%ebp
401be6: 49 89 d1 mov %rdx,%r9
401be9: 5e pop %rsi
401bea: 48 89 e2 mov %rsp,%rdx
401bed: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp
401bf1: 50 push %rax
401bf2: 54 push %rsp
401bf3: 49 c7 c0 a0 2d 40 00 mov $0x402da0,%r8
401bfa: 48 c7 c1 00 2d 40 00 mov $0x402d00,%rcx
401c01: 48 c7 c7 05 1d 40 00 mov $0x401d05,%rdi
401c08: 67 e8 92 04 00 00 addr32 callq 4020a0 <__libc_start_main>
401c0e: f4 hlt
401c0f: 90

可以看到,GDB调试hello程序时停止的第一条指令的地址为: 0x0000000000401be0, 这正是hello程序中_start符号的地址。所以对于静态链接的hello程序,其运行时的入口点为_start的地址。

检查动态链接的hello程序的入口

对于动态链接的可执行程序,其在执行前都需要加载动态链接库,并进行动态重定位,这些工作都是由ld.so来完成。对于动态链接的可执行程序,由于首先要加载并运行ld.so,所以对于动态链接的程序,其入口点为ld.so的入口点(_start)。我们可以通过gdb的starti指令来进行检查:

[root:~/work/v1/hello]# gcc -g hello.c -o hello

通过file命令可以看到hello为动态链接的可执行文件,如下:

[root:~/work/v1/hello]# file hello
hello: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=500380986e87b017e06ae8854782234dec8b43eb, for GNU/Linux 3.2.0, with debug_info, not stripped

通过GDB来检查动态链接的hello程序的入口:

[root:~/work/v1/hello]# gdb ./hello
Reading symbols from ./hello...
(gdb) starti
Starting program: /root/work/v1/hello/hello

Program stopped.
0x00007ffff7fd0100 in _start () from /lib64/ld-linux-x86-64.so.2
(gdb)

可以看到,通过gdb的starti指令,可以看到程序停在了ld-linux-x86-64.so.2的_start符号的入口上。所以对于动态链接的可执行程序,其入口点为动态链接器ld.so的_start。


Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表