【发布时间】:2014-08-30 14:33:07
【问题描述】:
elf格式的可执行文件和elf格式的可重定位文件有什么区别?
【问题讨论】:
标签: elf
elf格式的可执行文件和elf格式的可重定位文件有什么区别?
【问题讨论】:
标签: elf
正如您所知,每个编译的可执行文件都是具有相对地址和绝对地址的二进制文件,因此可重定位格式是一种格式,其中函数和其他符号仍然有名称定义,换句话说,函数和变量不绑定到任何特定地址.相反,地址仍然是符号
看:
unix > gcc -c main.c
unix > readelf --symbols main.o
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000000 0 FILE LOCAL DEFAULT ABS main.c
2: 00000000 0 OBJECT GLOBAL DEFAULT 3 buf
3: 00000000 0 OBJECT GLOBAL DEFAULT 1 main
unix > gcc main.c -o main
unix > readelf --symbols main
Num: Value Size Type Bind Vis Ndx Name
53: 08048460 2 FUNC GLOBAL DEFAULT 13 __libc_csu_fini
54: 08048462 0 FUNC GLOBAL HIDDEN 13 __i686.get_pc_thunk.bx
55: 0804a018 4 OBJECT GLOBAL DEFAULT 13 bufp0
你明白我在说什么
大部分时间我们将它们用作静态库
看这里的例子:
#ifndef MATH_H
#define MATH_H
int add(int a, int b);
#endif
/* math_test.c */
#include <stdio.h>
#include "math.h"
int main(void)
{
int result = add(1, 2);
printf("result: %d\n", result);
return 0;
}
尝试编译它
unix > gcc math_test.c -o math_test
/tmp/cclRibQq.o: In function `main':
math_test.c:(.text+0x19): undefined reference to `add'
collect2: ld returned 1 exit status
由于add 函数在math_test.c 中没有主体,所以我们可以进行流动:
int add(int a, int b)
{
return a + b;
}
然后使用 gcc 将其编译为可重定位文件
unix > gcc -c math.c # Create relocatable obj file (math.o)
unix > readelf -h math.o | grep Type # Read math.o with readelf
Type: REL (Relocatable file) # and verify its type
然后你可以用这样的链接器链接它:
unix > gcc math_test.c math.o -o math_test
unix > ./math_test
result: 3
一篇关于elf格式的可执行文件和elf格式的可重定位文件的区别的好文章你可以找到here
【讨论】:
Relocatable 没有任何加载地址,它只有带有偏移量的二进制代码序列(例如与 main() 函数相关的偏移量)。但是,具有加载地址的可执行文件不仅仅是与任何函数相关的偏移量。
它们之间的一个更根本的区别是 Executable 有引导应用程序,但 relocatable 没有它。
【讨论】:
如下图所示,可重定位的 ELF 作为链接器的输入,而可执行的 ELF 是链接器的产物。
【讨论】:
ELF 可执行文件,我们从它的名字就可以理解,是一个可以执行的文件。例如,该文件可以从 C 代码生成。
重定位的过程是固定在代码中创建的标签和符号的地址。例如,如果您用汇编语言编写程序并查看源代码的列表文件,您会发现有些地方写了 [00000000] 而不是这一行提到的标签。这个零表示链接器使用重定位来修复地址的未来值。
【讨论】: