导读:
为啥要学arm汇编,因为逆向so的需要,当so被反汇编之后得到的是一堆的arm汇编代码,而不是c/c++代码,虽然有IDA的强大的F5功能,但是事实上我们没法完全去相信IDA的F5,需要结合汇编代码进行结合辅助我们进行代码分析,这也就是我们为什么要学习arm汇编的原因
ARM体系结构
RISC与CISC
ARM体系的处理器继承自RISC(精简指令集计算机),之所以采用RISC,是因为CISC(复杂指令集计算机)的指令只有大约20%会被在80%的程序设计被重复使用,而大约80%的指令只占据程序设计的20%,这种设计显然不合理。
RISC结构优先选取使用频率最高的简单指令,避免复杂指令;将指令长度固定,指令格式和寻址方式种类减少;以控制逻辑为主。
流水线技术
这里只简单介绍一下arm7的三级流水线技术,为啥?因为弟弟我的手机只有这个三级流水线的。。。
三级流水线是哪三级?
取指级
取指级完成程序在存储器的指令读取,并将指令放入进流水线译码级
对指令进行译码,为下一周期准备数据路径需要的控制信号。这一级指令“占有”译码逻辑,而不“占有”数据路径。执行级
指令“占有”数据路径,寄存器堆栈被读取,操作数在桶形移位器中被移位,ALU产生相应的运算结果并写回到目的寄存器中,ALU结果根据指令需求更改状态寄存器的条件位。
每一级中的硬件必须能够独立操作,而不能多级占用同一硬件资源。每级指令经由流水线的一个时钟周期完成一条指令,三级则需要三个时钟周期。
当通过R15(程序计数器,即前面提到的CPU内部的存储器用于存储指令的存储器)总是指向取指的指令,而不是指向正在执行的指令或正在译码的指令。通常,人们把正在执行的指令作为参考点,称为第一条指令,因此PC总是指向第三条指令(执行级)。
PC值的计算
对于ARM指令,PC值=当前程序位置+8;对于Thumb指令,则有PC值=当前程序执行位置+4
ARM反汇编基础
android指令支持
这里只记我平时常用的两种架构
armeabi-v7a
- Thumb-2指令集扩展: 性能堪比32位ARM指令,简洁性类似于之前16位的Thumb指令集,同时支持16位与32位指令集的混合使用。
- VFP硬件FPU指令:包括VFPv3-D16,除了ARM核心中的16个32位寄存器,还包含16个专用的64位浮点寄存器。
同时支持可选扩展NEON、VFPv3-D32和ThumbEE, armeabi-v7a已经被并入AArch32架构。
arm64-v8a
兼容armabi-v7a,并支持AArch64架构,VFP扩展升级为v4版本, NEON指令集扩展是必需的。
64位arm64-v8a规格的处理器支持AArch64和AArch32两种运行模式。
在AArch64下,所有代码数据寻址采用64位地址空间,寄存器也采用64位的。
在AArch32模式为32位,因此,在此模式下代码数据寻址和寄存器的使用与之前一样,才有32位的。
因此,arm64-v8a完全兼容armeabi-v7a。
ARM原生程序的生成过程
- 编写代码
编译代码
编写完代码之后需要进行代码的编译,此处跟书本不一样,主要采用clang,此处采用官网的说明,而书中采用的是gcc
Android NDK编译从 NDK r19 开始,NDK 默认安装的工具链可供使用。与任意构建系统进行交互时不再需要使用 make_standalone_toolchain.py 脚本。为了确保使用正确的架构进行构建,请在调用 Clang 时使用 -target 传递适当的目标,或调用具有目标前缀的 Clang。例如,若要为 64 位 ARM Android 编译值为 21 的 minSdkVersion,可使用以下两种方法,您可以选择使用其中最方便的方法
$ $NDK/toolchains/llvm/prebuilt/$HOST_TAG/bin/clang++ -target aarch64-linux-android21 foo.cpp $ $NDK/toolchains/llvm/prebuilt/$HOST_TAG/bin/aarch64-linux-android21-clang++ foo.cpp
如上图,执行完这一句之后sum.cpp已经被编译完成。
完成代码的预处理
预处理阶段,编译器将代码中的预处理指令进行处理。例如#include 中包含的头文件会全部编译进来,#define预定义、#if预条件处理等也都会在这里被编译器处理。详细的输出信息通过-E进行查看。
clang++ -E -fPIE file.cpp -o file.i
相应的.i文件的内容如下,由于我包含了一个iostream,结果几行代码,预编译之后变成了将近30000行。
编译
该阶段会进行语法等代码规范性检查,检查无误会把代码翻译成ARM汇编代码,输出信息通过-s选项进行查看。clang++ file.i -S -fPIE -o file.s
执行该命令后会生成file.s的汇编文件。汇编
汇编阶段主要用来将汇编文件生成目标文件。clang++ -c file.s -o file.o
- 链接
将所有的目标合并,生成最终的可执行程序或动态链接库。clang++ file.o -fPIE -o file
Arm汇编基本语法
.text
在编译后用于存放代码的代码段。位于ARM EABI的ELF中。
.rodata
用于存放数据的数据段。位于ARM EABI的ELF中。
.section
汇编代码中用于声明段时需要使用的伪指令。.text实际上写作.section.text,但其比较特殊可简写。使用.section声明的所有的段信息在编译后可通过执行命令来查看。
.global
用于声明全局符号。可以被外部程序引用。