最近打算巩固计算机基础知识,网上一本评价极高的教材—— 深入理解计算机系统 ,下面要将讲的内容来自第一章一个小例子,不过对我们了解C语言如何从源程序到最终的可执行程序很有帮助,下面让我们开始吧。
首先一个简单的C语言版本的hello world例子,保存在文件 hello.c
中。
#include <stdio.h> int main() { printf("hello world/n"); }
一般而言,我们通常可以使用 gcc
命令将其转化为可执行程序
gcc -o hello hello.c
执行上面命令后,就会在当前目录生产一个 hello
的可执行文件。在 Centos 64位
机器上执行 file hello
,可以得到
hello: ELF 64-bit LSB executable, AMD x86-64, version 1 (SYSV), for GNU/Linux 2.6.9, dynamically linked (uses shared libs), not stripped
直接执行 ./hello
即可在控制台输出 hello world
。
为了说明C语言源程序是如何转化为最终的可执行文件,首先看下面这个图
下面来分布讲解
这个阶段处理 #
开头的指示语句, hello.c
中的 #include<stdio.h>
告知预处理器去加载 stdio.h
的内容,并把它插入到当前位置。
cpp hello.c > hello.i file hello.i # hello.i: ASCII C program text
这个阶段把C语言源程序编译为汇编程序,不同高级语言经由其编译器处理后,得到的同样的汇编语言。
cc -S hello.i #会生成 hello.s 文件 file hello.s # hello.s: ASCII assembler program text
这一阶段把汇编语言翻译为机器码,结果保存在称为 relocatable object program/file
的文件中,一般以 .o
结尾。
as -o hello.o hello.s file hello.o # hello.o: ELF 64-bit LSB relocatable, AMD x86-64, version 1 (SYSV), not stripped
注意到我们的 hello.c
程序使用了 printf
函数,它是由C语言的标准库函数,由C语言编译器提供, printf
函数应该会存在于一个 printf.o
的文件中,我们需要某种手段把它合并到我们的 hello.o
中,链接器就是做这件事的。最终生成的为一个称为 executable object file
的文件,它可以被装载进内存并且执行。