04动态库制作之解释生成与位置无关的代码原理
04动态库制作之解释生成与位置无关的代码原理
1 讲述
其实生成与位置无关的代码是很简单的,就是和静态库差不多,只不过加多了参数选项。即
“gcc -c main.c -o main.o -fPIC”
但是,这一篇我们主要分析它的原理,它为何要这样做。
2 分析为何要生成与位置无关的代码
看图解析
1)我们main.c(即图中a.out)中有函数定义fun1与fun2,fun1,fun2都是源程序自带函数,不属于动态库函数。当生成main.o文件时,这两个函数都会被汇编生成目标代码,有着确定的首地址(因为mian进行地址回填时默认赋值为0);然后最后进行链接,将对应xxx.o文件进行数据段合并和地址回填。 但是解析到这里,与生成位置无关的代码有什么关系呢?我们继续往下分析。
2)当我们运行a.out时(链接完成了),执行到fun3动态库的函数,该动态库就会被加载到内存,然后调用该函数;但是,我们怎么找到这个函数呢?它的地址是多少呢?有点人可能会说,1000+300呗,但是,你想想,如果在fun3调用之前还有fun0,fun100…等等呢?那这个动态库函数首地址又是多少呢?
3)所以这时就需要我们生成一个与位置无关的代码了,这就是我们讲述中将xxx.c生成xxx.o时要添加选项-fPIC了。
3 查看可执行文件,观察与位置无关的代码首地址格式是怎么样的
1)首先,我们对生成的可执行文件test输入一下命令,意思是将test二进制文件以反汇编代码显示,并重定向至out中。
2)观察反汇编代码。
4 何时将位置无关的代码变成确定的地址
1)上面第二张图可以看到反汇编的部分代码,printf就是一个动态库的函数,因为它的格式有"@plt",这是在制作动态库时,在xxx.c生成xxx.o生成的与位置无关的代码首地址(伪代码)。
那么这个"@plt是怎么转成确定的地址呢?
2)当动态库函数fun3被调用时,动态库会被加载到内存,这样里面的函数就有了地址,此时"@plt"就会被地址替换掉,这样就变成了确定的地址了。
3)所以,一些书会将动态库函数的调用称之为 “延时调用”,因为只有动态库被加载,地址才会确定下来。
5 总结
这一篇我们了解了为何在xxx.c生成xxx.o文件要生成与位置无关的代码原理后,下一篇将介绍制作动态库的步骤。
其实,这一篇只有第二点,第四点是重要的,理解这两点你就明白了这篇文章的意思。