当前位置: 首页 > news >正文

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

LOAD/STORE MULTIPLE         

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

.dataarray_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 lrwords:.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, #3mov r1, #4push {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-littlearmDisassembly of section .text:00008054 <_start>:8054: e3a00003 mov r0, #38058: e3a01004 mov r1, #4805c: 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:

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

LOAD/STORE MULTIPLE 有时一次加载&#xff08;或存储&#xff09;多个值更有效。为此&#xff0c;我们使用LDM&#xff08;加载多个&#xff09;和STM&#xff08;存储多个&#xff09;。这些指令有一些变化&#xff0c;基本上只在访问初始地址的方式上有所不同。这是…...

Python之Qt输出UI

安装PySide2 输入pip install PySide2安装Qt for Python&#xff0c;如果安装过慢需要翻墙&#xff0c;则可以使用国内清华镜像下载&#xff0c;输入命令pip install --user -i https://pypi.tuna.tsinghua.edu.cn/simple PySide2&#xff0c;如下图&#xff0c; 示例Demo i…...

【1day】复现泛微OA某版本SQL注入漏洞

目录 一、漏洞描述 二、影响版本 三、资产测绘 四、漏洞复现 一、漏洞描述 泛微e-cology是一款由泛微网络科技开发的协同管理平台,支持人力资源、财务、行政等多功能管理和移动办公。泛微OA存在SQL注入漏洞,攻击者利用Web应用程序对用户输入验证上的疏忽,在输入的数据…...

安卓系列机型-禁止卸载某个APP 防止误卸载软件 无需root权限

安卓系列机型-禁止安装某软件 防止“沉迷游戏的小孩”操作解析_安卓机器的博客-CSDN博客 上一期讲了如何禁止安装某个app。今天讲下如何禁止卸载某app。正好相反的操作。任何操作有利有弊。主要看使用者如何对待使用。 &#x1f494;&#x1f494;&#x1f494;以腾讯的一款游…...

【算法系列篇】二分查找——这还是你所知道的二分查找算法吗?

文章目录 前言什么是二分查找算法1.二分查找1.1 题目要求1.2 做题思路1.3 Java代码实现 2.在排序数组中查找元素的第一个和最后一个位置2.1 题目要求2.2 做题思路2.3 Java代码实现 3.搜索插入位置3.1 题目要求3.2 做题思路3.3 Java代码实现 4.x的平方根4.1 题目要求4.2 做题思路…...

【前端从0开始】JavaSript——分支流程控制

流程控制 在任何一门程序设计语言中&#xff0c;都需要支持满足程序结构 化所需要的三种流程控制: ●顺序控制 ●分支控制&#xff08;条件控制&#xff09; ●循环控制 顺序控制&#xff1a;在程序流程控制中&#xff0c;最基本的就是顺序控制。程序会按照自上而下的顺序执行…...

Linux权限

Linux中一切皆文件&#xff0c;那么文件就应该有相对于的类型&#xff0c;而在Linux当中&#xff0c;类型不是直接看后缀来决定的。 -普通文件、文本、可执行、归档文件等d目录b块设备、block、磁盘c字符设备、键盘、显示器p管道文件s网络socket文件l链接文件 link 然后后面的九…...

PMP如何备考?学习方式这里有

预习阶段&#xff1a;强烈建议跟着习课视频学习&#xff08;自己看书真的很难看懂&#xff09;&#xff0c;初步了解PMBOK&#xff0c;有个大致印象&#xff1b; 精讲阶段&#xff1a;这个时候就需要静下心来深入了解各个知识模块&#xff0c;不仅是看PMBOK&#xff0c;还要尽…...

【Java转Go】快速上手学习笔记(四)之基础篇三

目录 泛型内置泛型的使用切片泛型和泛型函数map泛型泛型约束泛型完整代码 接口反射协程特点WaitGroupgoroutine的调度模型&#xff1a;MPG模型 channel介绍语法&#xff1a;举例&#xff1a;channel遍历基本使用和协程一起使用案例一案例二 select...casemain.go 完整代码 文件…...

vue中form和table标签过长

form标签过长 效果&#xff1a; 代码&#xff1a; <el-form-item v-for"(item,index) in ticketEditTable1" :label"item.fieldNameCn" :propitem.fieldName :key"item.fieldNameCn" overflow"":rules"form[item.fieldName…...

java基础复习(第七日)

java基础复习(七) 1.MQ如何避免消息重复投递或重复消费&#xff1f; 在消息生产时&#xff0c;MQ 内部针对每条生产者发送到消息生成一个 inner-msg-id&#xff0c;作为去重的依据&#xff08;消息投递失败并重传&#xff09;&#xff0c;避免重复的消息进入队列&#xff1b;…...

day24 | 理论基础、77. 组合

目录&#xff1a; 解题及思路学习 理论基础 回溯的本质是穷举&#xff0c;穷举所有可能&#xff0c;然后选出我们想要的答案&#xff0c;如果想让回溯法高效一些&#xff0c;可以加一些剪枝的操作&#xff0c;但也改不了回溯法就是穷举的本质。 回溯法&#xff0c;一般可以…...

数据结构(1)

数据结构其实就是将数据按照一定的关系组织起来的集合&#xff0c;用于组织和存储数据。 1.数据结构分类 1.逻辑结构 逻辑结构是从具体问题中抽象出来的模型&#xff0c;是抽象意义的结构&#xff0c;按照对象中数据的相互关系进行分类。 1>集合结构&#xff1a;集合结构中…...

