Linux_ARM汇编(Day18)

一 回忆昨天的内容
    
    ARM  A R M 
    cortex-a53  8个cpu 1.4GHz
    
    流水线 
    三级流水线
    F D E 
    
    CPI 
    6周期 6条指令  CPI = 1
    6周期 4条指令  CPI = 1.5
    
    arm体系结构与编程
    7种工作模式
    svc        管理模式
    fiq              快速中断
    irq                 中断
    undef             未定义
    abort             终止
    system         系统
    
    user             用户
    
    前6中属于特权模式 最后一种属于非特权模式
    前5种异常模式 后两种正常模式
    
    arm有两种工作模式 arm, thumb
    32bit 16bit
    
    arm中有多少寄存器
    37
    31 通用寄存器
    6  状态寄存器 
    1  cpsr 程序状态寄存器 
    NZCV 位  F I T
    5  spsr 备份cpsr
    
    arm 汇编指令
    1. blx  分支跳转指令
        b cond 
        l link  带链接 把下一条指令的地址 ---》LR(r14)
        x 带状态切换的 
        arm ---》 thumb ---》 arm
    2. 算数运算指令
        add
        adc 
        sub
        sbc
    3. 数据传输指令
        mov {cond} {s} <Rd>, <operand>
        operand的三种表现形式:
        立即数
        通用寄存器
        通用寄存器移位之后的结果
    4. 移位指令
        LSL
        LSR
        ASR
        ROR  循环右移
        RRX  带扩展位的循环右移

二 shell编程框架的第一版

    获取干净的源码: make clean
    编译: make 
    链接脚本: shell.lds 
    
    Makefile
  目标:依赖
  
  编译好之后,放在板子上执行:
  1. 进入下位机 uboot的命令行
  2. 通过tftp 下载 shell.bin 
  3. 修改开发板的ip:
          setenv ipaddr 192.168.1.6
          saveenv
       修改PC的ip:
          setenv serverip 192.168.1.8
          saveenv
  4. 将虚拟机的ip也设置成192.168.1.8 
  5. 在下位机ping 上位机 
       第一次ping 不通不怪你 
       再ping一次
  6. 下载 shell.bin:
          tftp 48000000 /tftpboot/shell.bin
          执行:go 0x48000000
          
