第1课-ARM汇编编程概述

ARM标准汇编:适用于ARM公司的汇编器,适合在windows平台下使用,如ADS中使用
GNU汇编:适用于GUN交叉编译工具链中的汇编器,适合于Linux开发平台
汇编程序框架:

.section .data
    <初始化的数据>
.section .bss
    <未初始化的数据>
.section .text
.global _start
_start:
    <汇编代码>

建立汇编编程环境:汇编文件+链接脚本+Makefile+Ecplise
注意:

  1. 从SD卡启动,停留在uboot阶段,格式化整个内存
  2. 保存JLinkGDBServer一直在运行状态

第2课-ARM指令分类学习

算术和逻辑类指令

  1. mov
    MOV 从另一个寄存器、被移位的寄存器、或一个立即值装载一个值到目的寄存器(只能是通用寄存器)。你可以指定相同的寄存器来实现 NOP 指令的效果,你还可以专门移位一个寄存器:

      MOV     R0, R0                  ; R0 = R0... NOP 指令
      MOV     R0, R0, LSL#3           ; R0 = R0 * 8
    
  2. mvn
    在MOV的基础上进行取反之后再装载到目的寄存器

      MVN     R0, #4                  ; R0 = -5
      MVN     R0, #0                  ; R0 = -1
    


  3. sub
    SUB 用操作数 one 减去操作数 two,把结果放置到目的寄存器中。操作数 1 是一个寄存器,操作数 2 可以是一个寄存器,被移位的寄存器,或一个立即值:

      SUB     R0, R1, R2              ; R0 = R1 - R2
      SUB     R0, R1, #256            ; R0 = R1 - 256
      SUB     R0, R2, R3,LSL#1        ; R0 = R2 - (R3 << 1)
    


  4. add
    ADD 将把两个操作数加起来,把结果放置到目的寄存器中。操作数 1 是一个寄存器,操作数 2 可以是一个寄存器,被移位的寄存器,或一个立即值:

      ADD     R0, R1, R2              ; R0 = R1 + R2
      ADD     R0, R1, #256            ; R0 = R1 + 256
      ADD     R0, R2, R3,LSL#1        ; R0 = R2 + (R3 << 1)
    


  5. and
    AND 将在两个操作数上进行逻辑与,把结果放置到目的寄存器中;对屏蔽你要在上面工作的位很有用。 操作数 1 是一个寄存器,操作数 2 可以是一个寄存器,被移位的寄存器,或一个立即值:

    AND     R0, R0, #3              ; R0 = 保持 R0 的位0和1,丢弃其余的位。
    


  6. bic
    BIC 是在一个字中清除位的一种方法,与 OR 位设置是相反的操作。操作数 2 是一个 32 位位掩码(mask)。如果如果在掩码中设置了某一位,则清除这一位。未设置的掩码位指示此位保持不变。

    BIC     R0, R0, #%1011          ; 清除 R0 中的位 0、1、和 3。保持其余的不变。
    

比较指令

  1. cmp
    CMP 允许把一个寄存器的内容如另一个寄存器的内容或立即值进行比较,更改状态标志来允许进行条件执行。它进行一次减法,但不存储结果,而是正确的更改标志。标志表示的是操作数 1 比操作数 2 如何(大小等)。如果操作数 1 大于操作操作数 2,则此后的有 GT 后缀的指令将可以执行。此操作影响CPSR的N位和Z位。
  2. tst
    与CMP类似,对两个操作数进行按位与操作,根据操作结果修改CPSR的N位和Z位。

跳转指令

  1. b
    B 是最简单的分支。一旦遇到一个 B 指令,ARM 处理器将立即跳转到给定的地址,从那里继续执行。注意存储在分支指令中的实际的值是相对当前的 R15 的值的一个偏移量;而不是一个绝对地址。它的值由汇编器来计算,它是 24 位有符号数,左移两位后有符号扩展为 32 位,表示的有效偏移为 26 位(+/- 32 M)。
  2. bl
    BL 是另一个分支指令。就在分支之前,在寄存器 14 中装载上 R15 的内容。你可以重新装载 R14 到 R15 中来返回到在这个分支之后的那个指令,它是子例程的一个基本但强力的实现。

以上两条指令可以配合条件来实现条件跳转语句,有以下条件可以使用:

    EQ : 等于 
    如果一次比较之后设置了 Z 标志。 
      
    NE : 不等于 
    如果一次比较之后清除了 Z 标志。 
    
    GE : 大于或等于(有符号) 
    如果一次比较之后...
    设置了 N 标志并设置了 V 标志
    或者...
    清除了 N 标志并清除了 V 标志。 
      
    GT : 大于(有符号) 
    如果一次比较之后...
    设置了 N 标志并设置了 V 标志
    或者...
    清除了 N 标志并清除了 V 标志
    并且...
    清除了 Z 标志。 
      
    LE : 小于或等于(有符号) 
    如果一次比较之后...
    设置了 N 标志并清除了 V 标志
    或者...
    清除了 N 标志并设置了 V 标志
    并且...
    设置了 Z 标志。 
      
    LT : 小于(有符号) 
    如果一次比较之后...
    设置了 N 标志并清除了 V 标志。
    或者...
    清除了 N 标志并设置了 V 标志。 