10个非常有用的Python库,你知道几个?

整理&#xff5c;TesterHome 这里给大家介绍10个不是最流行但非常有用的Python库&#xff0c;希望可以提供参考帮助。 PyO3 PyO3是一个Rust库&#xff0c;可以让你在Rust中编写Python模块。它可以利用 Rust 的速度和安全性编写高性能的 Python 模块。 https://github.com/PyO3…...

linux安装 MySQL8 并配置开机自启动

目录 1.下载 mysql 安装包 2.上传并解压 mysql 3.修改 mysql 文件夹名 4.创建mysql 用户和用户组 5.数据目录 &#xff08;1&#xff09;创建目录 &#xff08;2&#xff09;赋予权限 6.初始化mysql &#xff08;1&#xff09;配置参数 &#xff08;2&#xff09;配置环…...

MySQL视图

一、视图-介绍及基本语法 视图&#xff08;View&#xff09;是一种虚拟存在的表。视图中的数据并不在数据库中实际存在&#xff0c;行和列数据来自定义视图的查询中使用的表&#xff0c;并且是在使用视图时动态生成的。 通俗的讲&#xff0c;视图只保存了查询的SQL逻辑&#xf…...

Pytorch-day05-可视化-checkpoint

PyTorch 可视化 1、模型结构可视化2、训练过程可视化3、模型评估可视化 #导入常用包 import os import numpy as np import torch from torch import nn from torch.utils.data import Dataset, DataLoader from torchvision.transforms import transforms import torchvis…...

实训笔记8.23

8.23笔记 8.23笔记一、Hive中函数1.1 Hive中内置函数1.1.1 数学函数1.1.2 字符串函数1.1.3 日期函数1.1.4 条件函数1.1.5 特殊函数 1.2 Hive的自定义函数1.2.1 自定义UDF1.2.2 自定义UDTF 二、Hive的压缩机制三、数据同步工具Sqoop的安装和使用3.1 sqoop的概念3.2 sqoop的核心功…...

2023年菏泽市中职学校技能大赛“网络安全”赛项规程

2023年菏泽市中职学校技能大赛 “网络安全”赛项规程 一、赛项名称 赛项名称&#xff1a;网络安全 赛项所属专业大类&#xff1a;信息技术类 二、竞赛目的 通过竞赛&#xff0c;检验参赛选手对网络、服务器系统等网络空间中各个信息系统的安全防护能力&#xff0c;以及分析…...

Android 13 - Media框架(6)- NuPlayer

上一节我们通过 NuPlayerDriver 了解了 NuPlayer 的使用方式&#xff0c;这一节我们一起来学习 NuPlayer 的部分实现细节。 ps&#xff1a;之前用 NuPlayer 播放本地视频很多都无法播放&#xff0c;所以觉得它不太行&#xff0c;这两天重新阅读发现它的功能其实很全面&#xff…...

基于算法竞赛的c++编程(28)结构体的进阶应用

结构体的嵌套与复杂数据组织 在C中&#xff0c;结构体可以嵌套使用&#xff0c;形成更复杂的数据结构。例如&#xff0c;可以通过嵌套结构体描述多层级数据关系&#xff1a; struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...

突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合

强化学习&#xff08;Reinforcement Learning, RL&#xff09;是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程&#xff0c;然后使用强化学习的Actor-Critic机制&#xff08;中文译作“知行互动”机制&#xff09;&#xff0c;逐步迭代求解…...

3.3.1_1 检错编码(奇偶校验码)

从这节课开始&#xff0c;我们会探讨数据链路层的差错控制功能&#xff0c;差错控制功能的主要目标是要发现并且解决一个帧内部的位错误&#xff0c;我们需要使用特殊的编码技术去发现帧内部的位错误&#xff0c;当我们发现位错误之后&#xff0c;通常来说有两种解决方案。第一…...

循环冗余码校验CRC码 算法步骤+详细实例计算

通信过程&#xff1a;&#xff08;白话解释&#xff09; 我们将原始待发送的消息称为 M M M&#xff0c;依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)&#xff08;意思就是 G &#xff08; x ) G&#xff08;x) G&#xff08;x) 是已知的&#xff09;&#xff0…...

SCAU期末笔记 - 数据分析与数据挖掘题库解析

这门怎么题库答案不全啊日 来简单学一下子来 一、选择题&#xff08;可多选&#xff09; 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘&#xff1a;专注于发现数据中…...

前端导出带有合并单元格的列表

// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...

令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍

文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结&#xff1a; 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析&#xff1a; 实际业务去理解体会统一注…...

【HTTP三个基础问题】

面试官您好&#xff01;HTTP是超文本传输协议&#xff0c;是互联网上客户端和服务器之间传输超文本数据&#xff08;比如文字、图片、音频、视频等&#xff09;的核心协议&#xff0c;当前互联网应用最广泛的版本是HTTP1.1&#xff0c;它基于经典的C/S模型&#xff0c;也就是客…...

2025季度云服务器排行榜

在全球云服务器市场&#xff0c;各厂商的排名和地位并非一成不变&#xff0c;而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势&#xff0c;对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析&#xff1a; 一、全球“三巨头”…...

JAVA后端开发——多租户

数据隔离是多租户系统中的核心概念&#xff0c;确保一个租户&#xff08;在这个系统中可能是一个公司或一个独立的客户&#xff09;的数据对其他租户是不可见的。在 RuoYi 框架&#xff08;您当前项目所使用的基础框架&#xff09;中&#xff0c;这通常是通过在数据表中增加一个…...