2015-09-23 26 views
2

我有一个关于ELF动态符号表的问题。对于类型为FUNC的符号,我注意到某些二进制文件中的值为0。但在其他二进制文件中,它有一些非零值。这两个二进制文件都是由gcc生成的,我想知道为什么这个区别?有没有编译器选项来控制它?ELF动态符号表

编辑:这是readelf --dyn-SYMS的输出PROG1的 “printf的” 符号是82f0这恰好是对printf的PLT表项的地址

Symbol table '.dynsym' contains 5 entries: 
Num: Value Size Type Bind Vis  Ndx Name 
0: 00000000  0 NOTYPE LOCAL DEFAULT UND 
1: 00000000  0 NOTYPE WEAK DEFAULT UND __gmon_start__ 
2: 000082f0  0 FUNC GLOBAL DEFAULT UND [email protected]_2.4 (2) 
3: 00008314  0 FUNC GLOBAL DEFAULT UND [email protected]_2.4 (2) 
4: 000082fc  0 FUNC GLOBAL DEFAULT UND [email protected]_2.4 

这里值。 readelf --dyn-SYMS的

输出PROG2

Symbol table '.dynsym' contains 6 entries: 
Num: Value Size Type Bind Vis  Ndx Name 
0: 00000000  0 NOTYPE LOCAL DEFAULT UND 
1: 00000000  0 NOTYPE WEAK DEFAULT UND __gmon_start__ 
2: 00000000  0 FUNC GLOBAL DEFAULT UND [email protected]_2.4 (2) 
3: 00000000  0 FUNC GLOBAL DEFAULT UND [email protected]_2.4 (2) 
4: 00000000  0 FUNC GLOBAL DEFAULT UND [email protected]_2.4 (2) 
5: 00000000  0 FUNC GLOBAL DEFAULT UND [email protected]_2.4 

这里的值,所有符号都为零。

+0

什么是创建prog1和prog2的确切命令? – Jens

+0

prog2:gcc -o prog2 prog2.c。但关于prog1,我不知道。我想知道是否有任何选项来创建这样的二进制文件。 –

回答

1

通过观察上是不确定的一些二进制

所有功能运行readelf有大小为零。

这些未定义的函数是通过库调用的函数。在我小的ELF二进制glibc的所有引用是不确定的有21

它变得清晰,符号表可以有三种符号的页大小零

http://docs.oracle.com/cd/E19457-01/801-6737/801-6737.pdf。在这三种类型中,两种类型的未定义符号和暂定符号是那些未指定存储的符号。在稍后的情况下,你可以看到在readelf输出,一些功能不是未定义的(有索引),并没有存储。

为清楚起见,未定义的符号是那些被引用但未分配存储空间(尚未创建),而暂定符号是创建但未分配存储空间的符号。 e.g未初始化的符号

编辑

如果你正在谈论.PLT,共享库绑定符号是懒惰。

如何控制绑定看到http://www.linuxjournal.com/article/1060

此功能被称为延迟符号结合。这个想法是,如果你有很多的共享库,它可能需要动态装载器大量的时间来查找所有的函数来初始化所有的.plt插槽,所以最好将绑定地址延迟到函数直到我们实际上需要他们。如果你最终只使用共享库中的一小部分函数,​​这将是一个巨大的胜利。在将控制权转交给应用程序之前,可以指示动态加载程序将地址绑定到所有.plt插槽,这是通过在运行程序之前设置环境变量LD_BIND_NOW = 1来完成的。例如,在调试程序时,这在某些情况下非常有用。另外,我应该指出.plt是在只读内存中。因此,用于跳转目标的地址实际上存储在.got节中。 .got还包含一组指针,用于来自共享库的程序中使用的所有全局变量。

+0

这里我没有提到函数的大小,通过与GLIBC函数对应的动态符号的值,我指的是.PLT中的条目的地址,从该位置跳转到实际的glibc函数(通过libc。所以)。我注意到这个入口在一些二进制文件中是非零的。 –

+0

,因为共享库在运行时绑定地址而不是编译时。 – shami

+0

是的,但Dynamic FUNC符号的地址不是加载库例程的地址,而是相应libc例程的二进制文件中plt条目的地址。我将编辑我的问题以添加readelf --dyn-syms的屏幕截图,以使您相信。 –

2

x86_64 SV ABI强制要求(重点煤矿):

为了允许比较的功能地址以预期方式工作, 如果可执行文件引用 的在共享对象中所定义的函数,链接编辑器会将该函数的过程链接表 条目的地址放置在其关联的符号表项中。 这将导致符号表条目的段索引为 SHN_UNDEF,但一种类型的STT_FUNC和为非零st_value。 在共享的 库中对函数地址的引用将通过可执行文件中的这种定义来满足 。

用我GCC,此程序:

#include <stdio.h> 

int main() 
{ 
    printf("hello %i\n", 42); 
    return 0; 
} 

时,直接编译成可执行产生一个空值:

1: 0000000000000000  0 FUNC GLOBAL DEFAULT UND [email protected]_2.2.5 (2) 

但此方案与printf功能的比较:

#include <stdio.h> 

int main() 
{ 
    printf("hello %i\n", 42); 
    if (printf == puts) 
    return 1; 
    return 0; 
} 

产生非空值:

3: 0000000000400410  0 FUNC GLOBAL DEFAULT UND [email protected]_2.2.5 (2) 

在的.o文件,所述第一程序产生:

000000000014 000a00000002 R_X86_64_PC32  0000000000000000 printf - 4 

和第二:

000000000014 000a00000002 R_X86_64_PC32  0000000000000000 printf - 4 
000000000019 000a0000000a R_X86_64_32  0000000000000000 printf + 0 

的差由引起额外的R_X86_64_32重定位获取函数的地址。

相关问题