ldm是什么意思

更新时间:2022-12-30 00:46:46 阅读: 评论:0


2022年12月30日发(作者:最牛历史老师)

ARM汇编指令

⽬录

⼀、ARM汇编指令集

、两个概念:指令和伪指令

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

(汇编)伪指令本质上不是指令(只是和指令⼀起写在代码中),它是编译器环境提供的,⽬的是⽤来指导编译过程,经过编译后伪指

令最终不会⽣成机器码。

、两种不同风格的ARM指令

ARM官⽅的ARM汇编风格:指令⼀般⽤⼤写、Windows中IDE开发环境(如ADS、MDK等)常⽤。如:LDRR0,[R1]

(我们使⽤)GNU风格的ARM汇编:指令⼀般⽤⼩写字母、linux中常⽤。如:ldrr0,[r1]

两种风格的指令差别不⼤,但是伪指令的差别特别⼤。

、ARM汇编特点

、特点1:LDR/STR架构

ARM采⽤RISC架构,CPU本⾝不能直接读取内存,⽽需要先将内存中内容加载⼊CPU中的通⽤寄存器中才能被CPU处理。

ldr(loadregister)指令将内存内容加载⼊通⽤寄存器。

str(storeregister)指令将寄存器内容存⼊内存空间中。

ldr/str组合⽤来实现ARMCPU和内存数据交换

注意:

CPU与内存之间的数据交换需要通过CPU中的通⽤寄存器才可以,所以访问效率会低⼀些。

、特点2:8种寻址⽅式

Mov表⽰从寄存器到寄存器,ld和str表⽰从内存到寄存器。

寄存器寻址movr1,r2

R1和r2都是寄存器名字,意思是将r2中的内容传送到r1

⽴即寻址movr0,#0xFF00

就是⽴即数寻址,意思是将⽴即数#0xFF00给r0

寄存器移位寻址movr0,r1,lsl#3

意思是将r1左移3位后传送个r0(lsl表⽰左移)

寄存器间接寻址ldrr1,[r2]

[r2]表⽰r2中存储的所指向的内存的地址,意思是将r2中存储的所指向的内存中的数据给r1。