移位指令

  1. lsl

      Rx, LSL #n    or
      Rx, ASL #n    or
      Rx, LSL Rn    or
      Rx, ASL Rn
    

    接受 Rx 的内容并按用‘n’或在寄存器 Rn 中指定的数量向高有效位方向移位。最低有效位用零来填充。除了概念上的第 33 位(就是被移出的最小的那位)之外丢弃移出最左端的高位,如果逻辑类指令中 S 位被设置了,则此位将成为从桶式移位器退出时进位标志的值。
    考虑下列:

      MOV    R1, #12
      MOV    R0, R1, LSL#2
    

    在退出时,R0 是 48。 这些指令形成的总和是 R0 = #12, LSL#2 等同于 BASIC 的 R0 = 12 << 2

  2. ror

      Rx, ROR #n    or
      Rx, ROR Rn
    

    循环右移类似于逻辑右移,但是把从右侧移出去的位放置到左侧,如果逻辑类指令中 S 位被设置了,则同时放置到进位标志中,这就是位的‘循环’。一个移位量为 32 的操作将导致输出与输入完全一致,因为所有位都被移位了 32 个位置,又回到了开始时的位置!

程序状态字访问指令

  1. msr
    复制一个寄存器到 PSR 中

      MSR     CPSR, R0                ; 复制 R0 到 CPSR 中
      MSR     SPSR, R0                ; 复制 R0 到 SPSR 中
    


  2. mrs
    复制 PSR 到一个寄存器中

      MRS     R0, CPSR                ; 复制 CPSR 到 R0 中
      MRS     R0, SPSR                ; 复制 SPSR 到 R0 中
    

存储器访问指令

  1. ldr
    把数据从内存装载到寄存器

    LDR{条件}    Rd, <地址>
    


  2. str
    把数据从寄存器写回内存

    STR{条件}    Rd, <地址>
    

第3课-ARM伪指令

ARM机器码

ARM机器码就是指令的二进制代码,通过将elf格式的执行程序进行反汇编后可以查看每条指令的机器码,是一个32位的整数。机器码分为若干个段,每个段可以反映指令本身的一些信息,比如指令的条件类型,操作数类型,操作数的值,是否影响CPSR,寄存器编号等。

定义类伪指令

伪指令本身并没有所对应的机器码,它只是在编译的时候起作用,或者转化为其他的实际指令来运行。类似于C语言中的预处理指令。

  1. global:定义全局符号
  2. data:定义数据段
  3. ascii:定义字符串数据
  4. byte:定义一个字节数据
  5. word:定义一个字的数据
  6. equ:类似于C语言中的宏定义

    .equ DA, 0x89  ; DA=0x89
    mov r0, #DA    ; r0=0x89
    
  7. align:控制对齐

    .data
    hello:
    .ascii "helloworld"
    .align 4
    bh:
    .byte 0x1
    wd:
    .word 0xff
    

操作类伪指令

  1. nop
    空操作,一般用来延时,实际上是用mov r0, r0来替代。
  2. ldr

    mov r0, #0x1ff   ;出错,对于mov指令,不能使用超过8位的立即数,这根机器码有关
    ldr r0, =0x1ff   ;正确,对于超过8位的赋值,需要使用ldr伪指令,小于8位也可以使用ldr进行赋值
    

第4课-协处理器访问指令

协处理器用于执行特定的任务,比如数学协处理器可以控制数字处理,以减轻处理器的负担。ARM可支持多达16个协处理器,其中CP15是最重要的一个。

协处理器可以用于提供额外的寄存器,用于控制缓存,MMU,保护系统,时钟模式以及其他的CPU选项,比如大小端工作模式。

对CP15的寄存器访问需要通过MCR和MRC来完成。

CP15提供了c0-c15共16组寄存器,在每组下面还有c0-cx若干小组寄存器,每个小组下面还有若干编码的具体寄存器。

MCR:将通用寄存器中的值放到协处理器中
MRC:与MCR相反,将值放回协处理器

    You can access CP15 registers with MRC and MCR instructions:
    MCR{cond} P15,,,,,
    MRC{cond} P15,,,,,

示例:

mrc P15, 0, r0, c0, c0, 0    ;将CP15的Main ID寄存器读取到r0中
mcr P15, 0, r0, c1, c0, 0    ;将r0赋值到CP15的Control寄存器

  • 无标签