数据类型

与高级编程语言类似,ARM也支持操作不同的数据类型。

我们载入(load)或存储(store)的数据类型可以是有符号或无符号的半字字节。这些数据类型的扩展符是:-h或-sh代表半字,-b和-sb代表字节,其中没有扩展符号。有符号和无符号的区别:

  • 有符号数据类型可以存储正数和负数,因此表示的值范围更小。
  • 无符号数据类型可以存储大的正数(包含0),不能存储符数因此可以表示更大的数。

载入和存储指令使用数据类型:

ldr = Load Word
ldrh = Load unsigned Half Word
ldrsh = Load signed Half Word
ldrb = Load unsigned Byte
ldrsb = Load signed Bytes
​
str = Store Word
strh = Store unsigned Half Word
strsh = Store signed Half Word
strb = Store unsigned Byte
strsb = Store signed Byte

字节序列

查看内存中的字节有两种基本方式:小端模式(Little-Endian)和大端模式(Big-Endian)。它们的不同之处是对象存储在内存中时每个字节的排列顺序-字节顺序。在x86这种小端模式的机器上低位字节存储在低地址(更靠近零地址),而在大端模式的机器上高位字节存储在低地址。在第三版本之前ARM架构是小端模式,之后是两种模式都允许,可以进行设置来切换字节序列。例如,在 ARMv6 上,指令是固定的小端,数据访问可以是小端或大端,由程序状态寄存器 (CPSR) 的位 9(E 位)控制。

ARM寄存器

寄存器的数量取决于ARM的版本。根据ARM参考手册,除了基于 ARMv6-M 和 ARMv7-M 的处理器外,共有30个32位通用寄存器。前 16 个寄存器可在用户级模式下访问,其他寄存器在特权软件执行中可用(除了 ARMv6-M 和 ARMv7-M )。在本教程中,我们将使用非特权模式下可访问的寄存器:r0-15。这 16 个寄存器可以分为两组:通用寄存器和特殊用途寄存器。

下表只是简要了解 ARM 寄存器与英特尔处理器中的寄存器的关系。

R0-R12:可用于常见操作期间存储临时值、指针(内存位置)等等。例如R0,在算术运算期间可以称为累加器,或用于存储调用的函数时返回的结果。R7在进行系统调用时非常有用,因为它存储了系统号,R11可帮助我们跟踪作为帧指针的堆栈上的边界(稍后将介绍)。此外,ARM上的函数调用约定函数的前四个参数存储在寄存器r0-r3中。

R14:LR(链接寄存器)。进行函数调用时,链接寄存器将更新为当前函数调用指令的下一个指令的地址,也就是函数调用返回后需要继续执行的指令。这么做是允许子函数调用完成后,在子函数中利用该寄存器保存的指令地址再返回到父函数中。

R15:PC(程序计数器)。程序计数器自动按执行的指令大小递增。此指令大小在ARM模式下始终为4个字节,在THUMB模式下为2个字节。执行分支指令时,PC保存目标地址。在执行过程中,在ARM模式下PC将当前指令的地址加上8(两个ARM指令),在Thumb(v1)状态下则指令加上4(两个Thumb指令)。这与x86 中PC始终指向要执行的下一个指令不同。

我们看一下在调试状态下PC的值。我们使用以下程序将PC地址存储到 r0 中,并包含两个随机指令。看看会发生什么。

.section .text
.global _start
​
_start:mov r0, pcmov r1, #2add r2, r1, r1bkpt

使用GDB在_start处设置断点并运行:

gef> br _start
Breakpoint 1 at 0x8054
gef> run

输出:

$r0 0x00000000   $r1 0x00000000   $r2 0x00000000   $r3 0x00000000
$r4 0x00000000   $r5 0x00000000   $r6 0x00000000   $r7 0x00000000
$r8 0x00000000   $r9 0x00000000   $r10 0x00000000  $r11 0x00000000
$r12 0x00000000  $sp 0xbefff7e0   $lr 0x00000000   $pc 0x00008054
$cpsr 0x00000010
​
0x8054 <_start> mov r0, pc     <- $pc
0x8058 <_start+4> mov r0, #2
0x805c <_start+8> add r1, r0, r0
0x8060 <_start+12> bkpt 0x0000
0x8064 andeq r1, r0, r1, asr #10
0x8068 cmnvs r5, r0, lsl #2
0x806c tsteq r0, r2, ror #18
0x8070 andeq r0, r0, r11
0x8074 tsteq r8, r6, lsl #6

