- 出版者的话
- 中文版序一
- 中文版序二
- 译者序
- 前言
- 关于作者
- 第 1 章:计算机系统漫游
- 第 2 章:信息的表示和处理
- 第 3 章:程序的机器级表示
- 第 4 章:处理器体系结构
- 第 5 章:优化程序性能
- 第 6 章:存储器层次结构
- 第 7 章:链接
- 第 8 章:异常控制流
- 第 9 章:虚拟内存
- 第 10 章:系统级 I/O
- 第 11 章:网络编程
- 第 12 章:并发编程
- 附录 A:错误处理
- 实验 1:Data Lab
- 实验 3:Attack Lab
- 实验 4:Architechture Lab
- 实验 5:Cache Lab
- 实验 6:Performance Lab
- 实验 7:Shell Lab
- 实验 8:Malloc Lab
- 实验 9:Proxy Lab
7.1 编译器驱动程序
考虑图 7-1 中的 C 语言程序。它将作为贯穿本章的一个小的运行示例,帮助我们说明关于链接是如何工作的一些重要知识点。
int sum(int *a, int n);
int array[2] = {1, 2};
int main()
{
int val = sum(array, 2);
return val;
}
int sum(int *a, int n)
{
int i, s = 0;
for (i = 0; i < n; i++) {
s += a[i];
}
return s;
}
图 7-1 示例程序 1。这个示例程序由两个源文件组成,main.c 和 sum.c。main 函数初始化一个整数数组,然后调用 sum 函数来对数组元素求和
大多数编译系统提供编译器驱动程序(compiler driver),它代表用户在需要时调用语言预处理器、编译器、汇编器和链接器。比如,要用 GNU 编译系统构造示例程序,我们就要通过在 shell 中输入下列命令来调用 GCC 驱动程序:
linux> gcc -Og -o prog main.c sum.c
图 7-2 概括了驱动程序在将示例程序从 ASCII 码源文件翻译成可执行目标文件时的行为。(如果你想看看这些步骤,用 -v 选项来运行 GCC。)驱动程序首先运行 ✦C 预处理器(cpp)✦,它将 C 的源程序 main.c 翻译成一个 ASCII 码的中间文件 main.i:
cpp [other arguments] main.c /tmp/main.i
✦C 预处理器(cpp)✦:在某些 GCC 版本中,预处理器被集成到编译器驱动程序中。
接下来,驱动程序运行 C 编译器(cc1),它将 main.i 翻译成一个 ASCII 汇编语言文件 main.s:
cc1 /tmp/main.i -Og [other arguments] -o /tmp/main.s
然后,驱动程序运行汇编器(as),它将 main.s 翻译成一个可重定位目标文件(relocatable object file)main.o:
as [other arguments] -o /tmp/main.o /tmp/main.s
驱动程序经过相同的过程生成 sum.o。最后,它运行链接器程序 ld,将 main.o 和 sum.o 以及一些必要的系统目标文件组合起来,创建一个可执行目标文件(executable object file)prog:
ld -o prog [system object files and args] /tmp/main.o /tmp/sum.o
要运行可执行文件 prog,我们在 Linux shell 的命令行上输入它的名字:
linux> ./prog
shell 调用操作系统中一个叫做加载器(loader)的函数,它将可执行文件 prog 中的代码和数据复制到内存,然后将控制转移到这个程序的开头。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论