首页 > 代码库 > C语言之a.out简介

C语言之a.out简介

在Linux下编译链接程序时,如果不用‘-o’选项来指定输出文件名称,默认情况下就会输出名为‘a.out’的文件。为什么默认是‘a.out’而不是别的名称呢?这是一个历史遗留问题。

在早期的BSD文档里有下面的提示:

a.out     ——   汇编程序和链接编辑输出格式。

可以看出它是一种输出格式,与EFL格式、二进制格式等是并列的。a.out是‘assembler output(汇编程序输出)’的缩写形式。以前并不存在连接器,程序一般是这样创建的:先把所有源文件连接在一起,然后进行汇编,汇编产生的汇编程序输出保存在a.out中。等有了连接器后,仍然保留了“输出文件默认为a.out”的命名习惯。

现在,a.out被普遍使用的ELF格式所替代,但输出文件名仍旧是a.out。我们看到的a.out只是一个可执行文件,而不再是文件格式。ELF可执行文件的第一个字节是八进制177,紧跟其后的2、3、4字节是ELF三个字母。可输入od -c a.out | head 查看。


既然是一种输出格式,那么它都是由哪几部分组成的呢?它一般由下面几部分组成:

执行头部:包含内核将二进制文件加载内存并执行所需的参数,也包含对链接编辑器ld的指引。

文本段:包含运行时被载入内存的机器码的相关数据,可能是只读的。

数据段:包含已初始化的数据,总是可写的。

文本重定位:包含链接编辑器在合并二进制文件时修改文件段指针的记录。

数据重定位:与文本重定位类似,但是给数据段指针用。

符号表:包含链接编辑器用于交叉引用不同二进制文件中变量和函数的记录。

字符串表:包含对应于符号表的字符串。

以一个程序out.c为例分析各部分会出现在哪些段中:

#include <malloc.h>

char pear[40];
static double peach;

int    mango = 13;
static long melon = 2001;

void
main()
{
    int i = 3, j, *ip;

    ip = malloc(sizeof(i));
    pear[5] = i;
    peach = 2.0 * mango;
}

图 out.c程序语句的各部分会出现在哪些段中
操作系统在a.out文件里干了些什么?
为什么a.out要以段的形式组织。段可以方便地映射到链接器在运行时可以直接载入的对象中。载入器只是取文件中每个段的映像,并直接将它们放入内存中,从本质上说,段在正在执行的程序中是一块内存区域,每个区域都有特定的目的。
文本段包含程序的指令。连接器把指令直接从文件拷贝到内存中,以后便再也不用管它。数据段包含经过初始化的全局和静态变量以及它们的值。BSS段的大小从可执行文件中得到,然后链接器得到这个大小的内存块,紧跟在数据段之后。