Chinaunix首页 | 论坛 | 博客
  • 博客访问: 384891
  • 博文数量: 102
  • 博客积分: 1395
  • 博客等级: 中尉
  • 技术积分: 1050
  • 用 户 组: 普通用户
  • 注册时间: 2012-11-05 18:09
文章分类

全部博文(102)

文章存档

2013年(25)

2012年(77)

分类:

2012-12-02 09:44:43

原文地址:ARM的地址模式 作者:GrizzlyPass

要访问内存最简单的办法是用一个立即数表示数据地址,然后用立即数发起访问,但由于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,=foofoo是一个地址标号,或者是一个立即数),列子说明:

 

.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 as0x30000000)是运行地址,也说就是说程序运行时,该程序应该放在什么地方,它是反汇编工具为了您阅读方便而给出的提示信息,程序也不一定要放在该地址才可以运行,除了第二排是CPU执行时真正执行的指令外,其余都是反编译工具给出的提示信息。

着重看第三条反汇编指令,该指令与链接地址为0x0时一样(e59f000c),但执行结果R00x30000014lablename的值在链接时确定,之后编译器将该值保存在缓冲池中。

 

最后这四条指令的意思是:

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代表的数据开始的地址

阅读(894) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~