基础概念:
1.链接地址:链接地址起始位置由程序员自己设定,程序链接之后就会确定。
2.运行地址:程序烧入芯片的地址,是程序在内存中运行的实际地址。
代码分析:
从下面这段ARM汇编代码分析:
.global _start
_start:
adr r0,_start
ldr r1,=_startstop:
b stop
实际生成的机器码(代码起始地址设为0x00000100):
4: adr r0,_start
0x00000100 E24F0008 SUB R0,PC,#0x00000008
5: ldr r1,=_start
6:
7: stop:
0x00000104 E59F1000 LDR R1,[PC]
8: b stop
0x00000108 EAFFFFFE B 0x00000108
0x0000010C 00000100 ANDEQ R0,R0,R0,LSL #2
0x00000110 00000000 ANDEQ R0,R0,R0
adr r0,_start和ldr r1,=_start两条指令都为伪指令,且作用都是获得_start标签的地址。
1.adr r0,_start ,对应生成机器码
0x00000100 E24F0008 SUB R0,PC,#0x00000008
可知,adr是求出pc与_start标签间的相对偏移距离,然后使用sub(或add)指令来获得_start标签地址。
2.ldr r1,=_start,对应生成机器码
0x00000104 E59F1000 LDR R1,[PC]
0x0000010C 00000100 ANDEQ R0,R0,R0,LSL #2
可知,ldr是将_start标签地址,存入代码段最后地址,再求得相对偏移量,使用ldr指令从地址中读出_start地址。此时_start存储在机器码上,在程序链接后就已经确定了。当我们把程序烧入芯片后,假设芯片运行起始地址为0x00000000,此时运行到ldr r1,=_start代码时,程序获取到的是0x00000100地址,而此时_start标签实际地址为0x00000000,程序运行无疑会跑飞。