LDMIA、LDMIB、LDMDB、LDMDA、STMIA、LDMFD、LDMFA、LDMED、LDMEA等指令详解

关于多寄存器加载存储指令

1.LDMIA指令、LDMIB指令、LDMDB指令、LDMDA指令

(1)LDMIA指令,IA表示每次传送后地址加4

(2)LDMIB指令,每次传送前地址加四

(3)LDMDB指令,每次传送前地址减4,这里还要注意程序中先给R5,还是先给R8,这里明显是先给R8

(4)LDMDA指令,每次传送后地址减4,这里也是先给R8,不是先给R5!!

2.下面来看看STMIA指令、STMIB指令、STMDB指令、STMDA指令

(1)      STMIA指令, STMIA R0,{R1,R2,R3,R4}  ;将R1—R4的数据存储到R0指向的地址上,R0的值不更新,IA传送后地址加4,所以这里内存当中的地址是从0x8004开始变化的

(2)      STMIB指令, STMIB R0,{R1,R2,R3,R4}  ;将R1—R4的数据存储到R0指向的地址上,R0的值不更新,IB每次传送前地址加4,所以内存中的值是从0x8008开始变化的

(3)      STMDB指令, STMDB R0,{R1,R2,R3,R4}  ;将R1—R4的数据存储到R0指向的地址上,R0的值不更新,DB每次传送后地址减4,所以内存中的值是从0x8010开始递减变化的,注意这里是先把表达式中的R4先给地址0x8010

(4)      STMDA与上面STMDB指令类似,DA是每次传送后地址减4,我就不截图了。

下面看一下最TMD烦的的是堆栈寻址方式,依次讲解STMFD、STMED、STMFA、STMEA

1.      STM加载指令

(1)      STMFD意思是满堆栈递减指令,堆栈向下增长。如下图就是解释堆栈向下增长,向下增长,栈顶指针在内存中向低地址处移动,叫做向下增长,这里我为什么要先讲STMFD指令,怎么不讲LDMFD等指令呢,因为这里涉及到堆栈,向内存中写入寄存器中所存储的值,更能体现出进栈的动作,看完下面的例子,你会知道STM的后缀为什么是FD了。

关键代码:STMFDSP!,{R1-R3,R4},可以这么看,先把R4,R3,R2,R1依次压栈,至于为什么不是R1,R2,R3,R4依次压栈,因为做出的实验就不是这样的,所以R4准备进栈的时候,栈指针SP先减4,然后先把R4寄存器里面的值放到内存地址为0x803c里面,这里为什么SP要先减4呢,因为这里是满堆栈,所以要先把栈指针做出响应的变化以后,才能进行存储,至于什么是满堆栈和空堆栈,我这里就不解释了。程序效果看下图即可:

(2)      看了上面STMFD以后,现在看STMFA就很简单了:不过这里需要特别注意,这里并不是先操作R4寄存器的,而是操作R1寄存器,至于为什么,我也不知道,只是实验总结出来的,这种东西并没有什么规律可言,实验是怎么样就怎么样吧。同理的是,先把SP做相应的改变,也就是这里先SP+4=0x8044,然后把R1寄存器的值放到内存地址的0x8044处,然后R2,R3,R4依次放下去,最后改变SP的值,因为代码中多了一个感叹号STMFA SP!,{R1-R3,R4}

(3)      STMED是空递减堆栈,可以看出堆栈指针一开始指在0x8040处,所以先把R4的寄存器的值放到内存单元0x8040中,这里其实也是先操作R4寄存器,至于为什么,只能说和STMFD对应的。

(4)      STMEA空递增堆栈,这里我只贴图不说话,哈哈,看不懂,回家种田去

下面看看和STMFD指令相对应的LDMFD等指令,我依次讲解LDMFD、LDMFA、LDMED、LDMEA指令,至于我为什么按这种顺序讲,为了和上面的STMFD等指令联系在一起。

(1)      还记得我上面那些STM那些指令先将的是什么,对了,第一个讲的是STMFD指令,把内存中的数据批量放到寄存器中。FD为满递减堆栈。

这里值得注意的是,FD不是满堆栈递减吗,为什么程序执行完以后SP是增加的,在没有执行MOVR9, SP这条指令之前,FD确实代表是递减的意思,这里因为sp栈顶指针实际上是增加,至于为什么不写LDMFA,只不过这样LDMFD能和STMFD指令对应,看起来顺眼点吧,其实这里我要说明的是STMDB并不是和LDMDB对应,而是和LDMIA对应的,这里注意一下就行了,以后程序编多了,直接就记住了,不过你只要原理懂了,管它怎么写呢。

(2)      那自然地下面就讲LDMFA指令了:同理的嘛!!

(3)      LDMED指令:依葫芦画瓢

(4)      LDMEA指令:就不写了,吃饭去了!!!

最后注意的一点就是这里的SP指针是我假定的一个值,如果你以后写arm代码,调用C函数的时候,用到栈指针,系统会自动分配,就不存在sp是否非法的问题,什么是非法问题呢?先举个例子,看下图,这里对应的SP是0x8020,并且是满递减,把寄存器的值写到内存当中,我明明写的是STMFDSP!,{R1-R3,R4},把4个寄存器的内容写到内存中,可是最后就存了两个,因为你0x8018的地址处之前可能代码段的内容就存入在那里,所以你就不能改了,获取你这时候把这个不能写入的内存地址是可以读取到寄存器中的,我没试过,有兴趣可以试试。所以在用STM指令的时候要注意这点了!!