三 ARM汇编:
        3.0
        qemu,仿真软件 跨平台的 
        运行在pc机上,模拟ARM核执行指令的执行过程
        qemu 的安装
        sudo apt install qemu 
        1.重新编译程序:
        arm-cortex_a9-linux-gnueabi-as add.s -o add.o -g
        arm-cortex_a9-linux-gnueabi-ld add.o -o add
        2.启动qemu的服务端
        qemu-arm -g 1234 add 
        3.启动客户端调试程序
        arm-cortex_a9-linux-gnueabi-gdb add
        (gdb) l
        (gdb) target remote localhost:1234
        (gdb) b 7 
        (gdb) info reg
        (gdb) n
        (gdb) info reg r0
        (gdb) info reg r1
        
        3.1 位运算指令
            and <cond> {s} <Rd>, <Rs> ,<operand> @按位与
                and r0, r1, r2 @r0=r1&r2
                and r0, r1, #8 @r0=r1&8
                and r0, r1, r2, lsl #3 @r0=r1&(r2<<3)
            
            orr <cond> {s} <Rd>, <Rs> ,<operand> @按位或
                orrgts r0, r1, r2 
            
            eor <cond> {s} <Rd>, <Rs> ,<operand> @按位异或
                eor r0, r0, #8 @r0 = r0^8
                
                如何取反32bit整形变量的bit15?
                mov r1, #1
                eor r0, r0, r1, lsl #15 
            
            bic <cond> {s} <Rd>, <Rs> ,<operand> 
                @第2个操作数对应的bit位中为1,结果为0
                @第2个操作数对应的bit位中为0,结果不变
                bic r0, r0, #0x08 @将r0中的bit 3位清0
                如何清零32bit整形变量的bit7,其他位保持不变?
                mov r1, #1
                bic r0, r0, r1, lsl #7
                
        3.2 比较测试指令
            cmp {cond} <Rn>,<operand> 
                特点:
                    1) 不需要+s,默认就影响NZCV位
                    2) 操作结果不保存
                    
            cmp r1, #0x10  @alu_out = r1 - 0x10
                                         @r1 > 0x10  C = 1
                                         @r1 == 0x10  Z = 1
                                         @r0 < 0x10  C = 0
                                         
            
            tst {cond} <Rn>,<operand>
                tst r0, #0x08  @测试 r0的bit3 是否为0
                                           @ alu_out = r0 & 0x08
                                           @ 如果为0 , Z = 1
                                           @ 如果非0 , Z = 0
                                           
            teq {cond} <Rn>,<operand>
                teq r0, #0x08 @ 测试r0 和 0x08是否相等
                                          @ alu_out = r0 ^ 0x08
                                          @ 相等 Z = 1
                                          @ 不相等 Z = 0
                                          
        练习: 求两个数的最大公约数:
                        128                    24
        算法:                 104                    24 
                                                    80                         24
                                                                    56                     24
                                                                                32                        24
                                                                                                8                         24
                                                                                                             16                        8
                                                                                                                             8                        8
        3.3 加载存储指令
        ARM 中所有的运算都是在通用寄存器中完成的
        加载指令:将数据由内存加载到寄存器中!
        操作的对象是:
            通用寄存器
            r0 ~ r15
            
            mov r1, 0x48000000
            ldr r0, [r1]   @将内存0x48000000开始的4字节数据加载到r0中
                                         @ r0 = *((int *) 0x48000000)
            ldrb r0, [r1]     @将内存0x48000000开始的1字节数据加载到r0中                         
                                         @ r0 = *((unsigned char *) 0x48000000
            ldrsb r0, [r1]     @将内存0x48000000开始的1字节数据加载到r0中, 
                                                r0中的高24bit补符号位
            ldrh r0, [r1] @将内存0x48000000开始的2字节数据加载到r0中,
                                            r0的高16位补0
            ldrsh r0, [r1] @将内存0x48000000开始的2字节数据加载到r0中,        
                                            r0的高16位补符号位
                                            
            ldr r0, [r1]   @[r1]  ---> r0
            ----------------------------------
            ldr r0, [r1, #0x08]      @ [r1+0x08] ----> r0
            ldr r0, [r1+r2]          @ [r1+r2] ----> r0
            ldr r0, [r1,r2,lsl #2] @ [r1 + r2<<2] ---> r0
            ----------------------------------
            ldr r0, [r1, #0x08]!     @ [r1+0x08] ----> r0  r1=r1+0x08 加!会更新基址
            ldr r0, [r1, r2]!        @ [r1+r2] ----> r0    r1=r1+r2   
            ldr r0, [r1,r2,lsl #2]!  @ [r1+r2*4] ---->r0   r1=r1+r2*4 
            ----------------------------------
            ldr r0, [r1], #0x08             @ [r1] ----> r0     r1= r1+0x08
            ldr r0, [r1], r2                 @ [r1] ----> r0       r1= r1+r2
            ldr r0, [r1], r2, lsl #3 @ [r1] ----> r0     r1=r1+r2*8
            ----------------------------------
            
            存储指令:
            str 从寄存器 ---》 内存
            mov r1, 0x48000000
            str r0, [r1] @将r0在的4个字节的数据写入到0x48000000的内存中
            strb r0, [r1] @将r0在的(低8位)1个字节的数据写入到0x48000000的内存中
            strh r0, [r1] @将r0在的(低16位)2个字节的数据写入到0x48000000的内存中
            
            str r0, [r1]                             @r0 ----> r1
            str r0, [r1+0x08]                 @r0 ----> r1+0x08
            str r0, [r1,r2]                    @r0 ----> [r1+r2]
            str r0, [r1,r2,lsl #2]    @r0 ----> [r1+r2*4]
            -------------------------------------------------
            str r0, [r1+0x08]!            @r0 ----> [r1+0x08]   r1=r1+0x08
            str r0, [r1]!, r2             @r0 ----> [r1+r2]   r1=r1+r2
            str r0, [r1]!, r2, lsl #2        @r0 ----> [r1+r2*4] r1=r1+r2*4
            -------------------------------------------------
            str r0, [r1], #0x08                    @r0 ----> [r1]   r1=r1+0x08
            str r0, [r1], r2                       @r0 ----> [r1]     r1=r1+r2
            str r0, [r1], r2, lsl #2        @r0 ----> [r1]   r1=r1+r2*4
            -------------------------------------------------
            练习: memcpy,将内存0x8e00开始的64字节的数据拷贝到0x8f00开始的内存空间。
            参见代码 memcpy.s
            
        3.4 栈操作指令:
            注意:满栈和空栈指的并不是栈里面的元素是否满了,
            指的是栈指针上面或者下面的空间中有没有数据
            或者说,接下来要存数据的时候,先放数据还是先改变sp的值
            ldmxx sp!,{r0~r5, r8}
            @将sp指向的栈空间的数据加载到 r0, r1, r2,r3,r4,r5,r8中
    
            stmxx sp!, {r0~r5,r8} 
            @将r0,r1,r2,r3,r4.r5,r8中的数据加载到sp指向的栈空间中
            
            xx,
                FD
                FA
                ED
                DA 
            
            stmfd sp!, {r0~r5,r8} 等价于 push {r0~r5,r8}
            ldmfd sp!, {r0~r5,r8} 等价于 pop {r0~r5, r8}
            按满减栈压入栈,也按满减栈弹出数据,就可以恢复寄存器
            
            局部变量如何在栈里面分配空间
            C 语言的运行是离不开栈的!
                1) 局部变量在栈中分配空间
                2) 函数嵌套调用时lr需要压入栈
            代码参见 test.s
            arm-cortex_a9-linux-gnueabi-gcc test.c -o test
            arm-cortex_a9-linux-gnueabi-objdump -S test > 1.asm
            
            fun1 ()
            {
                b++;
            }
            fun ()
            {
                push {fp, lr}
                fun1 (); //bl fun1 ---> lr = a++;
                a++;
                
                pop {lr}
                mov pc,lr
                pop {pc}
            }
            main ()
            {
                fun ();//bl fun ---> lr = i++;
                i++;
            }
            
        3.5 伪指令
            3.5.1 ldr 伪指令
            伪指令本身不被CPU所识别,
            但是能被汇编器编译成一条或者多条cpu所识别的指令
            实现了一个小功能
            ldr r0, [r1] //汇编指令 [] 有中括号是加载指令
            没有[] 是伪指令
            .code 32
            .global _start
            .text
            
            _start:
                @mov r0, #0x1ff //作业
                ldr r0, =0x1ff
                ldr r0, [pc]
                add r3, r4, r5
                b .
            .word 0x1ff
            
            .end
            
            ldr r0, =0x1ff
            ldr r1, =test @将立即数本身放到r1
            ldr r1, test @将立即数指向的内存中的数据放到r1
            
            3.5.2 nop 伪指令
                mov r0, r0
                一般用于延时
            
            3.5.3 adr 伪指令
            小范围的地址加载指令 
            忽略
            
        3.6 伪操作
        汇编文件中 以“.” 开头的都是伪操作
        伪操作是给汇编器使用的,一旦编译完成就消失了
        .text
        .data
        .bss
        .equ
                .equ NUM, #20 @类似于C语言中的宏
        .global
        .extern
        .byte
        .word
        .space 1024 @分配1024个字节的空间
        .string 
                .string "abcdefg"
        .ascii
        .code 32 ==== .arm
        .code 16 ==== .thumb
        .section  
        
        练习:用汇编实现strcmp
        r0   <-- "abcefg"    ldrb r2,[r0],#1
        r1   <-- "aabced"    ldrb r3,[r1],#1
        
        cmp r2,r3
        beq
        
        阅读uboot代码
        
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值