arm裸机学习预备知识一:arm汇编及机器码

注:以下学习内容学习于韦东山老师arm裸机第一期教程

   

    一.常用arm汇编指令

        1.1 ldr,读地址指令

            ldr R0,[R1]

           假设R1的值是x,那么这条语句:读地址x上的数据(4字节),保存到R0中

        

        1.2 str,写地址指令

            str R0,[R1]

           假设R1的值是x,把R0的值写到地址x(4字节)

        

        1.3 mov

            mov R0,R1

          把R1的值赋给R0,R0 = R1

          mov R0,#0x100(#后面表示是一个立即数) R0 = 0x100

        

        1.4 ldr ,伪指令

            ldr R0, = 0x12345678

          R0 = 0x12345678

            这是一条伪指令,它会被拆分为几条真正的ARM指令

            因为如果写入 mov R0,#0x12345678 是一条错误指令

扫描二维码关注公众号,回复: 1721896 查看本文章

            因为32位的arm指令,肯定会有一些字节表示mov指令本身,有一些位表示R0,剩下的不足32位,不能够保存任意的值,只能够保存简单值,也被称为立即数。 (0x100就是简单值)                                    

            因此引入伪指令ldr R0, = 0x12345678(注意有个等号,与读内存时不同),这条指令会被拆分成真正的arm指令。

            例如下面的代码
          
  .text
            .global _start

            _start:
                 /* 伪指令 */
                 ldr r0, =0x12345678
                 ldr r1, =0x100
                 mov r1, #0x200
            halt:
                b halt              
            反汇编代码如下:           
      
     led_on.elf:     file format elf32-littlearm

            Disassembly of section .text:

            00000000 <_start>:
            0:    e59f0008     ldr    r0, [pc, #8]    ; 10 <.text+0x10>
            4:    e3a01c01     mov    r1, #256    ; 0x100
            8:    e3a01c02     mov    r1, #512    ; 0x200

            0000000c <halt>:
            c:    eafffffe     b    c <halt>
            10:    12345678     eornes    r5, r4, #125829120    ; 0x7800000

            1.4.1 从上面代码可以看出,伪指令ldr r0, =0x12345678被转换成为了 ldr r0,[pc,#8],即去PC+8地址的地方读数据

              由于我使用的是arm-linux编译器,对于arm架构,PC(R15寄存器的别名)值等于当前地址+8,因此回去8+8=16,对应16进制0x10,

              因此回去0x10处读数据,读到12345678

              对于PC=当前地址+8的解释:

                对于arm架构,CPU是以流水线的方式执行的,即当前执行地址a的指令,已经在对地址a+4的指令进行译码,已经在读取地址a+8的指令

                因此 PC = a + 8

                

            1.4.2 对于伪指令ldr r1, =0x100,由于0x100比较简单,是一个立即数,因此不需要去内存读,直接转变为mov r1, #256

        1.5 sub

            sub r0,r1,#4  <==> r0 = r1 - 4

           sub r0,r1,r2  <==> r0 = r1 - r2

            

        1.6 add

            add r0,r1,#4  <==> r0 = r1 + 4

           add r0,r1,r2  <==> r0 = r1 + r2

            

        1.7 b跳转

        

        1.8 bl 跳转的时候将返回地址保存到lr寄存器中

       

        1.9

            1.9.1 stm(把多个寄存器的值写入内存)

                stmdb sp!, {fp, ip, lr, pc}

                把多个寄存器的值写入sp处

                

                假设sp = 4096,由于是db,先减sp' = sp - 4 = 4092,然后存放到后面4个寄存器中,存放时有一个规则,高编号的寄存器存在高地址           

                fp->r11 ip->r12 lr->r14 pc->r15

                因此         PC存放在4092~4095

                然后再次减  lr存放在4088~4091

                然后再次减  ip存放在4084~4097

                然后再次减  fp存放在4080~4083


                !表示sp = 最终被修改的sp值 = 4080

                

            1.9.2 ldm(读内存,写入多个寄存器)

                ldmia sp, {fp,sp,pc}

                将sp地址的值存放到多个寄存器中,存放时有一个规则,高地址存放在编号高的寄存器中

                

                    假设sp = 4080,由于是ia,先读sp' = 4080

                    因此            fp存放4080~4083的值,等于原来保存的fp

                                    /* sp被修改了 */

                    然后再次增加    sp存放4084~4087的值,等于原来保存的ip

                    然后再次增加    pc存放4088~4091的值,等于原来保存的lr

                                    pc = lr,因此程序就会返回

                    最后再次增加    sp' = sp + 4,由于sp后面无!号,sp修改后的地址并不存入sp中

                    但是sp在前面被修改了。

                

                ia->过后增加(Increment After)

                ib->预先增加(Increment Before)

                da->过后减少(Decrement After)

                /* 常用db,编译器默认使用db */

                db->预先减少(Decrement Before)

            

    二.机器码

        2.1 在反汇编的第二列的数据中就是机器码,对应的就是bin文件的数据

        2.2 编译器将我们写的程序先编译为反汇编,变为机器码,存放到bin文件中,烧到单板内。

        2.3 机器码的格式(以mov指令为例)

            mov指令机器码格式如下图:

            

            其中最后12位表示立即数,最后12位拆分为高4位rotate,低8位immed_8

            立即数 = immed_8 循环右移 (2 * rotate位)

            

            mov r0, #0x100对应的机器码为e3a01c01,其中低12位为1100 0000 0001,rotate = 12, immed_8 = 1

            0x100 = 1 循环右移 24位

            

            修改bin文件来达到将mov r0,#0x100,改为mov r0,#0x400

            0x400 = 1 循环右移 22位 ==> rotate = 11, immed_8 = 1

            因此对应的二进制就是1011 0000 0001,对应的机器码就为e3a01b01,修改对应的bin文件即可

        

    
                                            
        
        
   

猜你喜欢

转载自blog.csdn.net/qq_36521904/article/details/80577330