基址变址寻址ldrr1,[r2,#4]

意思是将r2中存储的地址加上4后所指向的地址中的内容给r1。

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

意思是⼀次访问7个寄存器,{r2-r7,r12}表⽰r2、r3、r4、r5、r6、r7、r12这7个寄存器。⽽r1!表⽰⼀串内存空间,相当于数组头地

址,第⼆个参数有7个寄存器,它就有7个内存空间。

将r1所存地址所代表的内存及其后边的7个连续内存中存储的数据传给7个寄存器。

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

sp是堆栈指针,是⼀个确定的值。具体和多寄存器寻址类似。

相对寻址beqflag以PC为标志来跳转。

在汇编中,“flag:”这种形式的写法叫做标号。⽤来标记后边指令的地址。这样可以直接跳转到标号出执⾏。和C语⾔中的goto⼀样。

、特点3:指令后缀

同⼀指令经常附带不同后缀,变成不同的指令。

经常使⽤的后缀有:

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

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

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

如:ldrldrbldrhldrsbldrsh

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

如:mov和movs

movr0,#0将0这个数字赋给r0,且r0中的标志位不变。

movsr0,#0将0这个数字赋给r0,且r0中的Z标志位变为1。

、特点4:条件执⾏后缀(⼤于、⼩于、等于)

例如:

movr0,r1相当于C语⾔中的r0=r1;

moveqr0,r1如果eq后缀成⽴,则直接执⾏movr0,r1;如果eq不成⽴,则此语句直接作废,相当于没有。类似于C语⾔中

if(eq){r0=r1;}

注意:

条件后缀是否成⽴不是取决于本句代码,⽽是取决于这句代码之前的代码运⾏的结果。

条件后缀决定了本句代码是否被执⾏,⽽不会影响上⼀句和下⼀句代码是否执⾏。

、特点5:多级指令流⽔线

为增加处理器指令流的速度,ARM使⽤多级流⽔线.,下图为3级流⽔线⼯作原理⽰意图。(S5PV210使⽤13级流⽔线,ARM11为8

级)允许多个操作同时处理,⽽⾮顺序执⾏。

PC指向正被取指的指令,⽽⾮正在执⾏的指令。

、数据传输与跳转指令

、数据处理指令

数据传输指令movmvn

mov(move)movr1,r0在两个寄存器之间进⾏数据传递

movr1,#oxff将⽴即数赋值给寄存器

mov和mvn⽤法⼀样,区别是mov是原封不动的传递,⽽mvn是按位取

反后传递。

例如:r1=0x000000ff,然后movr0,r1后,r0=0xff,但是我mvnr0,r

后,r0=0xffffff00

算术指令addsubrsbadcsbcrsc

逻辑指令andorreorbic

and逻辑与

orr逻辑或(位或)

eor裸机异或

bic位清除指令

bicr0,r1,#0x1f将r1中的数的bit0到bit4清零后赋值给r00x1f=0x00011111

⽐较指令(⽐较指令⽤来⽐较2个寄存器中的数)cmpcmntstteq

cmpcmpr0,r1判断r0-r1=0,等价于subr2,r0,r1(r2=r0-r1)

cmncmnr0,r1判断r0+r1=0,等价于addr0,r1

tsttstr0,#0xf测试r0的bit0~bit3是否全为0

tstr0,#0x8测试r0的bit3是否为0。

teqteqr0,r1对两个数进⾏EOR(异或),⽐较是否相等。若两个数

相等,结果为假,否则,结果为真。

注意:⽐较指令不⽤后加s后缀就可以影响cpsr中的标志位。

⽐较指令不需要保存结果,直接访问标志位即可知道⽐较指令的结果。

乘法指令mvlmlaumullumlalsmullsmlal

前导零计数clz(基本⽤不到)

、cpsr访问指令

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

mrs&msr

mrs⽤来读psr,msr⽤来写psr

mrsr0,cpsr将cpsr读取到寄存器r0中

msrcpsr,r0将r0中的数读取到cpsr中。

cpsr和spsr的区别和联系:cpsr是程序状态寄存器,整个SoC中只有1个;⽽spsr有5个,分别在5种异常模式下,作⽤是当从普通模式进

⼊异常模式时,⽤来保存之前普通模式下的cpsr的,以在返回普通模式时恢复原来的cpsr。

、跳转指令b&bl&bx

b(branch)直接跳转(就没打算返回),与C语⾔的goto类似。

bl(branchandlink),跳转前把返回地址放⼊lr中,以便返回,以便⽤于函数调⽤。

bx跳转同时切换到ARM模式,⼀般⽤于异常处理的跳转。

、访存指令(访问内存)ldr/str&ldm/stm&swp

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

多字批量访问ldm/stm

swp同时读写

swpr1,r2,[r0]将r0所指向的内存中的值读取到r1中,同时将r2中的值写⼊到r0所指向的内存中。

swpr1,r1,[r0]将r0所指向的内存中的值读取到r1中,同时将r1之前的值写⼊到r0所指向的内存中。

、软中断指令(⽤软件模拟中断)(⽤于操作系统)

swi(softwareinterrupt)

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

、⽴即数

合法⽴即数与⾮法⽴即数

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

合法⽴即数:经过任意位数的移位后⾮零部分可以⽤8位表⽰的即为合法⽴即数

例如:

合法⽴即数:0x000000ff0x00ff00000xf000000f

⾮法⽴即数:0x000001ff

、什么是协处理器

SoC内部的另⼀个处理核⼼,协助主处理器CPU实现某些功能,被主处理器CPU调⽤执⾏⼀定任务。

协处理器是通过编号来区分的,在使⽤时只需要知道他的编号就可以操作。

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

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

、协处理器cp15操作指令mcr&mrc

、操作指令的作⽤

mrc⽤于读取CP15中的寄存器

mcr⽤于写⼊CP15中的寄存器

、操作指令的使⽤⽅法

mcr{}p15,,,,,{}

_1:对于cp15永远为0

:ARM的普通寄存器,不能是r15,否则结果未知

:cp15的寄存器,合法值是c0~c15

:cp15的寄存器,⼀般均设为c0

_2:⼀般省略或为0

例⼦:

mrcp15,0,r0,c1,c0,0

bicr0,r0,#0x00002000

bicr0,r0,#0x00000007

orrr0,r0,#0x00000002

orrr0,r0,#0x00000800

mcrp15,0,r0,c1,c0,0

与栈的处理

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

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

ldm(loadregistermutiple)

stm(storeregistermutiple)

、ldm/stm的8种后缀

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

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

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

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

fd(fulldecrea)满递减堆栈

ed(emptydecrea)空递减堆栈

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

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

举例

stmiasp,{r0-r12}

说明:

将r0存⼊sp指向的内存处(假设为0x30001000);然后地址+4(即指向0x30001004),将r1存⼊该地址;然后地址再+4(指

向0x30001008),将r2存⼊该地址······直到r12内容放⼊(0x3001030),指令完成。

⼀个访存周期同时完成13个寄存器的读写

、四种栈

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

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

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

减栈:栈指针移动时向地址减⼩的⽅向移动的栈

、!的作⽤

ldmiar0,{r2-r3}

ldmiar0!,{r2-r3}

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

、^的作⽤

ldmfdsp!,{r0-r6,pc}

ldmfdsp!,{r0-r6,pc}^

^的作⽤:在⽬标寄存器中有pc时,会同时将spsr写⼊到cpsr,⼀般⽤于从异常模式返回。

、总结

批量读取或写⼊内存时要⽤ldm/stm指令

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

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

ARM默认的是满减栈(stmfd)

、伪指令的意义

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

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

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

、gnu汇编中的⼀些符号

@⽤来做注释。可以在⾏⾸也可以在代码后⾯同⼀⾏直接跟,和C语⾔中//类似

:以冒号结尾的是标号

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

例⼦:死循环(相当于C语⾔中的while(1);)

flag:flag标号,表⽰⼀个地址

bflag跳转到flag本⾝

b.跳转到当前指令的地址(这⼀句相当于上边两⾏)

#⽴即数前⾯要加#或$,表⽰这是个⽴即数

、常见的gnu伪指令

.global_start@给_start外部链接属性,为了让别的⽂件中访问

.@指定当前段为代码段

.@⽤于定义数据,相当于C语⾔中定义变量

例⼦:

IRQ_STACK_START:

.word0x0badc0de

其中IRQ_STACK_START为变量名,.word为变量类型,0x0badc0de为变量的值。相当于unsignedintIRQ_STACK_START=

0x0badc0de。

.@定义数据(双字,⼩数,字符串)

.align4@以16字节对齐,2的4次⽅。

.align2@以4字节对齐,2的2次⽅

.balignl160xabcdefgh@16字节对齐填充

B表⽰位填充;align表⽰对齐;l表⽰long,以4字节为单位填充;16表⽰以16字节对齐;0xabcdefgh是⽤来填充的原料。

例⼦:

地址

l160xabcdefgh

0x0000000c0xabcdefgh

0x00000010下⼀条指令

说明:

0x00000008为原地址,运⾏.balignl160xabcdefgh伪指令后,需要16字节对齐,跳转到0x00000010,中间的地址0x0000000c

⽤0xabcdefgh填充。

.equ@类似于C中宏定义

、偶尔⽤到的gnu伪指令

.end@标识⽂件结束

.include@头⽂件包含

.arm/.code32@声明以下为arm指令

.thumb/.code16@声明以下为thubm指令

、最重要的伪指令

ldr⼤范围的地址加载指令(将地址加载到寄存器中)

adr⼩范围的地址加载指令(将地址加载到寄存器中)

adrl中等范围的地址加载指令(将地址加载到寄存器中)

nop空操作

注意:

ARM中有⼀个ldr指令,还有⼀个ldr伪指令。⼀般都使⽤ldr伪指令⽽不

⽤ldr指令。

如果是指令,⽴即数前边是#,如果是伪指令,⽴即数前边是=;涉及到合法/⾮法⽴即数,设计到ARM⽂字池。

例如:

ldr指令:ldrr0,#0xff需要编程⼈员考虑⽴即数是否合法

ldr伪指令:ldrr0,=0xff不⽤考虑⽴即数是否合法

、adr和ldr

adr编译时会被1条sub或add指令替代,⽽ldr编译时会被⼀条mov指令替代或者⽂字池⽅式处理;

adr总是以PC为基准来表⽰地址,因此指令本⾝和运⾏地址有关,可以⽤来检测程序当前的运⾏地址在哪⾥(相对寻址)

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

adr和ldr的差别:

ldr加载的地址在链接时确定,⽽adr加载的地址在运⾏时确定;所以我们可以通过adr和ldr加载的地址⽐较来判断当前程序是否在链接时指

定的地址运⾏。

本文发布于:2022-12-30 00:46:46,感谢您对本站的认可!

本文链接:http://www.wtabcd.cn/fanwen/fan/90/56458.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

上一篇:mangosoft
下一篇:绿蔷薇国语
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图