我们可以看到PC持有将要执行的下一个指令(mov r0, pc) 的地址(0x8054)。现在,让我们执行这条指令,之后R0应该持有PC(0x8054) 的地址,对吗?

$r0 0x0000805c   $r1 0x00000000   $r2 0x00000000   $r3 0x00000000
$r4 0x00000000   $r5 0x00000000   $r6 0x00000000   $r7 0x00000000
$r8 0x00000000   $r9 0x00000000   $r10 0x00000000  $r11 0x00000000
$r12 0x00000000  $sp 0xbefff7e0   $lr 0x00000000   $pc 0x00008058
$cpsr 0x00000010
​
0x8058 <_start+4> mov r0, #2       <- $pc
0x805c <_start+8> add r1, r0, r0
0x8060 <_start+12> bkpt 0x0000
0x8064 andeq r1, r0, r1, asr #10
0x8068 cmnvs r5, r0, lsl #2
0x806c tsteq r0, r2, ror #18
0x8070 andeq r0, r0, r11
0x8074 tsteq r8, r6, lsl #6
0x8078 adfcssp f0, f0, #4.0

对吗?错!看一下R0中的地址。虽然我们期望R0包含以前读取的PC值(0x8054),但它保留的值比我们之前读取的PC 早两个指令(0x805c)。从这个示例中可以看到,当我们直接读取PC时,它遵循PC指向下一个指令的定义;但在调试时,PC会指向当前PC值之后的两个指令(0x8054 + 8 = 0x805C)。这是因为较旧的ARM处理器始终取当前执行的指令之后的两个指令。ARM保留此定义的原因是为了确保与早期处理器兼容。

状态寄存器

当你用gdb调试ARM程序时,你会看到一些状态标志:

寄存器$cpsr显示当前程序状态寄存器的值,在它下面你可以看到工作状态标志,用户模式,中断标志,溢出标志,进位标志,零标志位,符号标志。这些标志代表了CPSR寄存器中特定的位,并根据CPSR的值进行设置,如果标志位有效则会进行加粗。N、Z、C 和 V 位与x86上的EFLAG寄存器中的SF、ZF、CF和OF位相同。这些位用于支持条件分支中的条件执行,并在汇编层面支持循环语句。我们将在第6部分:条件执行和分支中进行介绍。

上图显示了32位寄存器(CPSR)的结构,左侧是高字节位,右侧是低字节位。每个单元(GE和M部分以及空白单元除外)的大小均为一个bit位。这些位定义了程序当前状态的各种属性。

假设我们可以使用CMP指令比较1和2,返回结果应该为负数(1 - 2 = -1)。当比较两个相等的数则会设置Z(zero)标志位(例如比较2和2, 2 - 2 = 0)。记住,CMP指令中使用的寄存器不会被修改,只有CPSR会根据这些寄存器相互比较的结果进行修改。

这是GDB(安装了GEF)中的模样:在此示例中,我们比较寄存器r1和r0,其中r1 = 4和r0 = 2。这是执行 cmp r1,r0 操作后标志的外观:

之所以设置Carry标志,是因为我们使用 cmp r1, r0 将 4 与 2(4 - 2)进行比较。相反,如果我们使用 cmp r0 r1、r1 将较小的数字(2)与较大的数字(4)进行比较,则设置负标志(N)。

CPSR 包含以下状态标志:

  • N – 当计算结果为负时被设置.
  • Z – 当计算结果为零时被设置.
  • C – 当计算结果有进位时被设置.
  • V – 当计算结果有溢出时被设置.

C:其设置分一下几种情况:

  • 加法运算(包括比较指令cmn):当运算结果产生了进位时(无符号数溢出),C=1,否则C=0.
  • 减法运算(包括比较指令cmp):当运算时发生了借位(无符号数下益出),C=0,否则C=1.
  • 对于包含移位操作的非加/减运算指令:C为移位操作中最后移出位的值.
  • 对于其他非加减运算指令:C的值通常保持不变.

V:如果加、减或比较的结果大于或等于2^31 或小于-2^31,则会发生溢出。

