ELF动态符号表 [英] ELF dynamic symbol table

查看:214
本文介绍了ELF动态符号表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

编辑:这是readelf的输出--dyn -syms prog1

 符号表'.dynsym'包含5个条目:
编号:值大小类型绑定Vis Ndx名称
0:00000000 0 NOTYPE LOCAL DEFAULT UND
1:00000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
2:000082f0 0 FUNC GLOBAL DEFAULT UND printf@GLIBC_2.4(2)
3:00008314 0 FUNC GLOBAL DEFAULT UND abort@GLIBC_2.4(2)
4:000082fc 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.4

这里的 printf符号是82f0,恰好是printf的plt表项的地址。



readelf的输出--dyn-syms prog2

 符号表'.dynsym'包含6个条目:
编号:值大小类型绑定Vis Ndx名称
0:00000000 0 NOTYPE LOCAL DEFAULT UND
1:00000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
2:00000000 0 FUNC GLOBAL DEFAULT UND puts@GLIBC_2.4(2)
3:00000000 0 FUNC GLOBAL DEFAULT UND printf@GLIBC_2.4(2)
4: 00000000 0 FUNC GLOBAL DEFAULT UND abort@GLIBC_2.4(2)
5:00000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.4

这里所有符号的值都是零。 x86_64 SV ABI 要求(强调我的):


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


使用我的GCC,这个程序:

  #include< stdio.h> 

int main()
{
printf(hello%i \\\
,42);
返回0;
}

直接编译为可执行文件时会生成一个空值:

  1:0000000000000000 0 FUNC GLOBAL DEFAULT UND printf@GLIBC_2.2.5(2)

但是这个程序与 printf 函数的比较:

  #include< stdio.h> 

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

产生一个非空值:

  3:0000000000400410 0 FUNC GLOBAL DEFAULT UND printf@GLIBC_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 重定位引起的。


I have a question about ELF dynamic symbol table. For symbols of type FUNC, I have noticed a value of 0 in some binaries. But in other binaries, it has some non-zero value. Both these binaries were generated by gcc, I want to know why is this difference?. Is there any compiler options to control this?

EDIT: This is the output of readelf --dyn-syms prog1

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 printf@GLIBC_2.4 (2)
 3: 00008314     0 FUNC    GLOBAL DEFAULT  UND abort@GLIBC_2.4 (2)
 4: 000082fc     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@GLIBC_2.4 

Here value of "printf" symbol is 82f0 which happens to be the address of plt table entry for printf.

Output of 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 puts@GLIBC_2.4 (2)
 3: 00000000     0 FUNC    GLOBAL DEFAULT  UND printf@GLIBC_2.4 (2)
 4: 00000000     0 FUNC    GLOBAL DEFAULT  UND abort@GLIBC_2.4 (2)
 5: 00000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@GLIBC_2.4 

Here the values for all the symbols are zero.

解决方案

The x86_64 SV ABI mandates that (emphasis mine):

To allow comparisons of function addresses to work as expected, if an executable file references a function defined in a shared object, the link editor will place the address of the procedure linkage table entry for that function in its associated symbol table entry. This will result in symbol table entries with section index of SHN_UNDEF but a type of STT_FUNC and a non-zero st_value. A reference to the address of a function from within a shared library will be satisfied by such a definition in the executable.

With my GCC, this program:

#include <stdio.h>

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

when compiled directly into an executable generates a null value:

 1: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND printf@GLIBC_2.2.5 (2)

But this program with a comparison of the printf function:

#include <stdio.h>

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

generates a non-null value:

 3: 0000000000400410     0 FUNC    GLOBAL DEFAULT  UND printf@GLIBC_2.2.5 (2)

In the .o file, the first program generates:

000000000014  000a00000002 R_X86_64_PC32     0000000000000000 printf - 4

and the second:

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

The difference is caused by the extra R_X86_64_32 relocation for getting the address of the function.

这篇关于ELF动态符号表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