刨根问底之C程序编译链接

        之前对C程序的编译过程一直似懂非懂,今天终于动手验证了一把心中的疑惑,第一个疑惑是:一个普通的 .c 文件(不含main())编译出来的 .o 文件是怎么被链接的?比如我们有如下两个文件:test.c 和 mlib.c,其中test.c中包含main函数,mlib.c包含一个全局变量和一个函数:

mlib.c:

int i = 2;
void fun(){}
test.c:

#include<stdio.h>
extern i;
void main(){printf("%p",&i);}

现在我们单独编译mlib.c文件生成一个mlib.o文件,然后使用nm命令观察mlib.o的符号表,以下是输出结果:

00000000    T    fun
00000000    D   i
该符号表中输出了两个符号,分别是fun和i,二者的偏移地址均为0. 作为对比,现在单独编译test.c文件,然后使用nm命令查看test.o文件,输出结果如下:

                   U   i
00000000   T   main
                   U  printf

该符号表中输出了两个未决义符号:printf 和 i,所以这两个符号的偏移量也是未知的。当然,在最终的可执行文件中,这些符号的地址都应该是确定的,这个工作是连接器完成的,下面我们将mlib.o和test.o链接在一起(gcc -o test test.o mlib.o),然后使用nm查看生成的test(nm test):

080483c0      t       frame_dummy
08048404     T      fun
0804a014     D     i
080483e4     T     main
                     U     printf@@GLIBC_2.0

其实输出了一大堆,这里只看我们感兴趣的,可以看到已经给 i 分配了位于0804a014处的一块内存,也给 fun 分配了相应的内存,大家或许注意到printf的位置仍然是未知的,因为printf是动态链接的,而动态链接是在程序执行过程中完成的,我们可以执行一下test,输出结果如下:

0x804a014

可以看到输出的地址确实是 i 的地址,因此链接之后便给相应的变量、函数分配了内存,程序执行时操作系统将直接把可执行文件载入到内存中执行。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值