欢迎光临我的博客
分类: LINUX
2010-08-06 13:21:08
本版UNIX的可执行文件是.out格式,如果你在UNIX下用gcc编译程序,它默认会生成一个名为“a.out”的可执行文件。尽管现在的UNIX/Linux基本上用ELF(EXECUTABLE
AND LINKABLE FORMAT)代替了.out做为可执行(以及目标和库)文件的标准格式,而且ELF对于动态链接、扩展库和面向对象语言(比如C++)有着更好的支持,但作为一个时代的标记,.out文件曾经扮演过重要的角色,而且ELF也由它发展而来,因此了解.out的格式是很有意义的。
.out文件最多可包含七个部分:可执行头(exec header)、程序段(Text segment)、数据段(data segment)、程序重定向表(text relocation)、数据重定向表(data relocation)、符号表(symbol table)和字符串表(string table)如图11-1所示。
图11-1 .out文件格式
其中只有可执行头是必须的,其他段都是可选的。
其结构定义如下:
struct exec {
unsigned long
a_midmag;
unsigned long a_text;
unsigned
long a_data;
unsigned
long a_bss;
unsigned
long a_syms;
unsigned
long a_entry;
unsigned
long a_trsize;
unsigned
long a_drsize;
};
对于16位CPU,它占用16字节,对于32位CPU,占用32字节。
—
a_midmag
a_midmag是魔术数,它标识了可执行文件的格式,取值如下:
#define OMAGIC
0407 /* old impure format */
#define NMAGIC
0410 /* read-only text */
#define ZMAGIC 0411 /* demand load format */
#define QMAGIC 0314
/* "compact" demand load
format */
OMAGIC表示程序段是可写的,在空间上和数据段连续。
NMAGIC表示程序段是只读的,并且空间上和数据段不连续,它和数据段的起始地址都是8K边界。
ZMAGIC表示程序段和数据段是通过两套活动页寄存器映射的,程序段是只读的。
QMAGIC目前还不支持。
—
a_text
程序段(text segment)大小,字节数。
—
a_data
已初始化的数据段大小。
—
a_bss
未初始化的数据段大小(bss = block started by symbol)。
—
a_syms
符号表(symbol table)大小,字节数。
—
a_entry
程序入口地址。
—
a_trsize
程序重定向表(text relocation)大小。
—
a_drsize
数据重定向表(data relocation)大小。
编译后的机器代码,它从0地址开始,只读。
它包含了已初始化的全局变量值。未初始化的全局变量并不在可执行文件中记录,而会在创建对应进程时分配空间,而因为没有初值,所以不需要记录。
它记录了程序段中哪些符号(全局变量和函数)需要重定向,链接器(link editor)会根据该表和符号表来设定它们的绝对地址,因为这在编译阶段是不可能知道的。
比如,有一段代码在main.c中:
int xx, yy;
void main()
{
xx = 1;
yy = 2;
}
在编译(还未链接)后,其汇编代码如下:
.globl _main
_main:
mov &xx, R0
mov 1, (R0)
mov &yy, R1
mov 2, (R1)
rts PC
由于还未链接,xx、yy的空间还未被分配,所以&xx、&yy用其他值比如0代替,并把它们记录到程序重定向表中,它们会在链接阶段被替换为真正的地址。
图11-2 程序对应机器指令
目标文件main.o中的代码(数据)重定向记录结构如下:
struct
relocation_info
{
int r_address;
unsigned int r_symbolnum : 24,
r_pcrel : 1,
r_length : 2,
r_extern : 1,
r_baserel : 1,
r_jmptable : 1,
r_relative : 1,
r_copy : 1;
};
(1)r_address
它表示需要重定向的符号相对于代码段(或数据段)的偏移量,字节数。上例中&xx对应值就是2,而&yy是10。