C运行时库中的R_386_32类型符号是什么?

时间:2018-10-03 10:16:06

标签: assembly compilation x86 binary crt

我读了Here
据我了解,R_386_32用于静态数据,R_386_PC32用于功能。对吧?

但是我仍然对R_386_32类型符号的用法感到困惑。
请参见以下示例。

示例1

readelf -a --wide /usr/lib/i386-linux-gnu/crt1.o | grep R_386_32
0000000c  00000901 R_386_32               00000000   __libc_csu_fini
00000011  00000b01 R_386_32               00000000   __libc_csu_init
00000018  00000c01 R_386_32               00000000   main

示例2

readelf -a --wide /usr/local/lib/gcc/i686-pc-linux-gnu/5.5.0/crtbegin.o 
00000001  00001501 R_386_32               00000000   __TMC_END__
00000010  00001601 R_386_32               00000000   _ITM_deregisterTMCloneTable
00000031  00001501 R_386_32               00000000   __TMC_END__
00000049  00001701 R_386_32               00000000   _ITM_registerTMCloneTable
000000a1  00001901 R_386_32               00000000   _Jv_RegisterClasses


问题

  1. 示例2 中,R_386_32类型的数据会自动添加到 Application
    在编译时?
  2. 如果可以,我可以在代码中引用这些数据吗?
    例如,我可以使 Application 用作printf的值为_Jv_RegisterClasses吗?
  3. 示例1 中,为什么 main R_386_32类型?
    我认为应该是R_386_PC32,因为它不是静态数据,而是函数。

1 个答案:

答案 0 :(得分:3)

您正在查看的是重定位,不是符号。重定位只是汇编器要引用其值未知的符号时生成的内容。这是指示链接器在链接时填写正确的值。重定位不是符号类型;可以通过任意数量的任意类型的重定位来引用每个符号。还要注意,符号表根本不知道符号所指的是什么类型的基准。符号只是地址和名称。

重定位类型R_386_32的意思是“在此处将符号的值粘贴为32位。”无法说出所使用的符号是用于数据还是文本。例如,如果您加载符号的地址或执行绝对存储器访问,则使用此方法。这两条指令都生成R_386_32重定位:

mov $foo, %eax       # move value of symbol to register
mov foo, %eax        # perform absolute memory access

另一方面,重定位类型R_386_PC32从符号中减去指令指针的值( p rogram c unter)并将其粘贴。此重定位类型主要用于直接跳转和调用指令:

jmp foo              # jump to foo
call foo             # call foo

通常,无法通过查看重定位来猜测符号定义在哪个节中。实际上,重定位根本不提供任何有关此的信息,并且目标文件不能要求外部符号引用数据或文本。对于已定义的符号,您可以通过运行nm实用程序来找出它们所在的部分。标记为tT的符号是文本,dD是数据,rR是只读数据,{{ 1}}或b是BSS。

第二个问题:是的,可以。使用这样的C代码来打印B的值。请注意,符号的值是它所引用的变量的地址。

_Jv_RegisterClasses