• 汇编指令


    汇编指令:逻辑指令、算术指令、跳转指令

    .text
        
        /* 逻辑指令 */
        mov r7,#0x88
        @ and r0,r1,#0xFF     //r0=r1&0xFF
        @ orr r7,r7,#0xffff77 //r7=r7&0x88,清除7号3号位,但立即数太大,报错
          bic r7,r7,#0x88       //清除r7中7号3号
        @ tst r0,#0x20        //测试5号位是否为0,为0则Z(30号位)标志置1
        @ cmp r1,r0           //将R1与R0相减做比较,并根据结果设置CPSR的标志位
        
        @ eg: 使能中断和快速中断
        @       mrs r0,cpsr     //对cpsr操作需要以寄存器为中介
        @       bic r0,r0,#0xc0 //I-6,F-7,使能,将6/7位清零
        @       msr cpsr,r0
            
        @ eg: 判断当前工作状态位ARM状态,是则切换到user工作模式?
        @     mrs r0,cpsr
        @     tst r0,#0x20    //5号位-1-Thumb状态,0-ARM状态
        @     andeq r0,#0xffffffe0  //1110 0000 ,先把M[4:0]清零
        @     orreq r0,#0x10  //将4号位置1
        @     mrseq cpsr,r0   //上一判断为真,则执行
        
        /* 算术指令 */
        @     add r0,r1,r2    //ro=r1+r2
        @      sub r0,r1,#3    //ro=r1-3
        @     sub r0,r1,r2,LSL#1      //r0=r1-(r2<<1)
        @      mul r1,r2,r3    //r1=r2*r3
        
        /* 跳转指令 */
        @      b       main    //跳转到标号为main的代码处
        @      bl   func    //保存下一条要执行的指令的位置到LR寄存器,跳转函数func
        @                   //跳转代码结束后,使用MOV PC,LR指令跳回来
        @      beq  addr    //当CPSR寄存器中的Z条件码置位时,跳转到该地址处
        @      bne  addr    //当不等时,跳转到地址addr
            
        .end

    用汇编实现以下功能:

     1 void main(void)
     2 {
     3      int ret=0;
     4      func1(2);
     5      while(1)  {}
     6 }
     7  
     8 func1(int a)
     9 {
    10      if(a=2)
    11         return func2(a); 
    12      else
    13         return func3(a);     
    14 }
    15 
    16 func2(int a)
    17 {
    18      return a+3;
    19 }
    20 
    21 func3(int a)
    22 {
    23      return a-1;
    24 }

    示例代码(1)

     1 .text
     2     
     3 main:
     4     mov r5,#0  //0x00
     5     mov r0,#2  //0x04
     6     bl func1   //PC:0x08 LR:0x0C(12)
     7 
     8 main_end:
     9     b    main_end  @ while(1) {}; 死循环
    10     
    11 func1:
    12     cmp r0,#2   //PC:0x10(16) LR:0x0C
    13     bleq func2  //PC:0x14(20) LR:0x18(24) 注意此处LR被跳转指令里面嵌套的跳转指令覆盖了,导致无法跳回第一次跳转指令的下一指令
    14     blne func3  //跳转回来时,PC:0x18  LR:0x18 往下走到0x1C,
    15 func1_end:
    16     mov pc,lr   //PC:0x1C(28) LR:0x18,又将跳回0x18,成死循环,跳不出func1
    17     
    18 func2:
    19     add r0,#3   //PC:0x20(32) LR:0x18
    20     mov pc,lr   //PC:0x24     LR:0x18
    21     
    22 func3:
    23     sub r0,r0,#1 @或者写成sub r0,#1
    24 func2_end:
    25     
    26     .end
    27     

    为了避免跳转指令嵌套导致LR被覆盖的问题,可以在嵌套调用的函数里另设寄存器R储存会被覆盖的LR值,在跳转时,将R赋PC就可以

     1 .text
     2     
     3 main:
     4     mov r5,#0  //0x00
     5     mov r0,#2  //0x04
     6     bl func1   //PC:0x08 LR:0x0C(12)
     7 
     8 main_end:
     9     b    main_end  @ while(1) {}; 死循环
    10     
    11 func1:
    12     mov r12,lr    //保存LR:0x0C,避免被覆盖
    13         cmp r0,#2   
    14     bleq func2  // 注意此处LR被跳转指令里面嵌套的跳转指令覆盖了,导致无法跳回第一次跳转指令的下一指令
    15     blne func3  
    16 func1_end:
    17     mov pc,r12   
    18     
    19 func2:
    20     add r0,#3   
    21     mov pc,lr   
    22     
    23 func3:
    24     sub r0,r0,#1 @或者写成sub r0,#1
    25 func2_end:
    26     
    27     .end
    28     
     1 .text
     2     
     3     //load/store架构规定,存储器之间不能直接拷贝,需要通过寄存器做中转
     4     ldr r0,[r1]    //r0=*r1,r1里面存放的是地址,把该地址存放的内容读入到r0
     5                    //LDRB(byte)  LDRH(half word)
     6     ldr r0,[r1,#8] //r0= *(r1+8) 存储器地址为r1+8的字数据读入寄存器0
     7     ldr pc,_irq    //pc= *(_irq) 将标号中的内容放入PC中
     8     
     9     str r0,[r1]    // *r1=r0   将r0中的值写入存储器地址为r1的空间中,并将r1+4写入r1
    10     
    11     str r0,[r1],#4 //r0=*r1,r1=r1+4 ,将r0中的值写入存储器地址为r1的空间中,并将r1+4写入r1
    12     
    13     str r0,[r1,#4] //*r0=(r1+4) 将r0中的字数据写入以r1+4为地址的内存中
    14     
    15     .end

    示例:拷贝srcBuf里的内容到destBuf中

    .text
        
        ldr  r0,=srcBuf   @r0存放src的地址
        ldrb r1,[r0]      @将r0里地址(src)里的(1byte)数据存入r1
        ldr  r0,=destBuf  @r0存放dest地址
        strb r1,[r0]      @将r1里的数据存入r0里的地址的空间
        
    scrBuf:
        .byte 0x01,0x02,0x03,0x04
    
    .data destBuf: .space
    8 .end

    示例2:用汇编实现以下功能:

    main()
    {
        int i=0;
        const char buf[]={1,2,3};
        char destbuf[8];
        for(i=0;i<3;i++)
        {
             destbuf[i] = buf[i];  
        }   
    
    }
    main:
        mov  r5,#0       @用于for循环计数
        ldr  r7,=buf
        ldr  r8,=destbuf
        
    loop:
        cmp  r5,#3
        beq  main_end
        add  r5,#1
        
        ldrb r0,[r7],#1  @将r7里的地址buf里的1byte数据存入r0后,r7=r7+1
        strb r0,[r8],#1  @将r0的值赋给r8里的地址dest空间后,r8=r8+1
        b loop
        
    main_end:
        b main_end
    
    buf:
        .byte 1,2,3   @定义在代码段仅可读,在数据段可读可写
    
        .data 
        
    destbuf:
        .space 8    @定义空间大小为8个字节
        
        .end

    GNU汇编伪指令

    .text                  // 将定义符开始的代码编译到代码段
    
    .data                  // 将定义符开始的代码编译到数据段
    
    .end                   //文件结束
    
    .equ   GPG3, 0xFFFF    //定义宏
    
    .byte                  //定义变量1字节
    
    .word                  //定义word变量(4字节 32位机)
    
    .string                //定义字符串  .string  "abc"
    
    .global   _start       //声明_start为去全局符号

    批量操作指令

    ia --- Increment After  

    ib --- Increment Before

    da --- Decrement After

    db --- Decrement Befor

    stmdb和ldmia指令一般配对使用,stmdb用于将寄存器压栈,ldmia用于将寄存器弹出栈,作用是保存使用到的寄存器。

    详见:https://blog.csdn.net/minsophia/article/details/53080183

    指令:stmdb sp!,{r0-r12,lr}
    含义:sp = sp - 4,先压lr,sp = lr(即将lr中的内容放入sp所指的内存地址)。sp = sp - 4,再压r12,sp = r12。sp = sp - 4,再压r11,sp = r11......sp = sp - 4,最后压r0,sp = r0。

    如果想要将r0-r12和lr弹出,可以用ldmia指令:

    指令:ldmia sp!,{r0-r12,lr}

  • 相关阅读:
    选择器
    【兼容】text
    SQL2008的数据更新跟踪测试
    拖拽文件到RichEdit的后期处理
    Web Browser 的扩展
    URL Protocol Handler
    asterisk1.6异步脚本
    CSDNER如何才能做到"最不缺的是技术"
    关于SQL语句Count的一点细节
    TG787 脚本
  • 原文地址:https://www.cnblogs.com/y4247464/p/12271751.html
Copyright © 2020-2023  润新知