elf文件格式与动态链接库(大地小神之个人收藏)

elf文件格式与动态链接库(非常之好)

机器执行的是机器指令,而机器指令就是一堆二进制的数字。高级语言编写的程序之所以可以在不同的机器上移植就因为有为不同机器设计的编译器的存在。高级语言的编译器就是把高级语言写的程序转换成某个机器能直接执行的二进制代码。以上的知识在我们学习CS(Computer Science)的初期,老师都会这么对我们讲。但是我就产生疑问了:

既然机器都是执行的二进制代码,那么是不是说只要硬件相互兼容,不同操作系统下的可执行文件可以互相运行呢?答案肯定是不行。这就要谈到可执行文件的格式问题。

每个操作系统都会有自己的可执行文件的格式,比如以前的Unix?是用a.out格式的,现代的Unix?类系统使用elf格式,WindowsNT?是使用基于COFF格式的可执行文件。那么最简单的格式应该是DOS的可执行格式,严格来说DOS的可执行文件没有什么格式可言,就是把二进制代码安顺序放在文件里,运行时DOS操作系统就把所有控制计算机的权力都给了这个程序。这种方式的不足之处是显而易见的,所以现代的操作系统都有一种更好的方式来定义可执行文件的格式。一种常见的方法就是为可执行文件分段,一般来说把程序指令的内容放在.text段中,把程序中的数据内容放在.data段中,把程序中未初始化的数据放在.bss段中。这种做法的好处有很多,可以让操作系统内核来检查程序防止有严重错误的程序破坏整个运行环境。比如:

某个程序想要修改.text段中的内容,那么操作系统就会认为这段程序有误而立即终止它的运行,因为系统会把.text段的内存标记为只读。在.bss段中的数据还没有初始化,就没有必要在可执行文件中浪费储存空间。在.bss中只是表明某个变量要使用多少的内存空间,等到程序加载的时候在由内核把这段未初始化的内存空间初始化为0。这些就是分段储存可执行文件的内容的好处。

下面谈一下Unix系统里的两种重要的格式: a.out和elf

1 / 14

(Executable and Linking Format)。这两种格式中都有符号表(symboltable),其中包括所有的符号(程序的入口点还有变量的地址等等)。

在elf格式中符号表的内容会比a.out格式的丰富的多。但是这些符号表可以用strip工具去除,这样的话这个文件就无法让debug程序跟踪了,但是会生成比较小的可执行文件。a.out文件中的符号表可以被完全去除,但是elf中的在加载运行时起着重要的作用,所以用strip永远不可能完全去除elf格式文件中的符号表。但是用strip命令不是完全安全的,比如对未连接的目标文件来说如果用strip去掉符号表的话,会导致连接器无法连接。例如:

代码: $:

gcc -c hello.c $:

ls hello.c hello.o

用gcc把hello.c编译成目标文件hello.o 代码: $:

strip hello.o

用strip去掉hello.o中的符号信息。 代码: $:

gcc hello.o /usr/lib/crt

1.o /usr/lib/crti.o /usr/lib/crtn.o–o hello/*

2 / 14

$:

gcc hello.o /usr/lib/gcc/i686-pc-linux-gnu/ 3.4.5/../../../crt

1.o7: In function `_start': init.c:

(.text+0x18): undefined reference to `main' collect2: ld returned 1 exit status */

再用gcc连接时,连接器ld报错。说明在目标文件中的符号起着很重要的作用,如果要发布二进制的程序的话,在debug后为了减小可执行文件的大小,可以用strip来除去符号信息但是在程序的调试阶段还是不要用strip为好。

在接下去讨论以前,我们还要来讲讲relocations的概念: 首先有个简单的程序hello.c 代码: $: cat hello.c

main( ){printf(\当我们把hello.c编译为目标文件时,我们并没有在源文件中定义printf这个函数,所以汇编器也不知道printf这个函数的具体的地址,所以在目标文件中就会留下printf这个符号。以下的工作就交给连接器了,连接器会找到这个函数的入口地址然后传递给这个文件最终形成可执行文件,这个过程就叫做relocations。a.out格式的可执行文件是没有这种relocation的功能的,内核不会执行其中还有未知函数的入口地址的可执行文件的。在目标文件中当然可以relocation,只不过连接器需要把未知函数的入口地址完全找到,生成可执行文件才行。这样就有一个很尴尬的问题,在a.out格式中极其难以实现动态连接技术。要知道为什么现在的Unix几乎都是用的elf格式的可执行文件就要了解a.out格式的短处。

3 / 14

联系客服:779662525#qq.com(#替换为@) 苏ICP备20003344号-4