ARM汇编【3】:LOAD/STORE MULTIPLE PUSH AND POP

这篇具有很好参考价值的文章主要介绍了ARM汇编【3】:LOAD/STORE MULTIPLE PUSH AND POP。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

LOAD/STORE MULTIPLE         

      有时一次加载(或存储)多个值更有效。为此,我们使用LDM(加载多个)和STM(存储多个)。这些指令有一些变化,基本上只在访问初始地址的方式上有所不同。这是我们将在本节中使用的代码。我们将一步一步地研究每一条指令。

.data

array_buff:
 .word 0x00000000             /* array_buff[0] */
 .word 0x00000000             /* array_buff[1] */
 .word 0x00000000             /* array_buff[2]. This element has a relative address of array_buff+8 */
 .word 0x00000000             /* array_buff[3] */
 .word 0x00000000             /* array_buff[4] */

.text
.global _start

_start:
 adr r0, words+12             /* address of words[3] -> r0 */
 ldr r1, array_buff_bridge    /* address of array_buff[0] -> r1 */
 ldr r2, array_buff_bridge+4  /* address of array_buff[2] -> r2 */
 ldm r0, {r4,r5}              /* words[3] -> r4 = 0x03; words[4] -> r5 = 0x04 */
 stm r1, {r4,r5}              /* r4 -> array_buff[0] = 0x03; r5 -> array_buff[1] = 0x04 */
 ldmia r0, {r4-r6}            /* words[3] -> r4 = 0x03, words[4] -> r5 = 0x04; words[5] -> r6 = 0x05; */
 stmia r1, {r4-r6}            /* r4 -> array_buff[0] = 0x03; r5 -> array_buff[1] = 0x04; r6 -> array_buff[2] = 0x05 */
 ldmib r0, {r4-r6}            /* words[4] -> r4 = 0x04; words[5] -> r5 = 0x05; words[6] -> r6 = 0x06 */
 stmib r1, {r4-r6}            /* r4 -> array_buff[1] = 0x04; r5 -> array_buff[2] = 0x05; r6 -> array_buff[3] = 0x06 */
 ldmda r0, {r4-r6}            /* words[3] -> r6 = 0x03; words[2] -> r5 = 0x02; words[1] -> r4 = 0x01 */
 ldmdb r0, {r4-r6}            /* words[2] -> r6 = 0x02; words[1] -> r5 = 0x01; words[0] -> r4 = 0x00 */
 stmda r2, {r4-r6}            /* r6 -> array_buff[2] = 0x02; r5 -> array_buff[1] = 0x01; r4 -> array_buff[0] = 0x00 */
 stmdb r2, {r4-r5}            /* r5 -> array_buff[1] = 0x01; r4 -> array_buff[0] = 0x00; */
 bx lr

words:
 .word 0x00000000             /* words[0] */
 .word 0x00000001             /* words[1] */
 .word 0x00000002             /* words[2] */
 .word 0x00000003             /* words[3] */
 .word 0x00000004             /* words[4] */
 .word 0x00000005             /* words[5] */
 .word 0x00000006             /* words[6] */

array_buff_bridge:
 .word array_buff             /* address of array_buff, or in other words - array_buff[0] */
 .word array_buff+8           /* address of array_buff[2] */

        在开始之前,请记住.字指的是32位=4字节的数据(内存)块。这对于理解抵消非常重要。因此,该程序由.data部分组成,我们在其中分配一个包含5个元素的空数组(array_buff)。我们将使用它作为存储数据的可写内存位置。.text部分包含我们的代码以及内存操作指令和一个只读数据池,其中包含两个标签:一个用于具有7个元素的数组,另一个用于“桥接”.text和.data部分,以便我们可以访问.data部分中的array_buff。

adr r0, words+12             /* address of words[3] -> r0 */

      我们使用ADR指令(惰性方法)将第4个(单词[3])元素的地址获取到R0中。我们指向单词数组的中间,因为我们将从那里向前和向后操作。

gef> break _start 
gef> run
gef> nexti

      R0现在包含字[3]的地址,在本例中为0x80B8。这意味着,我们的数组从字[0]的地址开始:0x80AC(0x80B8–0xC)。

gef> x/7w 0x00080AC
0x80ac <words>: 0x00000000 0x00000001 0x00000002 0x00000003
0x80bc <words+16>: 0x00000004 0x00000005 0x00000006

      我们用array_buff数组的第一个(array_buff[0])和第三个(array_buff[2])元素的地址来准备R1和R2。一旦获得地址,我们就可以开始对其进行操作。

