《深入理解计算机系统》第三章
知识补充:unix> gcc -01 -o p p1.c p2.c
//编译选项-01表示编译器使用第一级优化,(一般认为第二级优化比较好)
首先,C预处理器扩展源代码,插入所有用#include命令指定的文件,并扩展所有用#define声明指定的宏。
然后,编译器产生两个原代码的汇编代码,名字分别为p1.s和p2.s。
接下来,汇编器将汇编代码转化成二进制目标代码文件名为p1.o和p2.o。
(目标代码是机器代码的一种形式,它包含所有指令的二进制表示,但是还没有填入地址的全局值)
最后,链接器将两个目标代码文件与实现库函数(比如 printf)的代码合并,产生最终的可执行代码文件p。
IA32机器代码:
程序计数器(在IA32中,通常被称为“PC”,用%eip表示),指示将要执行的下一条指令在存储器中的地址。
整数寄存器文件包括8个命名的位置,分别存储32位的值。(page_106)
条件码寄存器保存着最近执行的算术或逻辑指令的状态信息。它们用来实现控制或数据流中的条件变化,比如说用来实现if和while语句。
一组浮点寄存器存放浮点数据。
程序存储器包含程序的可执行机器代码,操作系统需要的一些信息,用来管理过程调用和返回的运行时栈,以及用户分配的存储器块(比如用malloc库函数分配的)。程序存储器用虚拟地址来寻址。操作系统负责管理虚拟地址空间,将虚拟地址翻译为实际处理器存储器中的物理地址。
汇编:movb(move byte,传送字节)movw(move word传送字)movl(move long word传送双字)
11种寻址模式 分为三类:(tip:)
立即数、表示寄存器的值(寄存器类)、表示对存储在存储器中从地址Addr开始的b个字节值的引用,一般省略b (page_113)
数据传送指令:mov S , D D ← S 传送 (源操作数到目的操作数)
Pushl S R[%esp] ← R[%esp]-4
M[R[%esp]] ← S 将双字压栈
Popl D D ← M[R[%esp]]
R[%esp] ← R[%esp]+4 将双字出栈
Tip:传送指令的两个操作数不能都是存储器位置。
int exchange(int *xp,int y){ xp at %ebp+8,y at %ebp+12
int x = *xp; movl 8(%ebp) , %edp
By copying to %eax below,x becomes the return value
*xp = y; movl (%edx),%eax
return x; movl 12(%ebp) , %ecx
} movl %ecx , (%edx)
像x这样的局部变量一般保存在寄存器中(%eax),而不是存储器中,为了访问速度。