1. 在c里内嵌汇编
__asm__ __volatile__(
"汇编代码 \n"
"汇编代码 \n"
:"=r"(c变量名) //第一个冒号表示从汇编里输出到c语言的变量, =号表示在汇编里只能改变C变量的值,而不能取它的值. +号表示可以取变量值,也可改变变量的值. r表示在汇编里用一个寄存器代替c变量
:"r"(c变量名) //第二个冒号表示汇编里只能取c变量的值, 不能再有"=","+"号
//输入的变量的寄存器只能使用一次, 如果多次使用此输入的值,则应放到一个固定的寄存器上面(R0-R12)
:"r0", "r1" //第三个冒号表示告诉编译器不要把r0, r1寄存器分配给%0, %1等
);
// __volatile__ 告诉编译器不要优化下面的汇编代码, 可用可不用
2. (mov rd, #立即数或寄存器), 把立即数或寄存器的值给rd寄存器
//立即数受限制: 4位表示移位, 8位表示数字: 0x56000000 == 0x56 << 24;
//注意,只有MOV指令才可以把一个寄存器上的值搬移到另一个寄存器
3. ldr rd, =立即数, 立即数没限制, //把立即数放入rd寄存器 , ldr不能用于寄存器给寄存器赋值
4. add rd, r0, #立即数或寄存器 //r0+#立即数或另一寄存的值放入rd寄存器
//add r0, #4 --> add r0, r0, #4
5. sub rd, 被减数, 减数 //被减数必须是寄存器, 减数可以是立即数或寄存器
6. mul rd, rm, rn //rd和rm不能同一个寄存器(旧版本编译器)
//////////////////////////////////////////
CPSR / SPSR (架构手册P49)
31 30 29 28 7 6 4--0
N Z C V I F M[4:0]
工作模式位(架构手册P52)
I bit: Disables IRQ interrupts when it is set.
F bit: Disables FIQ interrupts when it is set.
N bit: 表示指令里目标寄存器的结果为负数时, N=1, 如为正数或零时N=0
Z bit: 如指令运算的结果为0, 则Z=1, 如果结果不是0, 则Z=0
C bit: 如果指令运算的结果产生进位或借位时, C=1, 如果没有, C=0
V bit: 如果指令运算的结果溢出时, V=1, 如果没有V=0
因cpsr是个特殊的寄存器, 需用特定的汇编指令来读取出来
mrs r0, cpsr //把cpsr的值读出放入通用寄存器r0里
默认情况下, 一般的指令都不会根据目标寄存器里的结果来改变cpsr里的值, 需要特定的汇编指令
才会改变cpsr的值
cmp // cmp r0, #1 根据r0减去1的结果来改变cpsr的条件状态位, r0本身的值不变
movs //根据目标寄存器的结果来改变cpsr的条件状态位
adds
subs
...
///////////////////////////////////////////
7. condition flasg : N(负数) Z(是否零) C(进位/借位) V(溢出)
conditon: 架构手册/p112
eq(0000) : 当cpsr里的Z位的值为1时, 此条件成立, 否则条件不成立, 使用此条件的
汇编指令不会执行
ne(0001) : 当cpsr里的Z位的值为0时, 此条件成立, 使用此条件的汇编指令会执行
//如果指令里没有指定条件, 则为条件码所占的位为e
8. cmp Rn, #立即数/寄存器 //根据Rn减去第二个参数的值的结果更新cpsr的条件标志位
9. movs Rd, #5 //先把5放入Rd, 再根据Rd里的结果更新cpsr的条件标志位
10. 移位lsl, lsr 逻辑左移, 右移
"lsl r0, r0, #4 \n"
asr 算术右移(C语言里>>是算术右移)
11. and rd, rn, #立即数或者寄存器 //把两个数位与上后,把结果放入rd寄存器 add rd, #4 == add rd, rd, #4
orr rd, rn, #立即数或者寄存器 //把两个数位或上后,把结果放入rd寄存器
mvn r0, #4 //把4的反码存入r0寄存器
12. bic rd, rn, op(#立即数或寄存器) //清除rn对应op里的相应位是1的值(可指定多位), 把结果放入rd
13. ldr rd, [rn] //把rn里的值作为地址,然后把地址上面的值放入rd
14. str r0, [rn] //把rn里的值作为地址, 然后把r0上的值写到rn里的地址上
注意: ldr/str的"[]"符号里不能写立即数的地址, 必须要把地址保存到寄存器后才可以操作
15. ldr/str 操作4个字节 ldrb/strb操作1个字节 ldrh/strh操作2个字节
在内嵌汇编里, 输入输出的%寄存器要用固定的寄存器来操作,尢其是输入的,一进去应用一个固定的寄存器代替它
16, ldr rd, [rm, rn/#立即数] //把rm寄存器上值加上rn值的结果作为地址,再把地址上值放入rd
17. mydata:
.word 0x789, 0x123 //相当于申请8个字节空间, 前4个字节放的值为0x789, 后4个字节放的值为0x123. mydata就是首地址, mydata本身不会占指令空间
.word func //func是个函数, 分配4个字节空间, 装func函数的地址
18 mystr:
.string "hello"
.align 2 //.string定义一字符串hello, .align 2按2的2次方字节来对齐, mystr为字符串的首地址
r13寄存器就是sp寄存器, 用于记录当前栈顶所在的内存地址
//stm/ldm是批量处理指令, fd为full descend, 意思为sp指向的地址是有数据的, 操作时先下降, 再保存
19. stmfd sp!, {r0-r3} //把寄存器r0-r3里的值保存到栈里去, push {r0-r3}, 压栈顺序r3, r2, r1, r0
ldmfd sp!, {r0-r3} //把保存到栈的值恢复到r0-r3寄存器去, pop {r0-r3}