汇编指令

Posted y4247464

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了汇编指令相关的知识,希望对你有一定的参考价值。

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

.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

技术图片

 

 

技术图片

 

以上是关于汇编指令的主要内容,如果未能解决你的问题,请参考以下文章

汇编指令JMP是啥意思?

汇编 LEA 指令

用于复数乘法的汇编代码/AVX 指令。 (GCC 内联汇编)

汇编学习笔记-伪指令

逆向工程部分

汇编指令机器码说明