重定位过程分析

当程序运行地址和链接地址不一样时,会有一段代码将程序复制到链接地址处,这个过程就是重定位。

首先加载_start的链接地址和运行地址到通用寄存器中,对应的指令分别为ldr r0,=_start和adr r1,_start;接着判断运行地址和链接地址是否相同,即判断r0和r1是否相同;不同进行重定位,

这是对上面汇编指令的介绍(网上查阅)

LDR
使用格式 :LDR
LDR用于从内存中将一个32位的字读取到指令的目标寄存器中,如果PC作为指令中的目标寄存器,指令就可以实现程序的跳转功能。
其实ARM的LDR指令有两种,一种就是LDR指令,另一个是LDR伪指令,它们的写法一样,但是含义不一样,伪指令的LDR有“=”,所以你所给的三个指令中,第一个LDR是ARM的LDR指令,第三个是ARM的伪指令LDR,伪指令LDR=后面的数是一个32位的立即数(可以立即为常量),在汇编编译源程序时,LDR 伪指令被编译器替换成一条合适的指令。若加载的常数未超出 MOV 或 MVN 的范围,则使用 MOV 或 MVN 指令代替该 LDR 伪指令;否则汇编器将常量放入文字池,并使用一条程序相对偏移的 LDR 指令从文字池读出常量。LDR 用于加载芯片外围功能部件的寄存器地址(32 位立即数),以实现各种控制操作。从 PC到文字池的偏移量必须小于 4 KB。

ADR伪指令
使用格式:ADR ,
ADR将一个基于PC或者寄存器的相对地址装载到寄存器R0中,主要限制是对expr这个地址的寻址范围,如果expr是字对齐的,那么它的寻址范围是(+-)1024字节,如果是非对齐的地址那么寻址范围只有(+-)255字节。它主要用于在一个小范围内读取数据。

具体使用到哪个汇编指令跳转取决于标签的类型和大小

ldr r0, _start

这是一条指令,从内存地址 _start 的位置把值读入。在这里_start是一个标号(是一个相对程序的表达式),汇编程序计算相对于 PC 的偏移量,并生成相对于 PC的前索引的指令:ldr r0, [pc, #4]。执行指令后,r0 =0xeafffffe。
ldr r0, _start是根据_start对当前PC的相对位置读取其所在地址的值,因此可以在和_start标号的相对位置不变的情况下移动。
adr r0, _start

这是一条伪指令,总是会被汇编程序汇编为一个指令。汇编程序尝试产生单个 ADD或 SUB 指令来装载该地址。如果不能在一个指令中构造该地址,则生成一个错误,并且汇编失败。在这里是取得标号_start 的地址到 r0,因为地址是相对程序的,因此ADR产生依赖于位置的代码,在此例中被汇编成:add r0, pc, #0。因此该代码可以在和标号相对位置不变的情况下移动;假如这段代码在 0x30000000 运行,那么 adr r0, _start 得到 r0 = 0x3000000c;如果在地址 0 运行,就是 0x0000000c 了。

进一步网上追踪ldr指令

ARM是RISC结构,数据从内存到CPU之间的移动只能通过L/S指令来完成,也就是ldr/str指令。
比如想把数据从内存中某处读取到寄存器中,只能使用ldr
比如:
ldr r0, 0x12345678
就是把0x12345678这个地址中的值存放到r0中。
而mov不能干这个活,mov只能在寄存器之间移动数据,或者把立即数移动到寄存器中,这个和x86这种CISC架构的芯片区别最大的地方。
x86中没有ldr这种指令,因为x86的mov指令可以将数据从内存中移动到寄存器中。

另外还有一个就是ldr伪指令,虽然ldr伪指令和ARM的ldr指令很像,但是作用不太一样。ldr伪指令可以在立即数前加上=,以表示把一个地址写到某寄存器中,比如:
ldr r0, =0x12345678
这样,就把0x12345678这个地址写到r0中了。所以,ldr伪指令和mov是比较相似的。只不过mov指令限制了立即数的长度为8位,也就是不能超过512。而ldr伪指令没有这个限制。如果使用ldr伪指令时,后面跟的立即数没有超过8位,那么在实际汇编的时候该ldr伪指令是被转换为mov指令的。
、、、、、、
2022/11/18

总的来说,ldr和adr伪指令是取标签(label)的地址,ldr指令是取标签地址下的内容。精简指令集(RISC)有ldr指令,没有adr指令。ldr和adr伪指令总会被解释为精简指令集中的指令。


下一步进军
目标文件  共享库文件  可执行文件
符号表 、重定位表 、偏移表(GOT表)。

静态重定位,

在静态链接时,链接器会提取每个目标文件的符号表作成全局符号表,此时各符号的地址信息就记录在全局符号表中,接着链接器会再次扫描所有的目标文件的符号表,根据目标文件的重定位表进行相关符号的重定位。

动态重定位分析。


共享库文件和可执行文件都是基于目标文件生成的,编译时每个源文件(.c)都会生成目标文件(.o),每个目标文件都会有符号表,里面的符号是文件自定义的或者引用的符号(符号包括函数和变量),

你可能感兴趣的:(开发语言,c语言)