ldr r1, array_buff_bridge    /* address of array_buff[0] -> r1 */
ldr r2, array_buff_bridge+4  /* address of array_buff[2] -> r2 */

    在执行上述两条指令后,R1和R2包含array_buff[0]和array_bufp[2]的地址。

gef> info register r1 r2
r1      0x100d0     65744
r2      0x100d8     65752

      下一条指令使用LDM从R0指向的内存中加载两个字值。因此,因为我们早些时候让R0指向单词[3]元素,单词[3]值变为R4,单词[4]值变为R5。

ldm r0, {r4,r5}              /* words[3] -> r4 = 0x03; words[4] -> r5 = 0x04 */

    我们用一个命令加载了多个(2个数据块),该命令设置R4=0x00000003和R5=0x00000004。

gef> info registers r4 r5
r4      0x3      3
r5      0x4      4

   到目前为止还不错。现在让我们执行STM指令,将多个值存储到内存中。我们代码中的STM指令从寄存器R4和R5获取值(0x3和0x4),并将这些值存储到R1指定的内存位置。我们之前将R1设置为指向第一个array_buff元素,因此在该操作之后,array_buff[0]=0x00000003,array_baff[1]=0x00000004。如果未另行指定,LDM和STM在字的一个步长上运算(32位=4字节)。

stm r1, {r4,r5}              /* r4 -> array_buff[0] = 0x03; r5 -> array_buff[1] = 0x04 */

     值0x3和0x4现在应该存储在存储器地址0x100D0和0x100D4处。以下指令检查地址0x000100D0处的两个存储器字。

gef> x/2w 0x000100D0
0x100d0 <array_buff>:  0x3   0x4

       如前所述,LDM和STM有变化。变体的类型由指令的后缀定义。示例中使用的后缀为:-IA(在之后增加)、-IB(在之前增加)、-DA(在后面减少)、-DB(在前面减少)。这些变体访问第一个操作数指定的内存(存储源或目标地址的寄存器)的方式不同。在实践中,LDM与LDMIA相同,这意味着要加载的下一个元素的地址在每次加载后都会增加。通过这种方式,我们从第一个操作数指定的内存地址(存储源地址的寄存器)获得顺序(正向)数据加载。

ldmia r0, {r4-r6} /* words[3] -> r4 = 0x03, words[4] -> r5 = 0x04; words[5] -> r6 = 0x05; */ 
stmia r1, {r4-r6} /* r4 -> array_buff[0] = 0x03; r5 -> array_buff[1] = 0x04; r6 -> array_buff[2] = 0x05 */

   在执行上述两条指令之后,寄存器R4-R6和存储器地址0x000100D0、0x000100D4和0x000100D8包含值0x3、0x4和0x5。

gef> x/3w 0x100D4
0x100d4 <array_buff+4>: 0x00000004  0x00000005  0x00000006
gef> info register r4 r5 r6
r4     0x4    4
r5     0x5    5
r6     0x6    6

          当我们使用LDMDA指令时,一切都开始向后操作。R0指向单词[3]。当加载开始时,我们向后移动,并将单词[3]、单词[2]和单词[1]加载到R6、R5、R4中。是的,寄存器也是向后加载的。因此,在指令完成后,R6=0x00000003,R5=0x00000002,R4=0x00000001。这里的逻辑是我们向后移动,因为我们在每次加载后递减源地址。发生反向注册表加载是因为每次加载时,我们都会减少内存地址,从而减少注册表编号,以跟上内存地址越高,注册表编号越高的逻辑。查看LDMIA(或LDM)示例,我们首先加载较低的注册表,因为源地址较低,然后加载较高的注册表,原因是源地址增加。

加载倍数,在以下时间后递减:

ldmda r0, {r4-r6} /* words[3] -> r6 = 0x03; words[2] -> r5 = 0x02; words[1] -> r4 = 0x01 */

执行后的寄存器R4、R5和R6:

gef> info register r4 r5 r6
r4     0x1    1
r5     0x2    2
r6     0x3    3

存储倍数,之后递减。

stmda r2, {r4-r6} /* r6 -> array_buff[2] = 0x02; r5 -> array_buff[1] = 0x01; r4 -> array_buff[0] = 0x00 */

