如果不指定编链后的文件名,linux会自动产生一个a.out的文件,大概是汇编输出的意思,实际上这是链接之后的输出,而不是汇编之后的输出,之所以这样是个历史遗留问题。
a.out文件除去魔术数字等东西,我们最关心的是程序中各个段的分配。一个程序文件一般会分成这样几个区域:
text,data,bss段
text指的是程序文本文件
data指的是所有的经过初始化后的全局变量和静态变量
bss段则是未经初始化的全局变量和静态变量,但是bss段不增加目标文件的大小,一般只是记录bss段的大小。
由const修饰的变量将存放于text文件之中。局部变量放在栈中。
例如
char a[100];
char b[100]= {100};
static int c;
static int d;
const int e = 5000;
void foo()
{
static int tmp1;
static int tmp2 = 1;
char i;
}
int main()
{
int i;
printf("hello,world!/n");
。。。。。。
}
此程序中,a[100],c,tmp1位于bss段,它们没有被初始化。
b[100],d,tmp2 位于data段,因为他们是已经初始化后的全局变量;
e 和main函数位于text文件中,e是const修饰的变量。
i则位于栈中。
在linux环境下,size a.out就可以查看各个部分的大小
一个二进制可执行(或其他相关)文件包括以下7个部分(sections)
exec header: 放有用来被操作系统载入到内存和执行,以及被ld用来进行和其他文件合并的参数。这个部分是托管的。
text segment: 放置机器码和相关数据,在程序执行的时候被载入内存,并且只读
data segment: 放置已初始化数据,被载入到内存中可写位置
text relocations: 放置编译相关的一些数据,现在不太明白
data relocations: 跟text relocation字段差不多,只不过是针对data segment的。
symbol table: 保存了命名变量以及函数符号的记录;被编译器用来在二进制文件中交叉引用这些命名变量或者函数的地址
string table: 保存对应符号名称的字符串
3.bss段和.data段的区别
【例一】
用cl编译两个小程序如下:
程序1:
int ar[30000];
void main()
{
}
程序2:
int ar[300000] =
void main()
{
}
发现程序2编译之后所得的.exe文件比程序1的要大得多。当下甚为不解,于是手工编译了一下,并使用了/FAs编译选项来查看了一下其各自的.asm,发现在程序1.asm中ar的定义如下:
_BSS SEGMENT
_BSS ENDS
而在程序2.asm中,ar被定义为:
_DATA SEGMENT
_DATA ENDS
区别很明显,一个位于.bss段,而另一个位于.data段,两者的区别在于:全局的未初始化变量存在于.bss段中,具体体现为一个占位符;全局的已初始化变量存于.data段中;而函数内的自动变量都在栈上分配空间。.bss是不占用.exe文件空间的,其内容由操作系统初始化(清零);而.data却需要占用,其内容由程序初始化,因此造成了上述情况。
【例二】
编译如下程序(test.cpp):
#include <stdio.h>
#define LEN 1002000
int inbss[LEN];
float fA;
int indata[LEN]={1,2,3,4,5,6,7,8,9};
double dbB = 100.0;
const int cst = 100;
int main(void)
{
}
命令:cl /FA
产生的汇编代码(test.asm):
include listing.inc
if @Version gt 510
.model FLAT
else
_TEXT
_TEXT
_DATA
_DATA
CONST
CONST
_BSS
_BSS
_TLS
_TLS
FLAT
endif
PUBLIC
PUBLIC
PUBLIC
PUBLIC
_BSS
?inbss@@3PAHA DD 0f4a10H DUP (?)
?fA@@3MA DD
_BSS
_DATA
?indata@@3PAHA DD 01H
?dbB@@3NA DQ
_DATA
PUBLIC
EXTRN
_DATA
$SG537
_DATA
_TEXT
_run$ = -400
_i$ = -404
_main
; File test.cpp
; Line 13
; Line 14
; Line 15
$L535:
$L534:
; Line 16
$L536:
; Line 17
; Line 18
_main
_TEXT
END
通过汇编文件可以看到,数组inbss和indata位于不同的段(inbss位于bss段,而indata位于data段)
若把test.cpp中的indata数组拿掉,查看生成的exe文件的大小,可以发现,indata拿掉之后exe文件的大小小了很多。而若拿掉的是inbss数组,exe文件大小跟没拿掉时相差无几。
说明了:
bss段(未手动初始化的数据)并不给该段的数据分配空间,只是记录数据所需空间的大小。
data(已手动初始化的数据)段则为数据分配空间,数据保存在目标文件中。
数据段包含经过初始化的全局变量以及它们的值。BSS段的大小从可执行文件中得到,然后链接器得到这个大小的内存块,紧跟在数据段后面。当这个内存区进入程序的地址空间后全部清零。包含数据段和BSS段的整个区段此时通常称为数据区。
来自http://hi.baidu.com/workbench/blog/item/f98401a8396eebb0ca130cf3.html