常见的汇编指令:
1. 跳转指令:
在程序执行过程中,跳转到其他代码运行,类似于c中 的函数调用和goto语句.
- B: 跳转后不可返回
- BL: 跳转后可以返回
2. 传输数据指令
- MOV
- MVN
3. 加载/存储
- LDR (load register)
注意:这里默认的是
LDR R0, #0x12DF ;将内存中0x12DF中的数据保存到寄存器R0
LDR R0, =0x12DF ; 伪指令,将数字0x12DF直接保存到寄存器R0
- STR(save to register)
4. 算术运算
- ADD 不带进位的加法
- ADDC 带进位进行加法
- ADDS 较大数相加,如果有进位,需要更改cpsr的第一位的进位位状态时使用.
- SUB/SUBC: 不带进位/带进位 进行减法
5. 位操作
- LSL: 逻辑左移(Logical Shift Left),寄存器中字的低端空出的位补0。
- 左移n位–>原数*= 2^n
LSL R0,R1,LSL#3 ;R0←R1*2^3
- 左移n位–>原数*= 2^n
- LSR: 逻辑右移(Logical Shift Right),寄存器中字的高端空出的位补0。
- 右移n位–>原数/=2^n
LSL R0,R1,LSR#4 ;R0←R1/2^4
- 右移n位–>原数/=2^n
立即数
相当于c中的一个常量.
#1234e320
但是在指令中如果操作一个立即数,有可能立即数超过了最大范围:如32-bit的ARM中指令占20bit,留给用户的只有12bit,也就是说命令能操作的最大数范围是2^12=4096,这对于贪婪的程序猿来说是不够的.因此,ARM设计了一种解决方案.将这12bit分为了两部分:包含8bit的基数和4bit的偏移标志位.
函数实现
压栈
1.当在同一模式下调用函数时:
stmfd sp!, {lr} @加上!是为了压栈后,sp能够对应的变化
2.当切换到不同模式时,需要保存通用寄存器的状态,保护现场
stmfd sp!, {r0-r12, lr} @压栈
.......
ldmfd sp!, {r0-12, pc}^ @出栈
出栈
ldmfd sp!, {pc}
返回值
函数的返回值是放在r0中的.这样c代码就可默认地获取到返回值了.