ARM裸机-9

1、ARM汇编指令集

1.1、两个概念:指令与伪指令

        (汇编) 指令是CPU机器指令的助记符,经过编译后会得到一串10组成的机器码,可以由CPU读取执行。

        (汇编)伪指令本质上不是指令 (只是和指令一起写在代码中),它是编译器环境提供的,目的是用来指导编译过程,经过编译后伪指令最终不会生成机器码。

1.2、两种不同风格的ARM指令

        ARM官方的ARM汇编风格::指令一般用大写、Windows中IDE开发环境 (如ADS、MDK等) 常用。如:LDR RO,[R1]。

        GNU风格的ARM汇编::指令一般用小写字母、linux中常用。如::ldr ro,[r1]。

1.3、ARM汇编特点

1.3.1、LDR/STR架构

        ARM采用RISC架构,CPU本身不能直接读取内存,而需要先将内存中内容加载入CPU中通用寄存器中才能被CPU处理。

        ldr (load register) 指令将内存内容加载入通用寄存器。

        str (store register) 指令将寄存器内容存入内存空间中。

        ldr/str组合用来实现 ARM CPU和内存数据交换。

1.3.2、8种寻址方式

        寄存器寻址                                                                mov r1, r2

        立即寻址                                                                   mov r0,#OxFF00

        寄存器移位寻址                                                        mov r0, r1, Isl #3

        寄存器间接寻址                                                        ldr r1, [r2]

        基址变址寻址                                                            ldr r1, [r2, #4]

        多寄存器寻址                                                            ldmia r1!, {r2-r7, r12}

        堆栈寻址                                                                   stmfd sp!, {r2-r7, lr}

        相对寻址                                                                   flag:beq flag

1.3.3、指令后缀

同一指令经常附带不同后缀,变成不同的指令。经常使用的后缀有:

        B (byte) 功能不变,操作长度变为8位

        H (half word)功能不变,长度变为16位

        S(signed)功能不变,操作数变为有符号

        例如:ldr ldrb ldrh ldrsb ldrsh

        S(S标志)功能不变,影响CPSR标志位。

        例如:mov和movs

1.3.4、条件执行后缀

ARM裸机-9_第1张图片

1.3.5、多级指令流水线

        为增加处理器指令流的速度,ARM使用多级流水线,下图为3级流水线工作原理示意图。(S5PV210使用13级流水线,ARM11为8级)

        - 允许多个操作同时处理,而非顺序执行。

ARM裸机-9_第2张图片

        PC指向正被取指的指令,而非正在执行的指令。 

1.4数据传输和跳转指令集

1.4.1、数据处理指令

        数据传输指令                                         mov mvn

        对比:mov是原封不动的传递,而mvn是按位取反后传递

        算术指令                                                add sub rsb adc sbc rsc

        逻辑指令                                                and orr eor bic

        比较指令                                                cmp cmn tst teq

        对比:比较指令用来比较两个寄存器中的数;比较指令不用后加s后缀就可以影像CPSR中的标志位。

        乘法指令                                                mvl mla umull umlal smull smla  

        前导零计数                                            clz

1.4.2、CPSR访问指令

        mrs&msr

        mrs用来读psr,msr用来写。

        CPSR寄存器比较特殊,需要专门的指令访问,这就是mrs和msr。

1.4.3、跳转(分支)指令

        b & bl & bx

        b 直接跳转 (就没打开算返回)

        bl(branch and link),跳转前把返回地址放入lr中,以便返回,以便用于函数调用

        bx跳转同时切换到ARM模式,一般用于异常处理的跳转

1.4.4、访存指令

        ldr/str & ldm/stm & swp

        单个字/半字/字节访问 ldr/str

        多字批量访问 Idm/stm

        swp r1, r2, [r0]

        swp r1, r1, [r0]

1.4.5、立即数

        在数字之前要加#,机器才知道这是个数字

        合法立即数与非法立即数

        ARM指令都是32位,除了指令标记和操作标记外,本身只能附带很少位数的立即数。因此立即数有合法和非法之分。

        合法立即数:经过任意位数的移位后非零部分可以用8位表示的即为合法立即数。

1.4.6、软中断指令

        swi(software interrupt)

        软中断指令用来实现操作系统中系统调用

1.5、协处理器和协处理器指令

1.5.1、什么是协处理器

        SoC内部另一处理核心,协助主CPU实现某些功能,被主CPU调用执行一定任务。

        ARM设计上支持多达16个协处理器,但是一般SoC只实现其中的CP15(cp:coprocessor)。

        协处理器和MMU、cache、TLB等处理有关功能上和操作系统的虚拟地址映射、cache管理等有关。

1.5.2、协处理器cp15操作指令

        mcr & mrc

        mrc用于读取CP15中的寄存器

        mcr用于写入CP15中的寄存器

1.5.3、mrc & mcr的使用方法

mcr{} p15,,,,,{}
//opcode_1:对于cp15永远为0
//Rd:ARM的普通寄存器
//Crn: cp15的寄存器,合法值是c0~c15
//Crm: cp15的寄存器,一般均设为c0
//opcode_2:一般省略或为0

1.5.4、协处理器学习要点

        不必深究,将uboot中和kernel中起始代码中的一般操作搞明白即可。

        只看一般用法,不详细区分参数细节,否则会陷入很多复杂未知中。

        关键在于理解,而不在于记住。

1.6、ldm/stm与栈的处理

1.6.1、为什么需要多寄存器访问指令

        ldr/str每周期只能访问4字节内存,如果需要批量读取、写入内存时太慢,解决方案是stm/ldm。

        ldm(load register mutiple)

        stm(store register mutiple)

1.6.2、八种后缀

        ia (increase after) 先传输,再地址+4

        ib (decrease before) 先地址+4,再传输

        da (decrease after) 先传输,再地址-4

        db (decrease before) 先地址-4,再传输

        fd (full decrease) 满递减堆栈

        ed (empty decrease) 空递减堆栈

        fa (......) 满递增堆栈

        ea (......) 空递增堆栈

1.6.3、四种栈

        空栈:栈指针指向空位,每次存入时可以直接存入然后栈指针移动一格;而取出时需要先移动一格才能取出。

        满栈:栈指针指向栈中最后一格数据,每次存入时需要先移动栈指针一格再存入;取出时可以直接取出,然后再移动栈指针。

        增栈:栈指针移动时向地址增加的方向移动的栈。

        减栈:栈指针移动时向地址减小的方向移动的栈。

1.6.4、!的作用

ldmia r0, {r2-r3}
ldmia ro!, {r2-r3}

        感叹号的作用就是r0的值在ldm过程中发生的增加或者减少最后写回到r0去,也就是说ldm时会改变r0的值。

1.6.5、^的作用

ldmfd sp!, {r0-r6,pc}
ldmfd sp!, {r0-r6,pc}^

        在目标寄存器中有pc时,会同时将spsr写入cpsr,一般用于异常模式返回。

1.6.6、总结

        批量读取或写入内存时要用ldm/stm指令。

        各种后缀以理解为主,不需记忆,最常见的是stmia和stmfd。

        谨记:操作栈时使用相同的后缀就不会出错,不管是满栈还是空栈、增栈还是减栈。

1.7、伪指令

1.7.1、伪指令的意义

        伪指令不是指令,伪指令和指令的根本区别是经过编译后会不会生成机器码。

        伪指令的意义在于指导编译过程。

        伪指令是和具体的编译器相关的,我们使用gnu工具链,因此学习gnu环境下的汇编伪指令。

1.7.2、gnu汇编中的一些符号

        @ 用来做注释。可以在行首也可以在代码后面同一行直接跟,和C语言中//类似。

        # 做注释,一般放在行首,表示这一行都是注释而不是代码。

        : 以冒号结尾的是标号。

        . 点号在gnu汇编中表示当前指令的地址。

        # 立即数前面要加#或$,表示这是个立即数。

1.7.3、常用伪指令

.global _start    @ 给_start声明外部链接属性
.section .text    @ 指定当前段为代码段
.ascii .byte .short .long .word .quad .float .string @ 定义变量数据
.align 4    @ 以16字节对齐
.balignl 16 0xabcdefgh @ 16字节对齐填充
@b表示位填充;align表示要对齐;l表示long,以4字节为单位填充;16表示16字节对齐;0xabcdefgh是用来填充的原料。
.equ     @ 类似于C中宏定义

1.7.4、偶尔会用到的gpu伪指令

.end                @标识文件结束
.include            @头文件包含
.arm/.code32        @声明以下为arm指令
.thumb/.code16      @声明以下为thubm指令

1.7.5、最重要的几个伪指令

ldr            大范围的地址加载指令
adr            小范围的地址加载指令
adrl           中等范围的地址加载指令
nop            空操作

        ARM中有一个ldr指令,还有一个ldr伪指令,一般都是用ldr伪指令而不是ldr指令。

ldr r0, #0xff        @ldr指令
ldr r0, =0xff        @伪指令

1.7.6、adr与ldr

        adr编译时会被1条sub或add指令替代,而ldr编译时会被一条mov指令替代或者文字池方式处理。

        adr总是以PC为基准来表示地址,因此指令本身和运行地址有关,可以用来检测程序当前的运行地址在哪里。

        ldr加载的地址和链接时给定的地址有关,由链接脚本决定。

你可能感兴趣的:(ARM,arm开发)