如果不指定编链后的文件名,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] = {1, 2, 3, 4, 5, 6 };
void main()
{
......
}
发现程序2编译之后所得的.exe文件比程序1的要大得多。当下甚为不解,于是手工编译了一下,并使用了/FAs编译选项来查看了一下其各自的.asm,发现在程序1.asm中ar的定义如下:
_BSS SEGMENT
?ar@@3PAHA DD 0493e0H DUP (?) ; ar
_BSS ENDS
而在程序2.asm中,ar被定义为:
_DATA SEGMENT
?ar@@3PAHA DD 01H ; ar
DD 02H
DD 03H
ORG $+1199988
_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)
{
int run[100] = {1,2,3,4,5,6,7,8,9};
for(int i=0; i<LEN; ++i)
printf("%d ", inbss[i]);
return 0;
}
命令:cl /FA test.cpp 回车 (/FA:产生汇编代码)
产生的汇编代码(test.asm):
TITLE test.cpp
.386P
include listing.inc
if @Version gt 510
.model FLAT
else
_TEXT SEGMENT PARA USE32 PUBLIC 'CODE'
_TEXT ENDS
_DATA SEGMENT DWORD USE32 PUBLIC 'DATA'
_DATA ENDS
CONST SEGMENT DWORD USE32 PUBLIC 'CONST'
CONST ENDS
_BSS SEGMENT DWORD USE32 PUBLIC 'BSS'
_BSS ENDS
_TLS SEGMENT DWORD USE32 PUBLIC 'TLS'
_TLS ENDS
FLAT GROUP _DATA, CONST, _BSS
ASSUME CS: FLAT, DS: FLAT, SS: FLAT
endif
PUBLIC ?inbss@@3PAHA ; inbss
PUBLIC ?fA@@3MA ; fA
PUBLIC ?indata@@3PAHA ; indata
PUBLIC ?dbB@@3NA ; dbB
_BSS SEGMENT
?inbss@@3PAHA DD 0f4a10H DUP (?) ; inbss
?fA@@3MA DD 01H DUP (?) ; fA
_BSS ENDS
_DATA SEGMENT
?indata@@3PAHA DD 01H ; indata
DD 02H
DD 03H
DD 04H
DD 05H
DD 06H
DD 07H
DD 08H
DD 09H
ORG $+4007964
?dbB@@3NA DQ 04059000000000000r