内嵌汇编的语法及最常用的arm汇编指令(转载)

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}

 

你可能感兴趣的:(内嵌汇编的语法及最常用的arm汇编指令(转载))