`
javababy1
  • 浏览: 1169387 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

常用的ARM汇编指令

 
阅读更多

在嵌入式开发中,汇编程序往往应用在非常关键的地方,比如系统启动时的初始化,进出中断时的环境保存、恢复,对性能要求非常苛刻的函数等。

1.相对跳转指令:b、bl

这两条指令的不同之处在于bl指令除了跳转之外,还将返回地址(bl的下一条指令的地址)保存在lr寄存器中。

这两条指令的可跳转范围是当前指令的前后32MB。它们是与位置无关的指令。

示例:

b fun1

...

fun1:

-------------------------------

bl fun2

...

fun2:

...

mov pc, lr @返回

2.数据传送指令mov,地址读取指令ldr

mov指令可以把一个寄存器的值赋值给另一个寄存器,或者是把一个常数赋值给另一个寄存器。例子如下:

mov r1, r2 /*r1=r2*/

mov r1, #4096

mov指令传送的常数必须能用“立即数”来表示。

当不知道一个数能否用“立即数”来表示时,可以使用ldr命令来赋值。ldr是伪指令,它不是真实存在的指令,编译器会把它扩展成为真正的指令:如果该常数能用“立即数”来表示,则使用mov指令;否则编译时将该常数保存在某个位置,使用内存读取指令把它读出来。

示例:

ldr r1,=4097 /*r1=4097*/

ldr本意为“大范围的地址读取伪指令”,下面的例子是使用它来将常数赋给寄存器r1。下例是获得代码的绝对地址:

ldr r1, =label

label:

...

3.内存访问指令:ldr、str、ldm、stm

注意:ldr指令既可能是前面所述的大范围的地址读取伪指令,也可能是内存访问指令。当它的第二个参数前面有“=”时,表示伪指令,否则表示内存访问指令。

ldr指令是从内存读存指令到寄存器中,str指令是把寄存器中的值存储到内存中。它们操作的数都是32位的数。

示例:

ldrr1,[r2,#4]/*将地址为r2+4的内存单元数据读取到r1中*/

ldrr1,[r2]/*将地址为r2的内存单元数据读取到r1中*/

ldrr1,[r2],#4/*将地址为r2的内存单元数据读取到r1中,然后,r2=r2+4*/

strr1,[r2,#4]/*将r1的数据保存到地址为r2+4的内存单元中*/

strr1,[r2]/*将r1的数据保存到地址为r2的内存单元中*/

strr1,[r2],#4/*将r1的数据保存到地址为r2的内存单元中,然后,r2=r2+4*/

ldm和stm属于批量内存访问指令,只用一条指令就可以读写多个数据。它们的格式如下:

ldm{cond}<addressing_mode><rn>{!}<register list>{^}

stm{cond}<addressing_mode><rn>{!}<register list>{^}

其中,

{cond}表示指令的执行条件,参见下面的指令条件码。

<addressing_mode>表示地址变化模式,有以下4种方式:

1)ia(increment after):事后递增方式;

2)ib(increment before):事先递增方式;

3)da(decrement after):事后递减方式;

4)db(decrement before):事先递减方式。

<rn>中保存内存的地址,如果后面加上了感叹号,指令执行后,rm的值会更新,等于下一个内存单元的地址。

<register list>表示寄存器列表,对于ldm指令,从<rn>所对应的内存块中取出数据,写入这些寄存器;对于stm指令,把这些寄存器的值写入<rn>所对应的内存块中。

{^}有两种含义:如果<register list>中有PC寄存器,它表示指令执行后,spsr寄存器的值将自动复制到cpsr寄存器中——这常用于从中断处理函数中返回;如果<register list>中没有PC寄存器,{^}表示操作的是用户模式下的寄存器,而不是当前特权模式的寄存器。

指令中寄存器列表和内存单元的对应关系为:编号低的寄存器对应于内存中的低地址单元,编号高的寄存器对应于内存中高地址的单元。

示例如下:

HandleIRQ:@中断入口函数

sublr,lr,#4@计算返回地址

stmdbsp!,{r0-r12,lr}@保存使用到的寄存器

@r0~r12,lr被保存在sp表示的内存中

@"!"使得指令执行后sp=sp-14*4

ldrlr,=int_return@设置调用IRQ_Handle函数后的返回地址

ldrpc,=IRQ_Handle@调用中断分发函数

int_return:

ldmiasp!,{r0-r12,pc}^@中断返回,"^"表示将spsr的值复制到cpsr

@于是从irq模式返回被中断的工作模式

@"!"使得指令执行后sp=sp+14*4

4.加减指令:add、sub

示例:

add r1, r2, #1/*表示r1=r2+1,即寄存器r1的值等于寄存器r2的值加上1*/

sub r1, r2, #1/*表示r1=r2-1*/

5.程序状态寄存器的访问指令:msr、mrs

ARM处理器有一个程序状态寄存器(cpsr),它用来控制处理器的工作模式、设置中断的总开关。

示例:

msr cpsr, r0/*复制r0到cpsr中*/

mrs r0, cpsr/*复制cpsr到r0中*/

6.其它伪指令

.extern main

.text

.global _start

_start:

含义:

".extern"定义一个外部符号(可以是变量也可以是函数),上面的代码表示本文件中引用的main是一个外部函数。

".text"表示下面的语句都属于代码段。

".global"将本文件中的某个程序标号定义为全局的,比如上面的代码表示_start是个全局函数。

7.汇编语言的执行条件

大多数的ARM指令都可以条件执行,即根据cpsr寄存器中的条件标志决定是否执行该指令:如果条件不满足,该指令相当于一条nop指令。

每条ARM指令包含4位的条件码域,这表明可以定义16个执行条件。可以将这些执行条件的助记符附加在指令后面,比如moveq、movgt等。这16个条件码和它们的助记符含义如下表所示:

源文档 <http://weimenlove.blog.163.com/blog/static/177754732011115115350287/>

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics