2012年(6)
分类: 嵌入式
2012-11-27 11:40:22
要访问内存最简单的办法是用一个立即数表示数据地址,然后用立即数发起访问,但由于ARM CPU的架构方式,ARM CPU没有提供这样的指令。arm cpu采用寄存器间接寻址方式,将数据的地址放在寄存器中,然后用寄存器中的值发起访问:
ldr Rd,[Rn]
它的扩展形式是:
ldr Rd,[Rn,op2]
ldr R1,[R2,#4]
ldr R1,[R2,R3,lsl #2]
另外一种方式是使用PC相对地址,假设你有某一个变量中memory中,你不能使用该变量地址时,你可以将该变量地址存储在代码执行附近,然后采用PC加上offset来取得地址,在通过该地址来取得数据。实现该方式有两种方法:
1 创建一个缓冲池,将数据放入缓冲池中,并对该缓冲池做好标记,然后用ldr指令取得,
2 使用伪指令,让编译器自动帮你完成,指令格式为:ldr Rd,=foo(foo是一个地址标号,或者是一个立即数),列子说明:
.text
.global _start
_start:
ldr r0,lablename
ldr r0,lablename+4
ldr r0,=lablename
ldr r0,=0x10
adr r0,lablename
lablename:
.long 0x00000000
.long 0x00000004
编译后如下:
Disassembly of section .text:
00000000 <_start>:
0:
e59f000c ldr r0, [pc, #12] ; 14
4:
e59f000c ldr r0, [pc, #12] ; 18
8:
e59f000c ldr r0, [pc, #12] ; 1c
c: e3a00010 mov r0, #16 ; 0x10
10: e24f0004 sub r0, pc, #4 ; 0x4
00000014
14: 00000000 .word 0x00000000
18: 00000004 .word 0x00000004
1c: 00000014 .word 0x00000014
解释代码:由于ARM CPU采用流水线方式取址,所以当CPU执行第一条指令时,PC已经指向第三条指令也就是地址为8的地方,然后PC+12就得到了ox14,第一二条指令的数据访问方式有点像数组,lablename是数组名,加上offset就可以访问该数组后面的数据;第三四两条指令是伪指令,编译器会用合适的指令完成该伪指令表示的功能,第三条指令:编译器将lablename代表的缓冲池的地址存入PC附件的地方(0x1c),该条指令执行之后r0就获得了lablename缓冲池的地址(PS:R0获得的不是缓冲区里面的数据,而是缓冲区的地址)。第四条指令将“=”后面的数字以合适的方式赋值给R0,第五条指令adr是一条伪指令,它是去取得lablename代表的数据缓冲池开始的地址,此时编译器生成一条相对pc寻址指令,这四条指令执行完毕后R0的值分别为:
0
4
0x10
0x1c
0x14
现在重点说明第三条指:ldr r0,=lablename
编译器在链接时会给标号、全局变量、函数等赋值,如果代码里有指令去获得某个标号的值,那该值就与链接地址相关了,上面的代码链接地址是0,让我们看看链接地址是0x30000000的反汇编:
Disassembly of section .text:
30000000 <_start>:
30000000: e59f000c ldr
r0, [pc, #12] ; 30000014
30000004: e59f000c ldr
r0, [pc, #12] ; 30000018
30000008: e59f000c ldr
r0, [pc, #12] ; 3000001c
3000000c: e3a00010 mov r0, #16 ; 0x10
30000010: e24f0004 sub r0, pc, #4 ; 0x4
30000014
30000014: 00000000 .word 0x00000000
30000018: 00000004 .word 0x00000004
3000001c: 30000014 .word 0x30000014
最前面一排数字(such as:0x30000000)是运行地址,也说就是说程序运行时,该程序应该放在什么地方,它是反汇编工具为了您阅读方便而给出的提示信息,程序也不一定要放在该地址才可以运行,除了第二排是CPU执行时真正执行的指令外,其余都是反编译工具给出的提示信息。
着重看第三条反汇编指令,该指令与链接地址为0x0时一样(e59f000c),但执行结果R0为0x30000014,lablename的值在链接时确定,之后编译器将该值保存在缓冲池中。
最后这四条指令的意思是:
ldr r0,lablename 取出lablename处的值,类似数组
ldr r0,lablename+4 取出lablename+4处的值,类似数组
ldr r0,=lablename 取出lablename在什么地方,编译器在编译的时候会根据链接地址给lablename赋值,其实现机制是编译器将lablename的值存入pc附近的缓冲池中,然后通过pc相对寻址去缓冲池中取得该值。
ldr r0,=0x10 以合适的方式将立即数0x01赋值给R0
adr r0,lablename 取得lablename代表的数据开始的地址