汇编 cmp_ARM汇编语言入门(二)相关推荐

  1. ARM 汇编语言入门

    [翻译]二进制漏洞利用(二)ARM32位汇编下的TCP Bind shell:https://bbs.pediy.com/thread-253511.htm ARM汇编语言入门 From:ARM汇编语 ...

  2. 汇编语言入门--调试工具debug的使用(史上最全,11种常见命令)

    汇编语言入门–调试工具debug的使用(史上最全,11种常见命令) 1.直接启动debug程序 详见:https://bingshuai.blog.csdn.net/article/details/1 ...

  3. 初学 Delphi 嵌入汇编[1] - 汇编语言与机器语言

    非科班出身, 现在才接触汇编, 惭愧呀, 好好学!  主选课本是清华大学王爽老师的<汇编语言>. 推荐 王爽老师的汇编网 汇编语言之前是机器语言. 机器语言是机器指令的集合, 机器指令是一 ...

  4. SQL基础使用入门(二): DML语句和DCL语句

    SQL语句第二个类别--DML 语句 DML是数据操作语言的缩写,主要用来对数据表中数据记录实例对象进行操作,包括插入.删除.查找以及修改四大操作,这也是开发人员使用中最为频繁的操作. 1.插入记录 ...

  5. 文本分类入门(二)文本分类的方法

    文本分类入门(二)文本分类的方法 文本分类问题与其它分类问题没有本质上的区别,其方法可以归结为根据待分类数据的某些特征来进行匹配,当然完全的匹配是不太可能的,因此必须(根据某种评价标准)选择最优的匹配 ...

  6. 转 Python爬虫入门二之爬虫基础了解

    静觅 » Python爬虫入门二之爬虫基础了解 2.浏览网页的过程 在用户浏览网页的过程中,我们可能会看到许多好看的图片,比如 http://image.baidu.com/ ,我们会看到几张的图片以 ...

  7. java类作用域标识符_java入门 (二) 标识符、数据类型、类型转换、变量、常量、作用域...

    java入门(二) 标识符 数据类型 类型转换 变量.常量.作用域 本次笔记引用B站:狂神说,虽然早就会了,现在回头来敲下基础,加深印象 1.标识符: java所有的组成部分都需要名字.类名丶变量名丶 ...

  8. MySQL入门 (二) : SELECT 基础查询

    1 查询资料前的基本概念 1.1 表格.纪录与栏位 表格是资料库储存资料的基本元件,它是由一些栏位组合而成的,储存在表格中的每一笔纪录就拥有这些栏位的资料. 以储存城市资料的表格「city」来说,设计 ...

  9. 微信小程序入门二:底部导航tabBar

    小程序底部导航栏组件tabBar,可以参考下官方的API:tabBar 先看代码 //app.json {"pages":["pages/index/index" ...

最新文章

  1. 《R语言初学指南》一2.8 参考文献
  2. 如何删除 Windows.old 文件夹
  3. 高服从编纂器 VIM-操作篇(1)
  4. mysql空间是什么格式_MySQL数据类型 - 空间数据类型 (6)
  5. Windows服务器管理(4)——WinServer2008/2008R2系统 安装AD域控及DNS服务器
  6. Wannafly挑战赛14 F
  7. authorization 传 就跨域_跨域访问接口上传图片出现options请求问题解决方法
  8. ASP.NET之MVC 微信公众号授权给第三方平台的技术实现流程一(获取第三方平台access_token)...
  9. 雷林鹏分享:MySQL 元数据
  10. 内核调试工具 — kdump crash
  11. 【缺陷检测】基于matlab GUI形态学PCB电路板缺陷检测【含Matlab源码 821期】
  12. 将txt格式的地图导入到ArcMap
  13. excel批量删除数值前几位
  14. python的注释符号有哪些_python注释符号
  15. mysql sum契合_文化契合者为王。 这是在下一次开发人员面试中如何定位的方法。...
  16. 解决群晖 “由于系统可用存储空间不足,您将无法登录“ 的问题
  17. 基于深度相机的三维重建技术
  18. Python之三元运算、集合、函数
  19. Microbiome杂志和主编简介
  20. 软件测试进阶(一)A/B测试终极指南

热门文章

  1. 面试:字符串拼接,什么时候用StringBuilder?
  2. Java 服务端推送消息有那么难吗?
  3. java 整型_Java整型计算
  4. python 多维list 排序_人生苦短 | Python列表和元组归纳整理
  5. android adb恢复出厂设置,android开发分享擦除数据/通过ADB恢复出厂设置
  6. pytorch计算模型参数量
  7. ncnn-mobile
  8. LibTorch NMS
  9. ModuleNotFoundError: No module named ‘config‘
  10. python-dotenv的使用