指令:cpu机器指令的助记符。如 mov 指令,会通过汇编器,解码成机器码(如:00011111),电脑只能识别机器码去执行。而指令就是方便我们记忆的这串机器码的的具体含义。
伪指令:本质上不是指令,而是编译环境提供的,是用来指导编译过程。
arm有8种寻址方式:
寄存器寻址: mov r2,r3 //相当于c中的 r2 = r3,把寄存器 r3 的值赋值给 r2
立即寻址: mov r2,#0 //把立即数 0 赋值给 r2
寄存器移位寻址: mov r2,r3,lsl #2 // r3 左移2位,再把值赋值给 r2
寄存器间接寻址: ldr r2,[r3] // 把r3的内存地址中的值,赋值给 r2,相当于c语言中的指针的赋值
基址变址:ldr r2, [ r3, #4] // r3中的内存地址 +4后的地址中的值,赋值给 r2
多寄存器寻址:ldmia r2!, {r3-r5, r8} //寄存器往内存加载,即把r3,r4,r5,r8,4个基础加载到 r2 存放的地内存址当中去
堆栈寻址:stmfd sp!, {r3-r4, lr} //和多寄存器寻址类似,只不过这个寄存器只能用 sp 寄存器。
相对寻址: beq flag //如果条件成立就跳转到 flag去,flag是一个标号,就像 goto一样。
arm 常见指令:
- mov r2,r3 两个寄存器之间的传递,也可以立即数穿给r2。传给r2的值是原封不动的。
- mvn r2,r3 两个寄存器之间的传递,也可以立即数穿给r2。传给r2的值是被取反的。
- 加:add r0,r1,r2 // r0 = r1 + r2
- 减:sub r0,r1,r2 //r0 = r1 - r2
- 带进位的加法指令:adc{条件}{S} 目的寄存器,操作数1,操作数2 。用于把两个操作数相加,再加上CPSR中的C条件标志位的值,并将结果存放到目的寄存器中。
- 带借位减法指令:sbc{条件}{S} 目的寄存器,操作数1,操作数2,把操作数1减去操作数2,再减去CPSR中的C条件标志位的反码,并将结果存放到目的寄存器中。
- 与:and r0,r0,#3 ; 该指令保持r0的0、1位,其余位清零。操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个立即数。该指令常用于屏蔽操作数1的某些位。
- 或:orr r0,r0,#3 ; 该指令设置r0的0、1位,其余位保持不变。操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个立即数。该指令常用于设置操作数1的某些位。
- 逻辑异或:eor r0,r0,#3 ; 该指令反转R0的0、1位,其余位保持不变。操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个立即数。该指令常用于反转操作数1的某些位。
- 位清零指令:bic r0,r0,#%1011 ; 该指令清除 R0 中的位 0、1、和 3,其余的位保持不变。作用是为 1 的位 变成 0。
- 直接比较指令:cmp r1,r0 ;将寄存器r1的值与寄存器r0的值相减,并根据结果设置CPSR的标志位。标志位表示的是操作数1与操作数2的关系(大、小、相等)。
- 负数比较指令:cmn r1,r0 ;将寄存器r1的值与寄存器r0的值相加,并根据结果设置CPSR的标志位。
- 测试指令tst r1,#0xf ; 判断 r1 的bit0 - bit3 夫是否全为0。用于测试在寄存器R1中是否设置了最低位(%表示二进制数) 。TST指令用于把一个寄存器的内容和另一个寄存器的内容或立即数进行按位的与运算,并根据运算结果更新CPSR中条件标志位的值。
- 位测试指令:teq r1,r2 ;将寄存器R1的值与寄存器R2的值按位异或,并根据结果设置CPSR的标志位。TEQ指令用于把一个寄存器的内容和另一个寄存器的内容或立即数进行按位的异或运算,并根据运算结果更新CPSR中条件标志位的值。该指令通常用于比较操作数1和操作数2是否相等。
- 乘法指令:
- 程序状态寄存器访问指令:MRS R0,CPSR ;传送CPSR的内容到R0
- MSR CPSR,R0 ;传送R0的内容到CPSR
- 无条件跳转指令:b Label ;程序无条件跳转到标号Label处执行
- bl Label ;当程序无条件跳转到标号Label处执行时,同时将当前的PC值保存到R14中
- 访问内存指令:ldr r0,[r1] ;将存储器地址为R1的字数据读入寄存器R0。(arm采用的RISC架构,cpu不能直接读取内存,而是要加载到cpu的通用寄存器中处理,再返回给内存。即要改变内存中的值,首先得将内存中的值读到 cpu 的寄存器中,通过寄存器去改变值,再将寄存器中的值存入到内存当中去。)
- str r0,[r1],#8 ;将R0中的字数据写入以R1为地址的存储器中,并将新地址R1+8写入R1。
- swp r0,r1,[r2]; 将r2的内存地址的值读到到寄存器r0中,再将r1的值写到r2的内存地址中,完成数据的交换。
伪指令:
- .global _stat :.global 是给start外部链接属性
- .section .text : 指定当前段位代码段
- .ascii .byte .short .long .word 定义变量的
- .quad .float .string 定义数据
- .align 4 以16字节对齐
- .balignl 16 0xabcdefgh 16字节对齐,4字节填充
- .equ 类似于c语言的宏定义,也可以直接使用#define来定义。汇编和C语言是相通的。
- .end 文件的结束
- .include 用来包含头文件的
- .arm / .code32 声明是arm指令
- .thumb .code16 声明是thumb指令
- ldr:立即数不合法也行,一般超过8位不为0的立即数算是不合法。而指令ldr用不合法的立即数是会报错的。所以arm就发明ldr的伪指令,用不合法的立即数也行。一般我们都是使用伪指令的ldr。
指令加后缀:如:ldr
- ldrb,加b,功能不变,但是操作的长度变为8位
- ldrh,加h,功能不变,但是操作的长度变为16位
- ldrs,加s,功能不变,但是变成是有符号的
- 还有一个是加s的,是改变cpsr的标志位,跟上面的不同,如movs,加了s后会改变其cpsr的标志位。
条件增加后缀:如 moveq r2,r3。看上一句的执行结果的标志位z是否等于1,如果等于执行这一句指令,如果不是等于则跳过这句指令,去执行这一句的下一句代码。这些条件后缀,如下图: