深入理解计算机系统(三)之程序的机器级表示

在一些应用中,程序员必须用汇编代码来访问机器的低级特性。一种方法是:整个函数都用汇编代码来写,然后在链接阶段与C语言函数结合起来。 第二种方法是,在C语言程序中直接利用GCC对嵌入汇编代码支持。

Intel 处理器系列俗称X86。

IA32指令集:

unix> gcc -O1 -o p p1.c p2.c

编译选项-O1 告诉编译器使用第一级优化。(第二级优化较好)

首先, C预处理器插入所有用#include命令指定的文件,并扩展所有用#define声明指定的宏。

然后,编译器产生两个源代码的汇编代码(p1.s 和 p2.s)。

接下来,汇编器将汇编代码转化成二进制目标代码(p1.o 和 p2.o)(目标代码是机器代码的一种形式,它包含所有指令的二进制表示,但是还没有填入地址的全局值)

最后,链接器将两个目标代码文件与实现库函数的代码合并,并产生可执行代码P。

对于机器级编程,有两种抽象:

第一种是机器级程序的格式和行为,定义为指令集体系结构(ISA),它定义了处理器状态、指令的格式,以及每条指令对状态的影响。

第二种抽象是机器级程序使用的是存储器地址是虚拟地址。


一些处理器状态是可见的(IA32机器):

PC:用%eip表示,指示将要执行的下一条指令在存储器中的地址。

整数寄存器文件包括8个命名的位置,分别存储32位的值。这些寄存器可以存储地址或整数数据。有的寄存器被用来记录某些重要的程序状态,而其他的寄存器则用来保存临时数据。例如过程的局部变量和函数的返回值。


一组浮点寄存器存放浮点数据。


unix> gcc -O1 -s code.c

"-s "选项,能得到c语言产生的汇编代码。


- IA32 指令长度从1到15个字节不等。常用的指令以及操作数较少的指令所需的字节数少,而那些不太常用或者操作数较多的指令所需的字节数较多。

- 设计指令格式的方式是,从某个给定位置开始,可以将字节唯一地解码成机器指令。如,只有pushl %ebp 是以字节值55开头。

- 反汇编器只是基于机器代码文件中的字节序列来确定汇编代码。


以 ‘.’ 开头的行都是指导汇编器和链接器的命令。(两种格式的汇编代码ATT和Intel) 

大多数GCC生成的汇编代码指令都有一个字符后缀,表明操作数的大小。例如,数据传送指令:movb、movw、movl。

在IA32中包含八个存储32位值的寄存器。

%eax, %ecx, %edx, %ebx, %esi, %edi (通用寄存器). 

%ebp, %esp(保存指向程序栈中重要位值的指针)


你可能感兴趣的:(深入理解计算机系统(三)之程序的机器级表示)