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 有时一次加载(或存储)多个值更有效。为此,我们使用LDM(加载多个)和STM(存储多个)。这些指令有一些变化,基本上只在访问初始地址的方式上有所不同。这是…...
Python之Qt输出UI
安装PySide2 输入pip install PySide2安装Qt for Python,如果安装过慢需要翻墙,则可以使用国内清华镜像下载,输入命令pip install --user -i https://pypi.tuna.tsinghua.edu.cn/simple PySide2,如下图, 示例Demo i…...
【1day】复现泛微OA某版本SQL注入漏洞
目录 一、漏洞描述 二、影响版本 三、资产测绘 四、漏洞复现 一、漏洞描述 泛微e-cology是一款由泛微网络科技开发的协同管理平台,支持人力资源、财务、行政等多功能管理和移动办公。泛微OA存在SQL注入漏洞,攻击者利用Web应用程序对用户输入验证上的疏忽,在输入的数据…...
安卓系列机型-禁止卸载某个APP 防止误卸载软件 无需root权限
安卓系列机型-禁止安装某软件 防止“沉迷游戏的小孩”操作解析_安卓机器的博客-CSDN博客 上一期讲了如何禁止安装某个app。今天讲下如何禁止卸载某app。正好相反的操作。任何操作有利有弊。主要看使用者如何对待使用。 💔💔💔以腾讯的一款游…...
【算法系列篇】二分查找——这还是你所知道的二分查找算法吗?
文章目录 前言什么是二分查找算法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——分支流程控制
流程控制 在任何一门程序设计语言中,都需要支持满足程序结构 化所需要的三种流程控制: ●顺序控制 ●分支控制(条件控制) ●循环控制 顺序控制:在程序流程控制中,最基本的就是顺序控制。程序会按照自上而下的顺序执行…...
Linux权限
Linux中一切皆文件,那么文件就应该有相对于的类型,而在Linux当中,类型不是直接看后缀来决定的。 -普通文件、文本、可执行、归档文件等d目录b块设备、block、磁盘c字符设备、键盘、显示器p管道文件s网络socket文件l链接文件 link 然后后面的九…...
PMP如何备考?学习方式这里有
预习阶段:强烈建议跟着习课视频学习(自己看书真的很难看懂),初步了解PMBOK,有个大致印象; 精讲阶段:这个时候就需要静下心来深入了解各个知识模块,不仅是看PMBOK,还要尽…...
【Java转Go】快速上手学习笔记(四)之基础篇三
目录 泛型内置泛型的使用切片泛型和泛型函数map泛型泛型约束泛型完整代码 接口反射协程特点WaitGroupgoroutine的调度模型:MPG模型 channel介绍语法:举例:channel遍历基本使用和协程一起使用案例一案例二 select...casemain.go 完整代码 文件…...
vue中form和table标签过长
form标签过长 效果: 代码: <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如何避免消息重复投递或重复消费? 在消息生产时,MQ 内部针对每条生产者发送到消息生成一个 inner-msg-id,作为去重的依据(消息投递失败并重传),避免重复的消息进入队列;…...
day24 | 理论基础、77. 组合
目录: 解题及思路学习 理论基础 回溯的本质是穷举,穷举所有可能,然后选出我们想要的答案,如果想让回溯法高效一些,可以加一些剪枝的操作,但也改不了回溯法就是穷举的本质。 回溯法,一般可以…...
数据结构(1)
数据结构其实就是将数据按照一定的关系组织起来的集合,用于组织和存储数据。 1.数据结构分类 1.逻辑结构 逻辑结构是从具体问题中抽象出来的模型,是抽象意义的结构,按照对象中数据的相互关系进行分类。 1>集合结构:集合结构中…...
10个非常有用的Python库,你知道几个?
整理|TesterHome 这里给大家介绍10个不是最流行但非常有用的Python库,希望可以提供参考帮助。 PyO3 PyO3是一个Rust库,可以让你在Rust中编写Python模块。它可以利用 Rust 的速度和安全性编写高性能的 Python 模块。 https://github.com/PyO3…...
linux安装 MySQL8 并配置开机自启动
目录 1.下载 mysql 安装包 2.上传并解压 mysql 3.修改 mysql 文件夹名 4.创建mysql 用户和用户组 5.数据目录 (1)创建目录 (2)赋予权限 6.初始化mysql (1)配置参数 (2)配置环…...
MySQL视图
一、视图-介绍及基本语法 视图(View)是一种虚拟存在的表。视图中的数据并不在数据库中实际存在,行和列数据来自定义视图的查询中使用的表,并且是在使用视图时动态生成的。 通俗的讲,视图只保存了查询的SQL逻辑…...
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年菏泽市中职学校技能大赛 “网络安全”赛项规程 一、赛项名称 赛项名称:网络安全 赛项所属专业大类:信息技术类 二、竞赛目的 通过竞赛,检验参赛选手对网络、服务器系统等网络空间中各个信息系统的安全防护能力,以及分析…...
Android 13 - Media框架(6)- NuPlayer
上一节我们通过 NuPlayerDriver 了解了 NuPlayer 的使用方式,这一节我们一起来学习 NuPlayer 的部分实现细节。 ps:之前用 NuPlayer 播放本地视频很多都无法播放,所以觉得它不太行,这两天重新阅读发现它的功能其实很全面ÿ…...
机器学习|DBSCAN 算法的数学原理及代码解析
机器学习|DBSCAN 算法的数学原理及代码解析 引言 聚类是机器学习领域中一项重要的任务,它可以将数据集中相似的样本归为一类。DBSCAN(Density-Based Spatial Clustering of Applications with Noise)是一种是一种经典的密度聚类…...
用NUXT.JS,轻松搞定SEO!
nuxt.js 是什么? 如果你正在准备开发一个SEO友好的新项目,而且准备用 vue 开发,那么恭喜你,用 nuxt 是一个成本和效率都比较优秀的方案。 官方文档 知识中心案例 简单介绍下背景,这是一个专门为氚云低代码平台引流…...
什么是电商RPA?电商RPA能解决什么问题?电商RPA实施难点在哪里?
RPA机器人可以应用于各个行业和领域,例如金融、保险、制造、物流、电商等。它可以减少人工错误和重复工作,提高效率和生产力。RPA还可以在处理大量数据时加快处理速度,提供更准确和可靠的结果。此外,RPA还可以为员工提供更有价值的…...
【BUG】Docker启动MySQL报错
个人主页:金鳞踏雨 个人简介:大家好,我是金鳞,一个初出茅庐的Java小白 目前状况:22届普通本科毕业生,几经波折了,现在任职于一家国内大型知名日化公司,从事Java开发工作 我的博客&am…...
Spring Boot通过企业邮箱发件被Gmail退回的解决方法
这两天给我们开发的Chrome插件:Youtube中文配音 增加了账户注册和登录功能,其中有一步是邮箱验证,所以这边会在Spring Boot后台给用户的邮箱发个验证信息。如何发邮件在之前的文章教程里就有,这里就不说了,着重说说这两…...
Windows使用MobaXterm远程访问ubuntu20.04桌面
参考ubuntu 2020.4 安装vnc 一、脚本文件 remote_setup.sh脚本文件内容: #! /bin/bash #参考链接:https://blog.csdn.net/hailangdeyingzi/article/details/124507304 sudo apt update sudo apt install x11vnc -y sudo x11vnc -storepasswd telpo.12…...
C++注释风格
1. 文件头注释 每个文件都应该开始于一个注释块,描述文件的目的、作者、创建日期和版权信息。 /** FileName: MyClass.cpp* Purpose: Provides functionality for XYZ operations.* Author: [Your Name]* Creation Date: YYYY-MM-DD* Last Updated: YYYY-MM-DD* C…...
Linux 编译内核模块出现--Unknown symbol mcount
文章目录 Linux suse: # cat /etc/os-release NAME"SLES" VERSION"12-SP2" VERSION_ID"12.2" PRETTY_NAME"SUSE Linux Enterprise Server 12 SP2" ID"sles" ANSI_COLOR"0;32" CPE_NAME"cpe:/o:s…...
Pywin32 Cookbook by Eric
Writing Prompt 现在你是一名专业的Python工程师,请你根据"Pywin32_Funtion"函数的功能,为其编写一个清晰的文档说明Functions win32gui.GetWindowDC(hwnd) 描述 win32gui.GetWindowDC()函数用于获取指定窗口的设备上下文(Devi…...
indexDB入门到精通
前言 由于开发3D可视化项目经常用到模型,而一个模型通常是几m甚至是几十m的大小对于一般的服务器来讲加载速度真的十分的慢,为了解决这个加载速度的问题,我想到了几个本地存储的。 首先是cookie,cookie肯定是不行的,因为最多以只…...
本地主机做网站/百度一下官网首页
壹 如今 一年不见,你还好么 听说这一年 你也参加了这样那样的会议 你说 没有干货,听得困了 结果打盹十分钟,醒来世界都变了 有时感觉台上广告讲的不错 内心有点复杂 想问问这时的你 是不是也会想我 想起我们曾经纯粹干货交流 那质朴而又…...
惠州网络公司网站建设/营销技巧
1 简介之前已经讲过TextView的基础知识,现在在这进一步进行讲解,这篇文字主要讲解如何给TextView设置段落级别的Span。如果一个Span想要影响段落层次的文本格式,则需要实现ParagraphStyle。2 ParagraphStyleParagraphStyle是一个接口…...
哪些网站可以找到做海报的素材/百度的链接
🎄🎄近期,小海带在空闲之余收集整理了一批农业作物开源数据集资源供大家参考。 整理不易,小伙伴们记得一键三连喔!!!🎈🎈 一、农作物图像分类(小麦、睡到、甘…...
dw中旅游网站怎么做/网站制作大概多少钱
看到oracle官方文档说oracle 11g dataguard在物理standby机器上出于open状态也可以应用redo,所以就在本地试验了下,确实如此,这样既可以应用redo也可以进行数据查询和数据库的备份.既解决了数据的容灾也解决了主数据库的压力.Oracle dataguard 简介 Dataguard分为2类:物理stan…...
个人求职网站履历怎么做/域名注册购买
一、项目准备 话不多说,我们开始准备项目的开发环境和软件 我的开发环境是:python 3.7.4,pycharm(不知道这个软件的可以去官网下载,百度一下就可以找到,专业版的有学生认证是免费的,不想认证也…...
行业网站建设优化案例/新闻20条摘抄大全
2.1经验误差与过拟合 定义:误差(error):学习器的实际预测输出与样本的真是输出之间的差异 定义:学习器在训练集上的误差称为“训练误差”(training error)或“经验误差”(empirical …...