- 第一讲:计算机的组织架构和汇编语言介绍
- 汇编语言
- 计算机组织架构
- 数字电路
- 术语回顾
- 数制
- 数字电路
- 硬件电路
- 数字电路的问题
- 汇编语言的开始
- 程序的节(sections)
- 调用操作系统的系统调用
- 列出文件(Listing files)
- 汇编和链接
- 调试汇编程序
- 反汇编现有的程序
- 附录
- 课程资源
第一讲:计算机的组织架构和汇编语言介绍
汇编语言
汇编语言和C/C++语言的区别是什么?
-
汇编语言是底层语言,更接近于CPU本身可以理解的内容。CPU可以理解的是纯粹的字节流(机器语言)。几乎不会有人愿意通过写原始的字节流进行编程。汇编语言处于机器语言的上层, 将CPU可以理解的操作码(Opcode)抽象成了人类可以理解的命令, 例如
add
,mov
等等。这些名字被称之为助记符。 -
和C/C++语言相比,汇编语言的工具较少。没有所谓的"标准汇编语言库"。如果你想要写一个字符串处理的方法,你只能自己编写。
-
汇编语言不能移植到其他类型的CPU上(x86 vs ARM)或者其他类型的操作系统上(Windows vs Linux), 甚至不能和其它类型的汇编语言(YASM vs MASM vs GAS)都无法兼容。
一般来说, 我们编译一个C/C++ 程序的流程如下所示:
compile link
C/C++ source code --> object code --> executable
其中object code是指指令流, 这些指令将会被CPU直接运行。C/C++中的一条语句可能会编译成许多指令。即使是像下面这样简单的语句:
x = y;
上面的语句可能需要在CPU级别执行大量的工作, 这取决于x和y在内存中的位置,它们是否有相同的类型等等。
因此,我们使用高级语言(C/C++)编写的"指令"的数量和CPU实际执行的指令的数量上存在很大的差异。
但是汇编语言所编写的指令和cpu实际执行的指令是一一对应的。汇编语言程序中的每一行代码都保证翻译成单个 CPU 指令。一方面,这意味着汇编语言可以让我们很好的掌握CPU正在执行的工作, 另一方面,我们在C/C++语言中很方便实现的特性实际上在CPU层面都不存在。实际上,在CPU层面上并没有所谓的for循环,if-else条件分支,变量声明等等。我们必须通过组合一些原始的操作来实现这些高级语言的特性。
由于汇编指令和CPU指令是一一对应的,因此每种类型的CPU都有自己对应的汇编语言。Intel CPU的汇编语言和ARM CPU(大多数智能手机使用ARM CPU)的汇编语言是完全不同的。并且与Arduino上使用的AVR CPU完全不同。与C/C++不同的是,汇编语言是无法做到移植性的。
即便我们使用同一种类型的CPU,也不能保证汇编器与操作系统之间的可移植性。与C/C++不同的是, C/C++由国际委员会决定C/C++的标准,然而汇编语言却不是这样。因此,按照YASM(汇编器)写出来的汇编代码可能无法在GAS/NASM或者微软的汇编器上进行汇编。操作系统层面也会导致这样的不兼容性,因为没有"标准汇编库"。在一种操作系统下写出的汇编程序可能无法移植到其他操作系统下。Windows下使用汇编语言写出的程序移植到Linux下可能不能运行,不仅仅是因为汇编器不同,操作系统系统的接口不同也是一个重要原因。(Windows和Linux对于系统调用的定义不同)。
本课程使用的是 YASM 汇编器, 基于64位的Intel CPU(X86-64),在Linux系统下运行。
我们会使用GDB调试器去调试你的汇编程序。在C++中,你最初用于调试程序的工具可能是在出错的位置附近添加cout,但是将打印添加到汇编程序中就可能需要重写你需要打印的函数,甚至重新所有的程序。显示通过打印的方式调试程序在汇编语言的debug中是不可行的。所以我们在课程中也会熟悉GDB工具。
计算机组织架构
计算机组织架构是指计算机的内部结构。内存、CPU、I/O设备等如何连接在一起,如何配合起来工作。虽然我们主要关注我们实际使用的计算机的组织架构(x86-64),但是有时我们也会去和其他的计算机系统进行比较(MIPS, ARM等等)。当然,记住这些不同的系统的区别也很重要。
数字电路
CPU通过数字电路来实现,数字电路由逻辑门电路组成。这是比汇编语言更加底层的内容。我们会稍微了解一下数字电路,仅仅是为了感受CPU是如何进行工作的,但是课程的侧重点还是在汇编语言上。
术语回顾
字节(Byte):可以单独寻址的计算机内存的最小单位。对于我们来说,一个Byte等于8个bit。但是需要了解的是并不是所有的系统都是这样的。有一些奇怪的系统,一个byte是10个bit或者7个bit。
每个byte中的每个bit的位置从右到左编号为0到7:
Bit value 0 0 1 0 1 1 0 1
Bit pos. 7 6 5 4 3 2 1 0
字(word): 两个字节(16 bits)。
将一个字视作2个字节时,我们将第一个字节(占据低8位的字节)称之为"低字节", 将第二个字节称之为"高字节"。
类似的,如果我们对一个字节中的bit的位置进行编号,则低字节的bit将编号为0-7,而高字节中的bit将编号为8-15。
这个规则可以推广到双字(dword)的低位字和高位字、四字(qword)的低位和高位双字等等。类似的,在一个字节中,比特0代表低位, 比特7代表高位。
双字(double-words/dword): 4个bytes(32个bits)
四字(Quad-word/qword): 8个bytes(64个bits)。(这个quad可以用quadra kill四杀来辅助记忆)
依次类推还有,双四字(double-quad-words),16bytes, 四四字(“quad-quad-words”), 32 bytes, 等等。但是这些很少见,不常用。
KB:kilo-bytes(千字节), 这里的"kilo"指的是二进制的千, 2 10 = 1024 {2}^{10} = 1024 210=1024字节。K后面跟着的大写的B代表我们的单位是字节,如果是小写的b则代表是比特。
Kb:kilo-bit(千比特)。这个单位通常使用的不太多,在通讯领域中使用很多。例如带宽通常以兆比特为单位进行测量。
MB:Mega-byte(兆字节), 2 20 = 1024 2 = 1048576 {2}^{20} = {1024}^{2} = 1048576 220