Part I 代码片段

Everything is comprehended in comparison - Author unknown

我在开始学C/C++的时候,经常写一些小段的代码编译一下,然后观察输出的汇编代码。这种习惯让我很容易理解代码背后到底发生了什么。这种习惯让C/C++代码和编译器产生的汇编语言的关系深深地印在我的脑海里,对我来说很容易就能通过汇编代码想出C代码和函数粗略的样子。或许这个技巧对其他初学者能有所帮助。

本书有时候会用到一些旧的编译器,这是为了尽可能得到最短的(最简单)代码片段。

关于练习

作者在学习C语言的时候,经常些写一些C语言的小函数,然后逐渐的将他们重写成汇编语言,并尝试让代码尽可能的短。现在这种做法不是很值得提倡,因为很难在效率上和现代编译器相竞争。不过这是一种深入理解汇编语言的好方法。因此,你可以放轻松一些,随便在这本书里找一段汇编代码,然后尝试者让它更短一些。当然不要忘记测试你所写的汇编代码。

优化等级和调试信息

源代码可以用不同的编译器,以不同的优化等级来编译。 典型的编译器有三种优化等级,其中0级代表不优化。优化既可以针对代码的体积,也可以针对代码的运行速度。一个无优化的编译器编译会更快一点,生成的代码也更容易理解一些(虽然很冗长)。反之一个带优化的编译器会运行的更慢,并编译出运行的更快的代码(但代码并不会更紧凑)。

除了优化的级别和方向外,一个编译器还可能在生成的文件里包含一些调试信息,这样的代码更容易调试。个编译器的一个重要特性是,在输出文件里面,可能会有源代码到机器码地址的连接。另一方面,带优化的编译器,更倾向于将所有的源代码优化掉后再输出,因此源代码不会出现在输出的机器码里。一个逆向工程师这两种情况都有可能遇到,因为有的开发者会打开优化,有的不会。所以,在这本书里,我们会尽可能关注每个例子的调试和发行版本的代码特征。

第一章

CPU简介

CPU是一种可以执行由机器码组成的程序的设备。

词汇表:

Instruction:用于控制CPU的指令。最简单的例子有:在寄存器之间进行数据转移操作,内存操作,算术操作。原则上每种CPU会有自己独特的一套指令构架(Instruction Set Architecture(ISA))。

Machine code: 机器码,CPU能直接处理的代码。每条指令都会被译成几个字节的机器码。

Assembly Language: 汇编语言,助记码和其他一些像宏那样的扩展组成的、便于程序员编写的语言。

CPU register:CPU寄存器,每个CPU都有一些通用寄存器(General Purpose Registers(GPR))。X86有8个,x86-64(amd64)有16个,ARM有16个,最简单的理解寄存器的方法就是,把寄存器想成一个未指定类型的临时变量。想象你在使用高级语言编程,并且只能用8个32bit(或 64-bit)的变量。但是只用这些可以完成非常多的事情。

那么你可能想知道,机器码跟程序语言有什么区别呢?答案主要在于人类和CPU的思维方式并不类似。对于人类来讲,使用例如C/C++, Java, Python这样高级语言会比较简单,但是CPU更喜欢低级抽象的东西。也许有一天CPU也能直接执行高级语言的语句,但那样的CPU肯定会变得比天的要复杂好几倍。类似的,人类之所以使用汇编语言会感觉不很方便,是因为它非常的低级,而且很难用它写很长的代码而不出错。

将高级语言转换成汇编语言的程序,被称为编译器。

1.1 关于不同指令集的几点

x86构架一直都带有可变长度的操作码,因此64位的世纪到来时,x64的扩展对这个构架并没有太大的影响。事实上x86构架还包含着很多最早在16位8086 CPU里出现的指令,他们在今天的处理器中依旧可以被使用。

ARM是一种带定长操作符的精简指令集的CPU,它过去有很多优点。

最初,ARM所有的指令都被编码为4个字节。这现在被称为“ARM模式”。但是人们发现这样做并不像他们一开始所想的那样节约。事实上现实中最常用的CPU指令都可以用更少的字节来编码。因此他们又增加了一种每个指令只以2字节编码的构架,叫做Thumb。这现在被称为“Thumb模式”。然而并不是所有的ARM构架都能被编码为2字节,所以Thumb构架在某些方面是有限制的。值得注意的是以ARM模式或Thumb模式编译得代码,有可能同时出现在一个程序里。

ARM的设计记者认为Thumb可以作为一种扩展存在,这就产生了Thumb-2,它首次在ARMv7里出现。Thumb-2依旧使用2字节的指令集,但是它也有一些4字节的新指令。有一种很常见的错误观念,认为Thumb-2是ARM和Thumb的混合物。这是不对的,Thumb-2扩展了对所有处理器特性的支持,所以他可以和ARM模式相竞争———很显然这个目标被很好的实现了。主要的iPod/iPhone/iPad应用是用Thumb-2指令集编译的(公认的,这主要是因为Xcode把这个设为默认模式)。

之后,64位的ARM发布了,这种构架有4字节的操作码,而且也不需要任何附加的Thumb模式。即便如此64位的要求也影响了构架,导致了现在有3种ARM构架:ARM 模式、Thumb 模式(包括Thumb-2)和ARM64。这些构架有部分交叉,可以说他们是不同的构架,但不能说他们是一个构架的的不同变种。因此在这本书里,我们会试着加入全部三种ARM构架的代码片段。

顺带提一下,还有很多带32位变长操作码的、精简指令集的构架。例如:MIPS,PowerPC and Alpha AXP.

results matching ""

    No results matching ""