ARM汇编指令集

指令与伪指令

  1. 汇编指令是CPU机器指令的助记符,经过编译后会得到一串0、1组成的机器码,由CPU读取执行
  2. 汇编伪指令本质上不是指令(只是和指令一起写在代码中),它是编译器环境提供的,目的是用来指导编译过程,经过编译后伪指令是最终不会生成机器码

ARM汇编特征

  1. LDR/STR架构
    ARM采用RISC架构,CPU本身不能直接读取内存,而需要先将内存中内容加载入CPU中通用寄存器中才能被CPU处理。
    ldr(load register)指令将内存内容加载入通用寄存器。
    str(store register)指令将寄存器内容存入内存空间中。
    ldr/str组合用来实现 ARM CPU和内存数据交换
  2. 8种寻址方式
    •寄存器寻址 mov r1, r2 (将r2的内容运送到r1 相当于C语言的r1=r2)
    •立即寻址 mov r0, #0xFF00 (将0xFF00直接给到r0)
    •寄存器移位寻址 mov r0, r1, lsl #3 (lsl—左移指令,该句的意思相当于将r1里的值左移三位再运送到r0 (其中左移一位相当于乘2))
    •寄存器间接寻址 ldr r1, [r2] (这里的r2相当于指针,r2存的内容是内存地址,[r2]表示内存里的值;相当于r2内存地址里的值运送到r1)
    ***•基址变址寻址 ldr r1, [r2, #4]***(将r2内存的值加4的内存地址里的值运送给r1)
    ***•多寄存器寻址 ldmia r1!, {r2-r7, r12}***(ldmia 中的 I 是 increase 的缩写,a 是 after 的缩小,ld加载(load)的意思,r1后面的感叹号“!”表示会自动调节 r1里面存的指针;整句话意思是任务栈r1的存储地址由低到高,将r1存储地址里面的内容手动加载到 CPU 寄存器 r2-r7,r12)
    ***•堆栈寻址 stmfd sp!, {r2-r7, lr}***(类似于多寄存器寻址,区别在于这里的内存地址是栈内存地址)
    •相对寻址 beq flag(flag-标号,用来标记标号后面那句指令的地址)
    flag:
  3. 指令后缀
    同一指令经常附带不同后缀,变成不同的指令。经常使用的后缀有:
    •B(byte)功能不变,操作长度变为8位
    •H(half word)功能不变,长度变为16位
    •S(signed)功能不变,操作数变为有符号
    •如 ldr ldrb ldrh ldrsb ldrsh
    •S(S标志)功能不变,影响CPSR标志位
    •如 mov和movs movs r0, #0
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bXTYLfKH-1647703878933)(C:\Users\86150\AppData\Roaming\Typora\typora-user-images\image-20220115205540480.png)]
    •条件位:
    –N = Negative result from ALU (结果为负值时被置位)
    –Z = Zero result from ALU (结果为零食被置位)
    –C = ALU operation Carried out (结果进位会被置位)
    –V = ALU operation oVerflowed (结果溢出会被置位)
  4. 条件执行后缀
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5LjiDF1i-1647703878934)(C:\Users\86150\AppData\Roaming\Typora\typora-user-images\image-20220115205914664.png)]
/*条件执行后缀例子*/
mov r0,r1        /*相对于C语言的r0=r1*/
moveq r0, r1     /*如果eq成立,则直接执行mov r0,r1;如果eq不成立则跳过本句代码,相当于没有*/
                 /*类似于C语言中的 if(eq){r0=r1}*/
    
 //值得注意的2点:
 //1.条件后缀是否成立,不取决于本句代码,而是取决于这句代码之前代码的运行结果。
 //2.条件后缀决定了本句代码是否被执行,而不会影响上一句和下一句代码是否被执行
  1. 多级指令流水线

常用数据处理指令

•数据传输指令 mov mvn(**mvn与mov的区别是:**mov是原封不动的传递,而mvn是按位取反后传递)

•算术指令 add sub rsb adc sbc rsc

•逻辑指令 and(与)orr(或) eor(异或) bic(位清零指令 例子:bic r0,r1,#0x1f 将r1的bit0-bit4清零后赋值给r0)

•比较指令:

cmp cmp r0,r1等价于 sub r2,r0,r1(r2 = r0 - r1)看相减是否为零

cmn cmn r0,r1等价于 add r0,r1 看是否互为相反数

tst:逻辑处理指令,用于把一个寄存器的内容和另一个寄存器的内容或立即数进行按位的与运算,并根据运算结果更新CPSR中条件标志位的值。当前运算结果为1,则Z=0;当前运算结果为0,则Z=1

tst r0 , #0x2         //进行and运算,如果bit_2为1,zero==0,如果bit_2为0,则zero==1,即该指令测试bit_2是否为0

teq 测试某些位相不相等s

(比较指令不用加s后缀就可以影响cpsr中的标志位)

•乘法指令 mvl mla umull umlal smull smlal

•前导零计数 clz

cpsr访问指令

•mrs & msr

•mrs用来读psr,msr用来写psr

•CPSR寄存器比较特殊,需要专门的指令访问,这就是mrs和msr。

**注意:**psr包括cpsr和spsr,它们的区别和联系:cpsr是程序状态寄存器,整个Soc只有一个;而spsr有5个,分别在5中异常模式下,作用是当从普通模式进去异常模式,用来保存之前普通模式下的cpsr,以在返回普通模式时恢复原来的cpsr

跳转(分支)指令

•b & bl & bx

•b 直接跳转(就没打开算返回)

•bl branch and link,跳转前把返回地址放入lr中,以便返回,以便用于函数调用

•bx跳转同时切换到ARM模式,一般用于异常处理的跳转。(现在基本用不上)

协处理器汇编指令

mcr & mrc

•mrc用于读取CP15中的寄存器

•mcr用于写入CP15中的寄存器

伪指令

•.global _start @ 给_start外部链接属性

•.section .text @ 指定当前段为代码段

•.ascii (定义字符).byte(一个字节) .short(两个字节) .long(四个字节) .word(四个字节).quad(八个字节) .float(浮点型) .string(字符串) @用来定义变量 ,定义数据

IRQ_STACK_START:
	.word	0x0badc0de
        
/*等价于 unsigned int IRQ_STACK_START = 0x0badc0de;*/

•.align 4 @ 以16(2的4次方)字节对齐

.balignl 16, 0xdeadbeef		@ 对齐 + 填充
/*b表示位填充;align表示要对齐;l表示long,以4字节为单位填充;16表示16字节对齐;0xdeadbeef是用来填充的原料。*/

•.end @标识文件结束

•.include @ 头文件包含

•.arm / .code32 @声明以下为arm指令

•.thumb / .code16 @声明以下为thubm指令

•ldr 大范围的地址加载指令

•adr 小范围的地址加载指令

  1. adr编译时会被1条sub或add指令替代,而ldr编译时会被一条mov指令替代或者文字池方式处理;
  2. adr总是以PC为基准来表示地址,因此指令本身和运行地址有关,可以用来检测程序当前的运行地址在哪里
  3. ldr加载的地址和链接时给定的地址有关,由链接脚本决定

•adrl 中等范围的地址加载指令

•nop 空操作