[汇编与C] main 函数和启动例程

为什么汇编程序的入口是 _start,而 C 程序的入口是 main 函数呢?现在我们来解释这个问题。Linux 中汇编和链接步骤是:

[test@localhost Assembler]$ as test.s -o test.o
[test@localhost Assembler]$ ld test.o -o test

以前我们常用 gcc main.c -o main 命令编译一个程序,其实也可以分三步做,第一步生成汇编代码,第二步生成目标文件,第三步生成可执行文件:

[test@localhost Assembler]$ gcc -S main.c 
[test@localhost Assembler]$ gcc -c main.s 
[test@localhost Assembler]$ gcc main.o

-S 选项生成汇编代码,-c 选项生成目标文件,-E 选项只做预处理而不编译,如果不加这些选项则 gcc 执行完整的编译步骤,直到最后链接生成可执行文件为止。如下图所示。

gcc
这些选项都可以和 -o 搭配使用,给输出的文件重新命名而不使用 gcc 默认的文件名 (xxx.c、xxx.s、xxx.o a.out),例如 gcc main.o -o mainmain.o 链接成可执行文件 main。先前由汇编代码生成的目标文件 test.o 我们是用 ld 来链接的,可不可以用 gcc 链接呢?试试看。

[test@localhost tmp]$ gcc test.o -o test
test.o:在函数‘_start’中:
(.text+0x0): multiple definition of `_start'
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crt1.o:(.text+0x0):第一次在此定义
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crt1.o:在函数‘_start’中:
(.text+0x20):对‘main’未定义的引用
collect2: 错误:ld 返回 1

提示两个错误:一是 _start 有多个定义,一个定义是由我们的汇编代码提供的,另一个定义来自 /usr/lib64/crt1.o;二是 crt1.o_start 函数要调用 main 函数,而我们的汇编代码中没有提供 main 函数的定义。从最后一行还可以看出这些错误提示是由 ld 给出的。由此可见,如果我们用 gcc 做链接,gcc 其实是调用 ld 将目标文件 crt1.o 和我们的 hello.o 链接在一起。crt1.o 里面已经提供了 _start 入口点,我们的汇编程序中再实现一个 _start 就是多重定义了,链接器不知道该用哪个,只好报错。另外,crt1.o 提供的 _start 需要调用 main 函数,而我们的汇编程序中没有实现 main 函数,所以报错。
如果目标文件是由 C 代码编译生成的,用 gcc 做链接就没错了,整个程序的入口点是 crt1.o 中提供的 _start,它首先做一些初始化工作(以下称为启动例程,Startup Routine),然后调用 C 代码中提供的 main 函数。所以,以前我们说 main 函数是程序的入口点其实不准确,_start 才是真正的入口点,而 main 函数是被 _start 调用的。
我们继续研究函数的调用过程。如果分两步编译,第二步 gcc main.o -o main 其实是调用 ld 做链接的,相当于这样的命令:

[test@localhost tmp]$ ld /usr/lib64/crt1.o /usr/lib64/crti.o main.o -o main -lc -dynamiclinker /lib64/ld-linux-x86-64.so.2

也就是说,除了 crt1.o 之外其实还有 crti.o,这两个目标文件和我们的 main.o 链接在一起生成可执行文件 main-lc 表示需要链接 libc 库,-lc 选项是 gcc 默认的,不用写, 而对于 ld 则不是默认选项,所以要写上。-dynamic-linker /lib64/ld-linux-x86-64.so.2 指定动态链接器是 /lib64/ld-linux-x86-64.so.2,稍后会解释什么是动态链接。
那么 crt1.ocrti.o

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值