序言
看到一个比较好的ARM汇编入门教程。上不了班,闲着没事翻译了一下。
原址:https://azeria-labs.com/writing-arm-assembly-part-1/
ARM 汇编语言入门(一)
Part1:ARM汇编介绍
处理器arm VS. intel
ARM与Intel有诸多不同,最主要的区别是指令集。Intel是复杂指令集(CISC:Complex Instruction Set Computing)处理器,拥有功能更多更丰富的指令,允许对内存进行更复杂的操作。因此也拥有更多的指令操作,寻址模式,然而寄存器数量却比ARM少。CISC处理器主要应用在个人电脑,工作站,服务器当中。
ARM是精简指令集(RISC:Reduced Instruction set Computing)处理器,拥有更简单的指令集(少于100个)和更多的通用寄存器。与Intel不同,ARM指令只操作寄存器,且只能使用Load/Stroe(取/存)命令来读取和写入内存。也就是说,如果增加某个地址处的32位数据的值,你起码需要三个指令(取,加,存):首先将该地址处的数据加载到寄存器(取),然后增加寄存器里的值(加),最后再将寄存器里的值存储到原来的地址处(存)。
精简指令集有优点也有缺点。优点之一是单条指令执行更快,相应地也获得了更高的处理速度(精简指令集系统通过减少单条指令的时钟周期来减少执行时间)。不利的一面是更少的指令意味着更加要求更加注重软件书写效率。还要注意的是ARM有两种工作状态:ARM模式和Thumb模式。Thumb模式指令可以是2个字节或者4个字节(详见Part 3:ARM指令集)。
ARM与x86其他区别:
- ARM中大部分指令都可以用作条件执行。
- x86和x86-64系列处理器使用小端(little-endian)地址格式。
- ARM架构在第三版以前是小端模式。之后变为大-小端(BI-endian)格式,允许大端或小端两种模式进行切换。
不仅ARM与Intel有不同,而且ARM各版本之间也有不同。本教程尽量保留它们之间最通用的部分以便你能理解ARM是怎么工作的。一旦你理解了最基本的部分,当你选择不同的ARM版本时也可以融会贯通。本教程所有的例子是在32-bit ARMv6平台(Raspberry Pi 1)创建,所有的说明都是基于此版本。
不同ARM版本命名
ARM汇编
在开始ARM开发之前我们需要先了解基本的汇编编程。使用一般的编程语言或者脚本语言来开发不行吗,为什么还需要ARM汇编?确实不行,如果我们要做逆向工程或者想了解ARM二进制程序流,创建自己的ARM壳程序(shellcode:利用程序漏洞而执行的代码),手工制作ROP(Return-Oriented Programming一种利用特殊返回指令不断返回多个前一段指令而最终拼成一段有效逻辑代码,以达到特殊攻击目的的编程技术)工具链以及调试ARM程序就要了解ARM汇编。
你不需要了解逆向工程或应用开发方面所有的汇编语言细节,你只需要了解一个大概。基础的知识都会在本教程中讲到,如果你想要了解更多可以参考文末的附加链接。
那么究竟什么是汇编语言?汇编语言你可以看成是包裹在机器码上的的一层薄薄的语法糖指令,这些指令代表着只有机器(计算机)才能读懂的二进制码。那么为什么不直接写机器码呢?好吧,如果那样做的话你绝对会很蛋疼。所以你最好还是写汇编,人能够容易读懂的ARM汇编。计算机不能运行汇编代码,它只能读懂机器码。我们要使用工具来将汇编代码转换为机器码。GNU汇编器as
为我们提供了这样的功能,可以识别*.s类型的源代码文件。
当你编写完扩展名*.s的汇编源文件后,要用as
编译然后用ld
链接:
$ as program.s -o program.o
$ ld program.o -o program
探秘汇编语言
现在我们从最底层的工作做起。在最底层是电路板上的电信号,电信号是切换两个不同的电平产生的,0V(off)或者5V(on)。因为很容易地看到电路的电平变化,所以我们可以通过可视化数字0和1的表示来匹配电压的开关模式,不仅是因为0/1可以代表电信号的缺失和出现,还因为0/1是二进制系统里数字。然后用一系列0/1组成机器码指令在计算机处理器中运行。下面就是一个机器语码指令。
1110 0001 1010 0000 0010 0000 0000 0001
很好,但是我们难以记得这些0/1组合的代表什么意思。因此我们使用叫做助记符的东西来帮助我们记忆这些二进制组合,每个二进制机器码给定一个名字。这些助记符通常包含三段字符,但不全是。这种程序被叫做汇编语言程序,它使用一系列助记符代表计算机机器码。指令中的操作数放在助记符之后。例如:
MOV R2, R1
现在我们知道了汇编程序是由叫做助记符的文本信息组成的,我们需要把它转换为机器码。前面提到的,GNU Binutils项目为我们提供了叫做as
的汇编工具。使用as
把ARM汇编语言转换为ARM机器码的过程就叫做汇编。
综上,计算机能够理解(回应)电信号的缺失和出现,并且我们可以将这一系列电信号表示成一组0/1序列(bits)。我们就可以用机器码(一系列电信号)让计算机根据一种定义好的行为做出反应。因为我们难以记忆这一串0/1组成的指令的意义,所以提供了一种助记来代表这些指令。这组助记符是计算机的汇编语言,我们使用名为"汇编器"的程序将代码从助记符表示形式转换为计算机可读的计算机代码,就像编译器对高级语言代码做的一样。