匯編指令


匯編指令:邏輯指令、算術指令、跳轉指令

.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\0"

.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}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM