ARM汇编指令集3 --汇编伪指令

来源:互联网 发布:淘宝网下载到桌面 编辑:程序博客网 时间:2024/06/08 15:22

ARM汇编指令集3 --汇编伪指令

                                               --参考朱有鹏裸机编程


1、协处理器和协处理器指令详解

什么是协处理器?协处理器的功能?

(1)MCR   &  MRC

MRC  :用于读取CP15中的寄存器

MCR:  用于写入CP15中的寄存器


(2)什么是协处理器?

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

2、ARM设计上支持多达16个协处理器,但是一般的SOC只实现其中的CP15

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



(3)怎么使用MCR & MRC

MRC & MCR的使用方法:

ARM  Cp 15协处理器

 

使能MMU

Mrc(读)  p15 , 0, r0, c1,c0 ,0

Mcr {<cond>} p15,<opcode_1> , <Rd>,

<Crn>, <Crm>,{<opcode_2>}

 

Rd:  ARM 的普通的寄存器,不能是R15

Crn:CP15的寄存器,合法值是C0~C15

CRM:CP15的寄存器,一般设为C0

Opcode_2:0


PS:对于协处理器学习的要点,不必深究,将UBOOT中和Kernel中起始代码中的一般操作搞明白就可以了。

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

3、关键在于理解,而不是死记硬背



2、LDM、STM批量处理的指令

从UBOOT搬到别的地方,做一个重定位的时候。

LDR、str每一个周期只能访问4字节的内存,如果需要批量读取,写入

内存的速度太慢,解决方案是:

STM、LDM(load register mutiple)

并行处理的,是为了提高频繁的大量的数据读取和写入的时候。


Stmia  sp,{r0 - r12}

r0存入sp指向的内存处(假设为0x30001000)

然后地址+4(即指向0x30001004),将r1存入该地址,然后地址再+4(指向0x30001008)

直到r12内容放入(0x3001030)

在一个访问周期同时完成13个寄存器的读写。

(单周期多寄存器访问)

SP理解为数组名


3、几种指令的后缀

ia:                               先传输,再地址+4

ib:                             先地址+4,再传输

da                                先传输,再地址+4

db:                               先地址-4,再传输

fd:                                满栈的递减堆栈

ed:                               空递减堆栈

Fa                                 满递减堆栈

ea                                 空递减堆栈



4/4种堆栈的形式

空栈:

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

(存储的地方是空的,先存后放)

满栈:

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

SP始终指向的是我们栈中满了的地方)

SP+1,先指针的移动,再存储数据)

增栈:

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

(可以往地址更大的地方移动)

减栈:

栈指针移动时向地址减少的方向移动的栈

(可以往地址更小的地方移动)


5、ARM汇编的部分伪指令

(1)指令经过编译之后会生成机器码,但是伪指令经过编译之后就消失了。

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

伪指令是和具体的编译器有关的,我们嵌入式开发就是用GNU工具链,

因此学习GNU环境下的汇编的伪指令


(2)在GCC里面,C和汇编是可以互相通用的。

@就是汇编里面注释的,跟C语言中//类似

:以冒号结尾的是标号(标号代表是后面指令的地址)

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

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


(3)汇编写一个死循环:

while(1)          C语言(for(;;))


flag:

            b  flag


常用的GNU伪指令:

.global _start           @给_start外部链接属性,相当于在别的文件定义了,想要在别的文件中使用

.section .text           @指定当前段为代码段,因为代码段是在运行的时候不变的,应该跟数据段分来

.ascii .byte .short .long .word      :非常类似于我们C语言的数据类型,定义变量的

IRQ_STACK_START:

.word  0x0badc0de

等价于 unsigned int IRQ_STACK_START = 0x0badc0de

 

                  @定义数据

.align 4          @以16字节对齐

.align 2           以4字节对齐 2^2

.balignl 16 0xabcdefgh  @16字节对齐填充

b表示位填充;align表示要对齐,l表示long,以4字节为单位对齐。

 

.equ              @类似于C中的宏定义



最重要的几个伪指令:

Ldr   :大范围的地址加载指令

Adr   :小范围的地址加载指令

Adrl  :中等范围的地址加载指令

Nop   :空操作

ARM中有一个ldr指令(前面是一个#号),还有一个ldr伪指令()


Ldr指令:    ldr  r0,#0xff

伪指令:ldr  r0, = 0xff

涉及到合法、非法立即数,涉及到ARM文字池

如果你用等号的话,就不用考虑后面的地址的长度。

如果是一个标号,所以不用=表示。

 

Adr与ldr

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

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

(这个地址就是一个相对的地址)

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

 

Adr和ldr的差别:ldr加载的地址在链接时确定

adr加载的地址在运行时决定

所以我们可以通过adr和ldr加载的地址,当前程序是否在链接时指定的地址运行。

跟地址的重定位是有关的













原创粉丝点击