adr与ldr的区别
adr与ldr r0, =label的区别:
adr 和 ldr r0, =label(这里不包括ldr的一般用法)都是pseudo-instruction。
adr r0, label与ldr r0, =label实际上实现的功能都是一样儿的,都是将label的地址存放到r0中,但是由于adr中用的是相对地址且使用一个汇编指令完成,故其寻址范围限制在4k的范围内。但是ldr则不同,由于其使用了literal pools,寻址范围可以在4G的任意范围(但是切记literal pools的位置仍然要在4k之内)。如果说两者之间有什么不同的话,那就是:使用ldr要比使用adr浪费一些存储空间(如果label距离PC不是很远的情况下,使用adr是合理的)。
使用arm的启动代码2440init.s来举例如下:
代码未作任何修改的代码如下:
copy_proc_beg
adr r0, ResetEntry
ldr r2, BaseOfROM
cmp r0, r2
ldreq r0, TopOfROM
beq InitRam
ldr r3, TopOfROM
其反汇编结果如下:
copy_proc_beg
0x00000268: e24f0f9c ..O. SUB r0,pc,#0x270 ; #0
0x0000026c: e59f2140 @!.. LDR r2,0x3b4
0x00000270: e1500002 ..P. CMP r0,r2
0x00000274: 059f013c <... LDREQ r0,0x3b8
0x00000278: 0afffffe .... BEQ InitRam ; 0x298
0x0000027c: e59f3134 41.. LDR r3,0x3b8
可见此时r0的值正好是(pc+8-270)=0x0(至于这里为什么加8请看后面),即ResetEntry的位置。
将adr r0, ResetEntry改写成ldr r0, =ResetEntry后代码如下:
copy_proc_beg
ldr r0, =ResetEntry
ldr r2, BaseOfROM
cmp r0, r2
ldreq r0, TopOfROM
beq InitRam
ldr r3, TopOfROM
反汇编结果如下:
copy_proc_beg
0x00000268: e59f00f0 .... LDR r0,0x360
0x0000026c: e59f2144 D!.. LDR r2,0x3b8
0x00000270: e1500002 ..P. CMP r0,r2
0x00000274: 059f0140 @... LDREQ r0,0x3bc
0x00000278: 0afffffe .... BEQ InitRam ; 0x298
0x0000027c: e59f3138 81.. LDR r3,0x3bc
可见这里是将0x360处的值赋给了r0,而0x360处在literal pools中,如下:
$d(表示literal pools位置)
0x00000328: 4a000008 ...J DCD 1241513992
0x0000032c: 4a00001c ...J DCD 1241514012
0x00000330: 00007fff .... DCD 32767
0x00000334: 4c000014 ...L DCD 1275068436
0x00000338: 4c000008 ...L DCD 1275068424
0x0000033c: 00038022 "... DCD 229410
0x00000340: 4c000004 ...L DCD 1275068420
0x00000344: 0005c011 .... DCD 376849
0x00000348: 560000b4 ...V DCD 1442840756
0x0000034c: 56000050 P..V DCD 1442840656
0x00000350: 56000058 X..V DCD 1442840664
0x00000354: 56000054 T..V DCD 1442840660
0x00000358: 000055aa .U.. DCD 21930
0x0000035c: 00000268 h... DCD 616
0x00000360: 00000000 .... DCD 0
0x00000364: 000002c8 .... DCD 712
0x00000368: 00000000 .... DCD 0
0x0000036c: 000000d8 .... DCD 216
0x00000370: 33ff5c00 .\.3 DCD 872373248
0x00000374: 33ff6000 .`.3 DCD 872374272
0x00000378: 33ff7000 .p.3 DCD 872378368
0x0000037c: 33ff8000 ...3 DCD 872382464
0x00000380: 33ff5800 .X.3 DCD 872372224
此处的值正好位0x0,即ResetEntry的位置。
在程序的423行,可以看到有一个LTORG伪指令,正是由于这个原因,编译器才会在0x00000328位置开始建立literal pools。有关literal pools可以参考http://blog.csdn.net/caimingda1987/article/details/6662893。
前面提到pc指针默认加8的原因如下(转载):
2440是三级流水线结构,下面来讲讲为什么三级流水线,故名思义,就是一个时刻做三件事情,对于2440来说,那就是取指,译码,执行
取指 译码 执行。。。
取指 译码 执行。。。
取指 译码 执行。。。
那么问一个问题,PC究竟是指向取指呢,译码呢,还是执行,由此便带来一个问题,当前指令执行的时候,PC的值已经不是当前指令所在的地址了,而是
当前地址+8
0x00000000
0x00000004 ---假设为当前执行的指令地址
0x00000008
PC-> 0x0000000c PC指向的是这儿
adr 和 ldr r0, =label(这里不包括ldr的一般用法)都是pseudo-instruction。
adr r0, label与ldr r0, =label实际上实现的功能都是一样儿的,都是将label的地址存放到r0中,但是由于adr中用的是相对地址且使用一个汇编指令完成,故其寻址范围限制在4k的范围内。但是ldr则不同,由于其使用了literal pools,寻址范围可以在4G的任意范围(但是切记literal pools的位置仍然要在4k之内)。如果说两者之间有什么不同的话,那就是:使用ldr要比使用adr浪费一些存储空间(如果label距离PC不是很远的情况下,使用adr是合理的)。
使用arm的启动代码2440init.s来举例如下:
代码未作任何修改的代码如下:
copy_proc_beg
adr r0, ResetEntry
ldr r2, BaseOfROM
cmp r0, r2
ldreq r0, TopOfROM
beq InitRam
ldr r3, TopOfROM
其反汇编结果如下:
copy_proc_beg
0x00000268: e24f0f9c ..O. SUB r0,pc,#0x270 ; #0
0x0000026c: e59f2140 @!.. LDR r2,0x3b4
0x00000270: e1500002 ..P. CMP r0,r2
0x00000274: 059f013c <... LDREQ r0,0x3b8
0x00000278: 0afffffe .... BEQ InitRam ; 0x298
0x0000027c: e59f3134 41.. LDR r3,0x3b8
可见此时r0的值正好是(pc+8-270)=0x0(至于这里为什么加8请看后面),即ResetEntry的位置。
将adr r0, ResetEntry改写成ldr r0, =ResetEntry后代码如下:
copy_proc_beg
ldr r0, =ResetEntry
ldr r2, BaseOfROM
cmp r0, r2
ldreq r0, TopOfROM
beq InitRam
ldr r3, TopOfROM
反汇编结果如下:
copy_proc_beg
0x00000268: e59f00f0 .... LDR r0,0x360
0x0000026c: e59f2144 D!.. LDR r2,0x3b8
0x00000270: e1500002 ..P. CMP r0,r2
0x00000274: 059f0140 @... LDREQ r0,0x3bc
0x00000278: 0afffffe .... BEQ InitRam ; 0x298
0x0000027c: e59f3138 81.. LDR r3,0x3bc
可见这里是将0x360处的值赋给了r0,而0x360处在literal pools中,如下:
$d(表示literal pools位置)
0x00000328: 4a000008 ...J DCD 1241513992
0x0000032c: 4a00001c ...J DCD 1241514012
0x00000330: 00007fff .... DCD 32767
0x00000334: 4c000014 ...L DCD 1275068436
0x00000338: 4c000008 ...L DCD 1275068424
0x0000033c: 00038022 "... DCD 229410
0x00000340: 4c000004 ...L DCD 1275068420
0x00000344: 0005c011 .... DCD 376849
0x00000348: 560000b4 ...V DCD 1442840756
0x0000034c: 56000050 P..V DCD 1442840656
0x00000350: 56000058 X..V DCD 1442840664
0x00000354: 56000054 T..V DCD 1442840660
0x00000358: 000055aa .U.. DCD 21930
0x0000035c: 00000268 h... DCD 616
0x00000360: 00000000 .... DCD 0
0x00000364: 000002c8 .... DCD 712
0x00000368: 00000000 .... DCD 0
0x0000036c: 000000d8 .... DCD 216
0x00000370: 33ff5c00 .\.3 DCD 872373248
0x00000374: 33ff6000 .`.3 DCD 872374272
0x00000378: 33ff7000 .p.3 DCD 872378368
0x0000037c: 33ff8000 ...3 DCD 872382464
0x00000380: 33ff5800 .X.3 DCD 872372224
此处的值正好位0x0,即ResetEntry的位置。
在程序的423行,可以看到有一个LTORG伪指令,正是由于这个原因,编译器才会在0x00000328位置开始建立literal pools。有关literal pools可以参考http://blog.csdn.net/caimingda1987/article/details/6662893。
前面提到pc指针默认加8的原因如下(转载):
2440是三级流水线结构,下面来讲讲为什么三级流水线,故名思义,就是一个时刻做三件事情,对于2440来说,那就是取指,译码,执行
取指 译码 执行。。。
取指 译码 执行。。。
取指 译码 执行。。。
那么问一个问题,PC究竟是指向取指呢,译码呢,还是执行,由此便带来一个问题,当前指令执行的时候,PC的值已经不是当前指令所在的地址了,而是
当前地址+8
0x00000000
0x00000004 ---假设为当前执行的指令地址
0x00000008
PC-> 0x0000000c PC指向的是这儿
Comments
Post a Comment