本章基于两种相关的机器语言:Intel IA32和x86-64。前者是32位计算机上的语言,后者是前者在64位机器上的拓展。
32位计算机的虚拟内存有4GB,而64位计算机高达256TB。
程序编码
假设一个C程序有两个文件p1.c和p2.c,在32位计算机上用Unix命令行编译这些代码如下:
unix> gcc -01 -o p p1.c p2.c
- 1
命令gcc就是Linux上的默认编译器:GCC C。编译选项-01告诉编译器使用第一级优化。
gcc命令调用了一系列程序,将源代码转化成可执行代码。
1. 预处理
首先,C预处理器拓展源代码,插入所有用#include 命令指定的文件,并拓展所有用#define声明指定的宏。
2. 编译
然后,编译器产生两个源代码的汇编代码,名字分别是p1.s和p2.s。
3. 汇编
接下来,汇编语言将汇编代码转换成二进制目标代码,文件名为p1.o和p2.o。目标代码是机器代码的一种形式,它包含所有指令的二进制表示,但是还没有填入地址的全局值。
4. 链接
最后,链接器将两个目标代码文件与实现库函数(例如printf)的代码合并,并产生最终的可执行代码文件p。
IA32机器代码和原始的C代码差别非常大,一些通常对C语言程序员隐藏的处理器状态是可见的:程序计数器(在IA32中用%eip表示)、整数寄存器文件、条件码寄存器等。
在命令行上使用“-S”选项,就能得到C语言编译器产生的汇编代码:
unix> gcc -01 -S code.c
- 1
这会使GCC运行编译器,产生一个汇编文件code.s,但是不做其他进一步的工作。
如果我们使用“-c”命令行选项,GCC会编译并汇编该代码:
unix> gcc -01 -c code.c
- 1
这就会产生目标代码文件code.o,它是二进制格式,所以无法直接查看。机器实际执行的程序只是对一系列指令进行编码的字节序列,机器对产生这些指令的源代码一无所知。
要查看目标代码文件的内容,最有价值的是反汇编器,它是基于机器代码文件中的字节序列来确定汇编代码。
生成一个实际可执行的代码需要对一组目标文件运行链接器,而这组目标代码文件中必须含有一个main函数。假设在文件main.c中有下面这样的函数:
int main() {
return sum(1,3);
}
- 1
- 2
- 3
然后,用如下方法生成可执行文件prog:
unix> gcc -01 -o prog code.o main.c
- 1
生成的prog不仅包含两个过程的代码,还包含了用来启动和终止程序的信息,以及用来与操作系统交互的信息。
控制
循环
C语言提供了多种循环结构,即do-while、while和for。汇编中用条件测试和跳转结合起来实现。大多数汇编器根据一个循环的do-while形式来产生循环代码,即使do-while的形式用得相对较少。其他的循环会首先转换成do-while形式,然后再编译成机器代码。首先从do-while开始。
do-while循环
do-while的通用形式可以翻译成如下所示的条件和goto语句:
loop:
body-statement
t=test-expr;
if(t)
goto loop;
- 1
- 2
- 3
- 4
- 5
每次循环,程序会执行循环体内的语句,然后执行测试表达式。如果测试为真,则回去再执行一次循环。
while循环
将while循环翻译成机器代码有很多种方法,常见的是使用条件分支,在需要时省略循环体的第一次执行,从而将代码转换成do-while循环,如下:
if(!test-expr)
goto done;
do
body-statement
while (test-expr);
done:
- 1
- 2
- 3
- 4
- 5
- 6
接下来,这个代码可以直接翻译成goto代码,如下:
t=test-expr;
if(!t)
goto done;
loop:
body-statement
t=test-expr;
if(t)
goto loop;
done:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
for循环
for循环可以很容易转换成while循环,进而转换成do-while形式:
init-expr;
if(!test-expr)
goto done;
do {
body-statement
update-expr;
} while (test-expr);
done:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
然后,将它转换成goto代码:
init-expr;
t=test-expr;
if(!t)
goto done;
loop:
body-statement
update-expr;
t=test-expr;
if(t)
goto loop;
done:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
<link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/markdown_views-ea0013b516.css">
</div>