DennyQi's Log

02 Machine-Level Representation of Programs

我们已经知道了如何用机器来表示信息,现在我们希望用机器来处理信息。信息的处理可以看作一个程序(一个函数)。人类的自然语言,或是一些人类设计的形式语言,可以“表示”一个程序(“表示”的意思是语言指向了一个逻辑形式下的程序)。计算机的基本工作,就是要自动“执行”高级语言程序。“执行”就是指通过一套精心设计的系统,自动把高级语言还原为信息的储存和搬运,并在最简单的逻辑门下做运算。出于效率的考虑,这个还原的过程并不是一步到位的,而是会经历多个层级。最底层是机器指令,这些指令是人们为特定机器设定的特定协议,它包含最基础的信息储存、搬运、计算操作。为了让机器指令变得更加人类可读,人类设计了汇编语言来表示机器指令。比汇编语言更高层级地有C,Python等等。因此,此刻我们关心以下问题:(1) 这个处理信息的机器是什么样的?它有什么样的结构,有哪些组成部件,具有什么样的功能?(2) 最底层的机器指令有哪些?它们和高级语言(以C为例)有什么联系?

我们接下来讨论的这个系统称为x86-84,它是最主流的计算机系统,由INTEL公司开发。首先让我们关注这个系统里最重要的两个部件,一个称为中央处理单元(Central Processing Unit, CPU),一个称为内存(Memory)。让我们把内存暂时看作一个巨大的数组,数组的每一个栏位存储着一个字节的信息,数组的下标就称为地址(address)。CPU由五个部分组成,分别是寄存器、算数逻辑单元(Arithmetic Logical Unit, ALU)、控制单元(Control Unit)、高速缓存(Cache)、总线接口(Bus Interface)。寄存器用来临时存储正在被处理的一些数据,ALU负责完成最基本的计算,控制单元负责从内存中读取当前指令,高速缓存和总线接口之后再说。

首先让我们列出x86-64中的16个整数寄存器的名字:(每个寄存器都是64位的,32,16,8分别对应着较低位的部分,其命名是INTEL开发的历史遗留下来的)

寄存器

整数寄存器

64/32/16/8Caller/Callee saved常用功能备注
rax/eax/ax/al调用者保存函数返回值
rbx/ebx/bx/bl被调用者保存
rcx/ecx/cx/cl调用者保存第4个参数
rdx/edx/dx/dl调用者保存第3个参数
rsi/esi/si/sil调用者保存第2个参数
rdi/edi/di/dil调用者保存第1个参数
rbp/ebp/bp/bpl被调用者保存
rsp/esp/sp/spl/栈指针
r8/r8d/r8w/r8b调用者保存第5个参数
r9/r9d/r9w/r9b调用者保存第6个参数
r10/r10d/r10w/r10b调用者保存
r11/r11d/r11w/r11b调用者保存
r12/r12d/r12w/r12b被调用者保存
r13/r13d/r13w/r13b被调用者保存
r14/r14d/r14w/r14b被调用者保存
r15/r15d/r15w/r15b被调用者保存

条件码寄存器

名称常用功能备注
zfzero flag上一指令结果是否为0
sfsign flag上一指令结果是否为负数
cfcarry flag上一无符号运算是否有进位
ofoverflow flag上一有符号运算是否溢出

指令

比较和测试

指令基于备注
cmp s1 s2s1 - s2根据两数的差设置条件码
test s1 s2s1 & s2根据两数的与设置条件码

跳转指令

指令跳转条件备注
jmp Label跳转到Label
je LabelZF相等就跳转
jne Label~ZF不相等就跳转
jg Label~(SF^OF) & ~ZF(有符号)大于就跳转
jge Label~(SF^OF)(有符号)大于等于就跳转
jl Label(SF^OF)(有符号)小于就跳转(less)
jle Label`(SF^OF)ZF`
ja Label~CF & ~ZF(无符号)大于就跳转(above)
jae Label~CF(无符号)大于等于就跳转
jb LabelCF(无符号)小于就跳转(below)
jbe Label`CFZF`