ELF之链接初探
示例程序
/* a.c */ |
链接过程
主要分为两步:
1.空间和地址分配
2.符号解析和重定位
空间和地址分配
主要涉及到相似节合并和虚拟地址空间的分配以及映射关系的建立,可以观察到VMA在链接之后被分配
root@L:/home/l/c++ |
符号解析和重定位
先来看一下结果
可以看到符号的地址已经变成了VMA
root@L:/home/l/c++ |
重定位表
typedef uint64_t Elf64_Addr; |
本程序实例
可以用工具需要重定位的位置,这里有个问题,就是值都是地址减4感觉是个问题,call的话明明需要减去下一条指令的地址才对,有机会研究一下。
root@L:/home/l/c++ |
小结
到了这里大概已经了解了汇编到链接的粗浅的过程,虽然没有看过源码的实现,但是也粗浅猜测一下,最重要的就是节表和elf头表,这两个表看起来可以定位elf中的所有元素,节中元素只需要考虑对节的相对偏移即可,接下来的每一步操作只要维护节表和头表即可,看到这里感觉字符串表完全是可以省略的东西,但是一想链接需要名字来识别,但是可执行文件估计就可以少了好多东西。
/*可以看到是有字符串表的*/ |
关于common
书中也讲了弱符号同名该如何处理,将了一种common块的知识,但是目前gcc貌似弃用了这玩意,直接在bind中表明这东西是弱符号。
fcommon选项都不起作用了
int printf(const char* format, ...); |
杂记
重复代码消除
非常高视角的讨论一下,有个印象
c++的模板的实现,函数级别的链接,都涉及到代码的消除,否则会产生重定义的问题。具体的方法有,将不同函数放在不同的段,相同函数放在相同的段,链接的时候只保留一个。至于函数级别的链接,则涉及到无用函数的消除,但是会加大链接和汇编的成本。
c++与ABI
一句话来说是api是为了源码级别的兼容,在提供相应接口的os上,接口的行为是一样的。如posix标准,规定了一些列操作系统应该提供怎么样的接口的标准。而c库开发者若使用这些接口就很容易在不同的os上移植这些库。(粗显介绍)
至于ABI,则是应用二进制接口,就是不同的平台的二进制文件可以相互移植,基本上就是你windows的操作系统也可以处理linux的elf文件,看到这里,还是有点可能,毕竟这种文件格式的定义都是在c库中的实现,但是就算是文件结构可以合并到一起,又如何在一个机器上同时执行2种汇编代码呢?虚拟机吗?但是这不是兼容两种型号,是兼容多种型号,该如何实现?不知道了。