链接器

Posted 阿弥陀佛.a

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了链接器相关的知识,希望对你有一定的参考价值。


链接目标文件,整合在一起得到可执行程序




标识符func相对于代码段的地址
g_pointer标识符大小为4字节,C:暂时不知道放在哪一个段


g_global在bss段,相对于bss段地址为0(地址不知道)
g_test位于data段
main位于代码段

通过链接后,得到test.out,此时重定位,给段中标识符最终的地址(nm test.out):




反编译program.out放到result.txt文件里去:

先查找main地址,然后搜索这个地址,发现在_start函数中有这个地址信息,push:将main函数压入栈中,执行_libc_start_main函数
_start函数将main函数地址作为参数调用_libc_start_main函数
start函数地址与代码段起始地址一致,段位于内存之后,pc指针指向代码段第一条指令




链接成功,执行后成功打印,并且正常退出

可以看出代码段只有一个函数:program函数
再通过objdump查看代码段起始地址,与program函数起始地址一致:



意义:

-nostartfiles:在链接时不使用系统标准启动文件

原则:


链接脚本指导链接器工作

.text 0x2000000 相当于重定位
* 代表通配符,代表每一个文件的代码段,整合在一起
. 代表指针
S 在链接脚本表示标识符 将地址赋值给标识符,重定位S,让S位于指针所指之处。S代表0x8000000内存的别名
data段起始地址:0x3000000,*(.data)代表将所有文件代码段整合在一起
bss段会根据目标平台的规范自动重定位

创建两个文件:.c .lds(链接标本)

先普通的编译得到可执行程序:

接下来使用链接脚本:

为什么发生段错误?
因为代码段/数据段的起始地址都是随便给的,没有遵循目标平台的规范…
因此证明链接脚本的存在,链接器遵循连接脚本的规则!

分别使用objdump -h(左边是正常的可执行我呢见text.out,右边是发生段错误的test-lds.out)

从右边可以看出链接脚本起作用了,代码段数据段都是我们自定义的
接下来根据Linux平台规范修改段地址:


可以正常运行!

继续试验:

将s1重定位至地址0x01000000初,并生成可执行文件:

在链接脚本中定义s2变量,在test.c中使用:








说明链接脚本起作用了,objdump -h查看代码段起始地址:


说明program在链接之后,代码段起始地址就是program的入口地址

以下知识在复习《汇编语言嵌入编程》后再来复习






上述冒号(:)前面要打一个空格,不然报错!!!
GNU链接器的真身:ld
默认动态链接,但是需要模拟嵌入式设备开发,所以我们需要使用静态链接


实验:



得到.o文件(不使用内嵌函数):


不使用内嵌函数,完成打印功能:

使用正常的printf函数完成上述功能,然后对比大小:

可以看出test文件比我们的文件大很多

以上是关于链接器的主要内容,如果未能解决你的问题,请参考以下文章

如何设置 code::blocks 以在目标链接器选项之前链接项目链接器选项?

为啥链接器无法识别我的链接器脚本中定义的入口点

链接器下——链接器实战

初识OpenGL 链接着色器

初识OpenGL 链接着色器

Delphi链接器和C++链接器的区别