时间: 2024-10-12 10:11:54

LDMIA、LDMIB、LDMDB、LDMDA、STMIA、LDMFD、LDMFA、LDMED、LDMEA等指令详解的相关文章

汇编指令大全

blt   小于跳转 tst r0,#02 bne sleep ldr  r1,#0 解释:位比较,先进行and运算,如果r0第2位不为1,则与的结果为0,设置标志位zero=1,继续下面的ldr指令.反之,zero=0,跳转到sleep执行. bne指令: 非零则跳转 个人总结:tst 和bne连用: 先是用tst进行位与运算,然后将位与的结果与0比较,如果不为0,则跳到bne紧跟着的标记(如bne sleep,则跳到sleep处). tst 和beq连用: 先是用tst进行位与运算,然后将位

ARM汇编指令汇总

1.ARM汇编的格式:    在ARM汇编里,有些字符是用来标记行号的,这些字符要求顶格写:有些伪码是需要成对出现的,例如ENTRY和END,就需要对齐出现,也就是说他们要么都顶格,要么都空相等的空,否则编译器将报错.常量定义需要顶格书写,不然,编译器同样会报错.    2.字符串变量的值是一系列的字符,并且使用双引号作为分界符,如果要在字符串中使用双引号,则必须连续使用两个双引号.    3.在使用LDR时,当格式是LDR r0,=0x022248,则第二个参数表示地址,即0x022248,同

ARM指令集的概述

ADC  addition Carry 带进位的加法指令   数据处理类算术运算指令 ADD addition 加法指令 数据处理类算术运算指令 AND logic and 逻辑与 数据处理类算术运算指令 B Branch B 是最简单的分支.一旦遇到一个 B 指令,ARM 处理器将立即跳转到给定的地址,从那里继续执行.注意存储在分支指令中的实际的值是相对当前的 R15 的值的一个偏移量:而不是一个绝对地址.它的值由汇编器来计算,它是 24 位有符号数,左移两位后有符号扩展为 32 位,表示的有

[基于Android的ARM汇编语言系列]之四:ARM处理器的寻址方式

作者:郭嘉 邮箱:[email protected] 博客:http://blog.csdn.net/allenwells github:https://github.com/AllenWell 处理器的寻址方式是通过指令给出的地址码字段来寻找真实操作数地址的方式,ARM处理器支持9中寻址方式. 一 立即寻址 立即寻址指令后面的地址码部分为立即数(常量或常数),立即寻址多用于给寄存器赋值. 举例 MOV RO, #1234 指令执行后,R0=1234. 二 寄存器寻址 寄存器寻址中,操作数在寄存

linux-2.6.26内核中ARM中断实现详解(转)

转载:http://www.cnblogs.com/leaven/archive/2010/08/06/1794293.html 更多文档参见:http://pan.baidu.com/s/1dDvJRaD 作者:刘洪涛,华清远见嵌入式学院金牌讲师,ARM ATC授权培训讲师. 看了一些网络上关于linux中断实现的文章,感觉有一些写的非常好,在这里首先感谢他们的无私付出,然后也想再补充自己对一些问题的理解.先从函数注册引出问题吧. 一.中断注册方法 在linux内核中用于申请中断的函数是req

Linux内核源码分析--内核启动之(1)zImage自解压过程(Linux-3.0 ARMv7) 【转】

转自:http://blog.chinaunix.net/uid-25909619-id-4938388.html 研究内核源码和内核运行原理的时候,很总要的一点是要了解内核的初始情况,也就是要了解内核启动过程.我在研究内核的内存管理的时候,想知道内核启动后的页表的放置,页表的初始化等信息,这促使我这次仔细地研究内核的启动代码. CPU在bootloader的帮助下将内核载入到了内存中,并开始执行.当然,bootloader必须为zImage做好必要的准备:  1. CPU 寄存器的设置: R0

【转】Android kernel启动流程

;font-family:Arial, Console, Verdana, 'Courier New';line-height:normal;white-space:normal;background-color:#FFFFFF;"> linuxandroidmakefileimagecachealignment 虽然这里的Arm Linux kernel前面加上了Android,但实际上还是和普遍Arm linux kernel启动的过程一样的,这里只是结合一下Android的Makef

ARM体系结构和汇编指令

第一节 可编程器件的编程原理 1. 可编程器件的特点 1 . CPU在固定频率的时钟控制下节奏运行 2 . CPU可以通过总线读取外部存储设备中的二进制指令集,然后解码执行 3 . 这些可以被CPU解码执行的二进制指令集是CPU设计的时候确定的,是CPU的设计者(ARM公司)定义的,本质上是一串由1和0组成的数字.这就是CPU的汇编指令集 2. 从源代码到cpu执行过程 第二节 指令集对cpu的意义 1. 汇编语言与C等高级语言的差异 汇编无移植性,c语言有一定可移植性,jave等更高级的语言移

Android逆向之旅---动态方式破解apk进阶篇(IDA调试so源码)

一.前言 今天我们继续来看破解apk的相关知识,在前一篇:Eclipse动态调试smali源码破解apk 我们今天主要来看如何使用IDA来调试Android中的native源码,因为现在一些app,为了安全或者效率问题,会把一些重要的功能放到native层,那么这样一来,我们前篇说到的Eclipse调试smali源码就显得很无力了,因为核心的都在native层,Android中一般native层使用的是so库文件,所以我们这篇就来介绍如何调试so文件的内容,从而让我们破解成功率达到更高的一层.