array_buff[2]、array_buff[1]、array_bbuff[0]执行后的内存地址:

gef> x/3w 0x100D0
0x100d0 <array_buff>: 0x00000000 0x00000001 0x00000002

存储倍数,递减之前:

stmdb r2, {r4-r5} /* r5 -> array_buff[1] = 0x01; r4 -> array_buff[0] = 0x00; */

array_buff[1]和array_bufp[0]执行后的内存地址:

gef> x/2w 0x100D0
0x100d0 <array_buff>: 0x00000000 0x00000001

PUSH AND POP

     进程中有一个名为Stack的内存位置。堆栈指针(SP)是一个寄存器,在正常情况下,它总是指向堆栈内存区域中的地址。应用程序经常使用Stack进行临时数据存储。如前所述,ARM使用加载/存储模型进行内存访问,这意味着指令LDR/STR或其衍生物(LDM../STM..)用于内存操作。在x86中,我们使用PUSH和POP从堆栈加载和存储。在ARM中,我们也可以使用以下两条指令:

当我们把一些东西推到Full Descending(第7部分:堆栈和函数中关于堆栈差异的更多信息)堆栈上时,会发生以下情况:

  • 首先,SP中的地址减少4。
  • 其次,信息被存储到SP指向的新地址

当我们从堆栈中弹出某个东西时,会发生以下情况:

  •   当前SP地址处的值被加载到某个寄存器中,
  •   SP中的地址增加4。

在以下示例中,我们同时使用PUSH/POP和LDMIA/STMDB:

.text
.global _start

_start:
   mov r0, #3
   mov r1, #4
   push {r0, r1}
   pop {r2, r3}
   stmdb sp!, {r0, r1}
   ldmia sp!, {r4, r5}
   bkpt

让我们来看看这个代码的反汇编。

azeria@labs:~$ as pushpop.s -o pushpop.o
azeria@labs:~$ ld pushpop.o -o pushpop
azeria@labs:~$ objdump -D pushpop
pushpop: file format elf32-littlearm

Disassembly of section .text:

00008054 <_start>:
 8054: e3a00003 mov r0, #3
 8058: e3a01004 mov r1, #4
 805c: e92d0003 push {r0, r1}
 8060: e8bd000c pop {r2, r3}
 8064: e92d0003 push {r0, r1}
 8068: e8bd0030 pop {r4, r5}
 806c: e1200070 bkpt 0x0000

    正如您所看到的,我们的LDMIA和STMDB指令被转换为PUSH和POP。这是因为PUSH是STMDB-sp!的同义词!,reglist和POP是LDMIA sp的同义词!reglist(请参阅ARM手册)

让我们在GDB中运行此代码。

gef> break _start
gef> run
gef> nexti 2
[...]
gef> x/w $sp
0xbefff7e0: 0x00000001

  运行前两条指令后,我们快速检查了SP指向的内存地址和值。下一条PUSH指令应将SP减少8,并将R1和R0的值(按顺序)存储到堆栈中。

gef> nexti
[...] ----- Stack -----
0xbefff7d8|+0x00: 0x3 <- $sp
0xbefff7dc|+0x04: 0x4
0xbefff7e0|+0x08: 0x1
[...] 
gef> x/w $sp
0xbefff7d8: 0x00000003

   接下来,这两个值(0x3和0x4)从堆栈弹出到寄存器中,使得R2=0x3和R3=0x4。SP增加8:文章来源地址https://www.toymoban.com/news/detail-668534.html

gef> nexti
gef> info register r2 r3
r2     0x3    3
r3     0x4    4
gef> x/w $sp
0xbefff7e0: 0x00000001

