文章目录
-
- 前言
-
- 引子
- 指令集
-
- 复杂指令集(CISC)
- 精简指令集(RISC)
- RISC-V
- ARM和x86的区别
- 指令集和汇编
-
- 汇编语言是用人类看得懂的语言来描述指令集
- 不同指令集对应不同的汇编语言
- ARM和x86指令集差异
-
- ARM指令集
- x86指令集
- CPU架构和ABI
-
- 什么是ABI
- ABI对不上会怎么样
- CPU架构和对应的ABI库
- 参考
前言
CPU架构以及对应的指令集是计算机组成原理一书的重点,同样也是逆向工程中必须要掌握的知识点。逆向中分析二进制文件是必不可少的,经常需要把二进制文件反汇编出汇编指令,那么看懂汇编指令就显得很重要了。
本篇博客主要介绍ARM和x86指令集的区别,以及汇编指令上的区别。同时也给出CPU架构以及对应ABI的版本和解释,一起学习。
引子
我们在反编译安卓代码之后,有些代码是写在了native中,搜索函数名,然后我们就会发现函数所在目录为:
resources/lib/armeabi-v7a/*.so
疑问:
- 这里的armeabi-v7a代表的是ARM指令集的版本吗?
- 除了ARM指令集还有什么指令集?
- ARM指令集的汇编指令和其他指令集的汇编指令有什么区别呢?
带着问题,我们一起去学习和尝试解答这些问题。
指令集
复杂指令集(CISC)
- 最新的x86-64指令集中,指令的数量超过了3000条。
- 设计初衷是为了最大限度地提高硬件的性能。
- 存在兼容效率低,硬件发热高,编译器优化慢,扩展性低等问题
精简指令集(RISC)
- ARMv7架构支持大约37条指令,而在ARMv8-A架构中,其指令集增加到了大约54条。
- RISC的指令简单、定长,通过编译器实现简单指令的组合,完成复杂功能。
Intel和ARM处理器的第一个区别是,前者使用复杂指令集(CISC),后者使用精简指令集(RISC)。
RISC-V
它是开源的RISC,可以说是CPU界的Linux。
ARM和x86的区别
- arm 架构注重的是续航能力
- 由于节能的特点,ARM处理器非常适用于移动通信领域,匹配其主要设计目标为低成本、高性能、低耗电的特性。
- x86 架构注重的是性能
- X86结构的电脑无论如何都比ARM结构的系统在性能方面要快得多、强得多。
指令集和汇编
汇编语言是用人类看得懂的语言来描述指令集
否则指令集的机器码都是一堆二进制数字,人类读起来非常麻烦,但汇编是用类似人类语言的方式描述指令集,读起来方便多了。
虽然汇编语言读起来方便了,但也有缺陷。首先汇编语言操作起来还是挺麻烦的。其次汇编语言对应一条条指令集,所以当指令集改变时,就得修改相应汇编语言,导致其可移植性很差,不能跨平台使用,如ARM的汇编语言与Intel X86的就不同。这时人们就想开发一种更方便操作,超越指令集的语言,于是有了C,C++等高级语言。
但处理器只能识别二进制码,那怎么能识别高级语言呢?于是人们开发了编译器,依照如下顺序,将高级语言翻译成二进制码: 高级语言 → 汇编语言 → 二进制机器码。
不同指令集对应不同的汇编语言
不同指令集里,对应的汇编代码会对应这个指令集的机器码。 “汇编语言”其实可以理解成“机器码”的一种别名或者书写方式,不同的指令集和体系结构的机器会有不同的“机器码” 高级语言在转换成为机器码的时候,是通过编译器进行的,需要编译器指定编译成哪种汇编/机器码。
物理机自己执行的时候只有机器码,并不认识汇编代码。
ARM和x86指令集差异
ARM指令集
这个截图中的汇编语言指令集是ARM指令集。
汇编语言指令含义如下:
ldr是装载(Load)指令,用于从内存中取出数值放入寄存器中。 str是存储(Store)指令,用于将寄存器的值存储到内存中。 mov 指令用于将一个寄存器的值复制到另一个寄存器,或者将一个立即值(即一个固定的数, 例如一个整型或者字符型的常量)复制到一个寄存器。
x86指令集
还是以上案例,对应x86的汇编语言指令为:
装载操作:mov eax, [ebx] 这个指令会将由寄存器ebx指向的内存地址中的内容加载到寄存器eax中。 存储操作:mov [eax], ebx 这个指令会将寄存器ebx的值存入寄存器eax指向的内存地址。
在x86指令集中,mov指令功能很丰富,可以实现从内存到寄存器,寄存器到内存,寄存器到寄存器,以及立即值到寄存器或内存,连寄存器和内存之间都可以直接传送数据。
所以在x86指令集中,不需要ldr和str,全部都是由mov指令实现。我们看到ldr和str就可以推断出,是ARM指令集。
CPU架构和ABI
什么是ABI
全称是"Application Binary Interface",即应用程序二进制接口。它是一个接口标准,定义了应用程序和操作系统之间或者不同应用程序模块间所必须遵守的一个约定。
这关乎到应用程序的二进制兼容性问题。你可以把它看作是一种约定,即:
- 如何在运行时找到并执行程序的入口函数
- 系统如何调用在程序二进制文件中定义的函数,以及
- 如何将参数从调用函数传递给被调用函数,以及从被调用函数返回结果给调用函数。
ABI对不上会怎么样
如果 ABI 接口对不上,那么程序可能无法在指定设备上运行,或者会出现各种预期外的问题,例如性能差、运行不稳定或应用崩溃等。这是因为 ABI 接口定义了应用程序和操作系统之间的二进制接口规范,包括如何调用函数、参数传递方式等,如果不匹配,那么程序和操作系统之间的交互就会出现问题。
CPU架构和对应的ABI库
- ARMv5
- ARMv7 (从2010年起)
- x86 (从2011年起)
- MIPS (从2012年起)
- ARMv8
- MIPS64
- x86_64 (从2014年起)
在Android系统上,每一个CPU架构对应一个ABI:
- armeabi
- armeabi-v7a
- x86
- mips
- arm64-v8a
- mips64
- x86_64
参考
从CISC到RISC-V:指令集的未来在哪里
iOS汇编教程:理解ARM