ARM汇编

621 阅读6分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第22天,点击查看活动详情

若看到相同文章,为本人其他平台

ARM汇编指令

0.“.”开头的指令

.global
@ .global关键字用来让一个符号对链接器可见,可以供其他链接对象模块使用。
@ .global _start 让_start符号成为可见的标示符,这样链接器就知道跳转到程序中的什么地方并开始执行。linux寻找这个 _start标签作为程序的默认进入点。


.extern XXXX 
@ XXXX,调用的时候可以遍访所有文件找到该函数并且使用它


.macro
.endm
@ 类似宏定义,将一组命令放在这两个命令中间组成一个命令集合。
.macro STACK_MAGIC_SET param0, param1, param2
    ldr     r0, =\param0
    mov     r1, \param1
    ldr     r2, =\param2
    bl      excstack_magic
.endm


.code 32
@ 表示后面的指令全部用arm指令集

.code 16
@ 表示下面的汇编代码都使用thumb指令集


.section .text        
#定义文本段(代码段)

.section .data        
#定义数据段

.section .bss          
#定义 bss 段

.section ".vectors", "ax"       
#指定以下代码段必须存放在.vectors段里, “ax”表示该段可执行并且可分配

1.相对跳转指令:

1.1无条件转移指令

B:跳转指令

BL:bl除了跳转之外,还将返回地址(bl的下一条指令的地址)保存在lr寄存器中。他们是位置无关的指令(范围为当前指令的前后32mb)

    b fun1
......
fun1:
    bl fun2
......
fun2:
......

BLX :带返回和状态切换的跳转指令

有两种方式实现跳转:1.使用分支指令直接跳转。 2.向PC寄存器赋值实现跳转。

1.2条件转移指令

BEQ 相等 BNE 不等 BPL 非负 BMI 负 BCC 无进位 BCS 有进位 BLO 小于(无符号数) BHS 大于等于(无符号数) BHI 大于(无符号数) BLS 小于等于(无符号数) BVC 无溢出(有符号数) BVS 有溢出(有符号数) BGT 大于(有符号数) BGE 大于等于(有符号数)

BLT 小于(有符号数) BLE 小于等于(有符号数)

先进行判断【程序状态寄存器CPSR】中的标志位,然后决定是否跳转。

2.数据处理:传送指令mov,地址读取伪指令ldr

mov :

​ 指令是把一个寄存器的值赋给另一个寄存器,或者把一个常数赋给寄存器。

mov r1, r2
mov r1, #4096

如果传送的数不能确定是否可以使用“立即数”来表示的话,可以使用Ldr命令来赋值。

ldr是伪指令,如果该常数能用立即数表示,则直接使用mov指令,否则编译时将常数放入某个位置,使用内存读取伪指令把它读出来。

ldr r1, =4097       /*r1=4097,将常数赋值给r1*/
ldr r1, =label        /*获取代码的绝对地址*/
label:
......

ldr: 本意为“大范围的地址读取伪指令”

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

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

ldr:从内存中读取数据到寄存器。操作的数据为32位。

str:把寄存器的值存储到内存中。操作的数据为32位。

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

格式:

ldm {cons}<addressing_mode> <rn>{!} <register list>{^}
stm {cons}<addressing_mode> <rn>{!} <register list>{^}

{cond} :表示指令的执行条件。 条件如下表3.2所示.

{addressing_mode}表示地址变化模式,有下列4中方式:

​ ia: 事后递增方式。

​ ib:事先递增方式。

​ da:事后递减方式。

​ db:事先递减方式。

{rn}中保存内存的地址,如果后面加上感叹号,指令执行后,rn的值会变成下一个内存单元的地址。

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

{^}:

​ 1.中有pc寄存器,它表示指令执行后,spsr寄存器的值将自动复制到cpsr寄存器中--常用来从中断函数中返回。

​ 2.中没有pc寄存器,它表示操作的是用户模式下的寄存器,而不是当前特权模式的寄存器。

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

HandleIRQ:                    @中断入口函数
    sub lr, lr, #4            @计算返回地址
    stmdb sp!,    {r0-r12,lr} @保存使用到的寄存器
                            @r0-r12,lr被保存在sp表示的内存中
                            @“!”使得指令执行后sp=sp-14*4

    ldr lr, =int_return        @设置调用IRQ_Handle函数后的返回地址
    ldr pc, =IRQ_Handle        @调用中断分发函数
int_return:
    ldmia    sp!,    {r0-r12,pc }^    @中断返回,^表示将spsr的值复制到cpsr
                                    @于是从irq模式返回被中断的工作模式
                                    @!使得指令执行后sp=sp+14*4

4.乘法指令(arm7tdmi-s加入的指令)

5.加减指令:add,sub

add r1, r2, #1        @表示r1=r2+1
sub r1, r2, #1        @表示r1=r2-1

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

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

msr cpsr, r0        @复制r0到cpsr中
mrs r0, cpsr        @复制cpsr到r0中

7.杂项指令:swi,mrs,msr

8.其他伪指令

.extern main    @定义一个外部符号(可以是变量和函数) 这个main代表一个函数
.text            @表示下面的语句都属于代码段
.global _start    @将本文中的某个程序标号定义为全局的,这个_start表示一个全局函数
_start:

adr                @小范围地址读取伪指令
adrl            @中等范围的地址读取伪指令
ldr                @大范围地址读取伪指令

nop                @空操作伪指令

SPACE和DCD的区别在于:
SPACE和DCD的功能类似,SPACE申请一片内存空间,DCD申请一个字(32bit)的内存空间
SPACE和DCD的区别在于,SPACE申请空间但不赋初值,DCD申请一个字的空间,并赋初值
MCR
@ 指令将ARM处理器的寄存器中的数据传送到协处理器的寄存器中。如果协处理器不能成功地执行该操作,将产生未定义的指令异常中断。
MCR{<cond>} p15, 0, <Rd>, <CRn>, <CRm>{,<opcode_2>}

MCR2 p15, 0, <Rd>, <CRn>, <CRm>{,<opcode_2>}

mrc 
@ 从协处理器移动到寄存器

and 
@ 按位与操作


bne
@ 数据跳转指令,标志寄存器中Z标志位不等于零时, 跳转到BNE后标签处。


.irp <param> {,<val_1>} {,<val_2>} …
@ 循环执行.endr前的代码段,param依次取后面给出的值。
@ 在循环执行的代码段中必须以“/<param> ”表示参数。

.endr 
@结束循环(与armasm中的WEND相似).


LDRD 和 STRD 双字数据传送必须是八字节对齐的。如果要用 LDRD 或 STRD 访问
数据,则在内存分配指令(如 DCQ)之前使用 ALIGN 8(请参阅第7-17 页的数
据定义指令)。

strd: 将double word存储到指定内存地址

9.汇编指令的执行条件

条件有:看上边表3.2

arm指令包含4位的条件域码,这表明可以定义16个执行条件,可以将这些执行条件的助记符附加到汇编指令后。

例如:moveq,movgt等。