到了这里,关于ARM汇编【3】:LOAD/STORE MULTIPLE PUSH AND POP的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • hadoop之kerberos权限配置(ranger基础上)(三)

    hadoop之kerberos权限配置(ranger基础上)(三)

    上传kerberos安装包到/opt/rpm 安装:rpm -Uvh --force --nodeps *.rpm 修改配置:vi /var/kerberos/krb5kdc/kdc.conf 修改配置:vi /etc/krb5.conf 初始化数据库:/usr/sbin/kdb5_util create -s -r HADOOP.COM。密码设为:ffcsict1234!#% 查看生成文件:cd /var/kerberos/krb5kdc -- ls 创建数据库管理员:/usr/sbin/kadmin.local -q “

    2024年02月08日
    浏览(10)
  • 轻松打造完美客户服务系统,这4个关键点不容错过

    轻松打造完美客户服务系统,这4个关键点不容错过

      客户服务对于一个企业来说非常重要,有以下几个原因: 1、建立客户忠诚度:通过提供高质量的客户服务,可以增加客户满意度和忠诚度。这将有助于企业保持竞争优势并吸引新客户。 2、提高客户满意度:客户对企业的服务感到满意时,他们更有可能再次购买或推荐给朋

    2024年02月04日
    浏览(13)
  • 电脑数据丢失怎么办?5 种免费数据恢复软件能帮到您

    电脑数据丢失怎么办?5 种免费数据恢复软件能帮到您

    我们存储在计算机中的个人和专业数据如果丢失,可能会给我们带来经济和精神上的困扰。有许多情况会导致此类数据丢失;其中一些包括意外删除、硬盘驱动器故障、软件崩溃、病毒攻击等。 5 种最佳免费数据恢复软件 为防止此类事故,建议定期备份计算机上的数据。您可

    2024年02月22日
    浏览(15)
  • windows环境下实现ffmpeg本地视频进行rtsp推流

    windows环境下实现ffmpeg本地视频进行rtsp推流

    摘要:有时候服务端(如linux)或者边缘端(jetson盒子)需要接受摄像头的视频流输入,而摄像头的输入视频流一般为rtsp,测试时需要搭建摄像头环境,很不方便,因此需要对本地视频进行rtsp推流,模拟摄像头的rtsp输入。 本地使用windows10, 64位 rtsp下载地址:https://github.com

    2024年04月13日
    浏览(10)
  • 腾讯云网站备案流程步骤、备案审核通过时间详细说明

    腾讯云网站备案流程步骤、备案审核通过时间详细说明

    腾讯云网站备案流程先填写基础信息、主体信息和网站信息,然后提交备案后等待腾讯云初审,初审通过后进行短信核验,最后等待各省管局审核 ,前面腾讯云初审时间1到2天左右,最长时间是等待管局审核时间,网站备案地区不同管局审核时间也不同,快的3天即可通过审核

    2024年02月03日
    浏览(15)
  • lua学习笔记21完结篇(lua中的垃圾回收)

    lua学习笔记21完结篇(lua中的垃圾回收)

    输出 学习地址  【唐老狮】Unity热更新之Lua语法_哔哩哔哩_bilibili 

    2024年04月15日
    浏览(28)
  • Vue中的MVVM【第三篇】

    Vue中的MVVM【第三篇】

            MVVM图示  🌈 一、MVVM简介          简单来说: MVVM(M-VM-M) ,一种更好的UI模式解决方案,MVVM通过数 据双向绑定 让数据 自动地双向同步。 M(Model):Model数据模型,json格式数据 V(View):View视图,jsp、html VM(ViewModel):ViewModel视图模型   🌈 二、MVVM详解        我以

    2024年02月04日
    浏览(14)
  • SpringBoot API 接口防刷

    SpringBoot API 接口防刷

    接口防刷: 顾名思义,想让某个接口某个人在某段时间内只能请求N次。 在项目中比较常见的问题也有,那就是连点按钮导致请求多次,以前在web端有表单重复提交,可以通过token来解决。 除了上面的方法外,前后端配合的方法。现在全部由后端来控制。 在你请求的时候,服

    2023年04月18日
    浏览(8)
  • Spark On Hive配置测试及分布式SQL ThriftServer配置

    Spark On Hive配置测试及分布式SQL ThriftServer配置

    Spark本身是一个执行引擎,而没有管理metadate的能力,当我们在执行SQL的时候只能将SQL转化为RDD提交。而对于一些数据中的元数据Spark并不知道,而Spark能写SQL主要是通过DataFrame进行注册的。 这时候我们就可以借助Hive中的MetaStore进行元数据管理。也就是说把Hive中的metastore服务

    2024年01月21日
    浏览(11)
  • SQL - 将查询结果插入到另一张表中

    注意:字段必须一致(位置一致,类型一致),否则会出现数据转换错误。 例如,要将 test 表插入到 newTest 表中,则可以通过如下SQL语句实现: 使用场景: 从一个表中选取数据,然后把数据插入另一个表中。常用于创建表的备份复件或者用于对记录进行存档。

    2024年02月16日
    浏览(10)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包