C 运行时库中的 R_386_32 类型符号是什么?
What is R_386_32 type symbols in C runtime library?
我读了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
问题
- 在示例 2 中,
R_386_32
键入的数据会自动添加到 Application
在编译时?
- 如果是,我可以在我的代码中引用这些数据吗?
例如,我可以使 printf 的 Application 成为 _Jv_RegisterClasses
的值吗?
- 在示例1中,为什么main是
R_386_32
类型?
我觉得应该是R_386_PC32
,因为不是静态数据,是函数。
您正在查看 重定位, 而不是 符号。 重定位正是汇编程序在要引用其符号时生成的内容价值未知;这是对 link 人员的指示,要求他们在 link 时填写正确的值。重定位不是符号类型;每个符号都可以通过任意数量的任意类型的重定位来引用。另请注意,符号 table 不知道符号引用的数据类型(如果有的话)。一个符号只是一个地址和一个名字。
重定位类型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
减去指令指针的值(program counter ) 从符号中粘贴。这种重定位类型主要用于直接跳转和调用指令:
jmp foo # jump to foo
call foo # call foo
通常,无法通过查看重定位来猜测符号定义在哪个部分。实际上,重定位根本不提供任何相关信息,并且目标文件不能要求外部符号引用数据或文本。对于已定义的符号,您可以通过 运行 和 nm
实用程序找出它们所在的部分。标记为t
或T
的符号是文本,d
或D
是数据,r
或R
是只读数据,b
或 B
是 BSS。
对于你的第二个问题:是的,你可以。使用这样的 C 代码打印 _Jv_RegisterClasses
的值。注意一个符号的值是它所引用的变量的地址。
extern const void _Jv_RegisterClasses; /* or any other type */
printf("%p\n", &_Jv_RegisterClasses); /* print value of symbol */
我读了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
问题
- 在示例 2 中,
R_386_32
键入的数据会自动添加到 Application
在编译时? - 如果是,我可以在我的代码中引用这些数据吗?
例如,我可以使 printf 的 Application 成为_Jv_RegisterClasses
的值吗? - 在示例1中,为什么main是
R_386_32
类型?
我觉得应该是R_386_PC32
,因为不是静态数据,是函数。
您正在查看 重定位, 而不是 符号。 重定位正是汇编程序在要引用其符号时生成的内容价值未知;这是对 link 人员的指示,要求他们在 link 时填写正确的值。重定位不是符号类型;每个符号都可以通过任意数量的任意类型的重定位来引用。另请注意,符号 table 不知道符号引用的数据类型(如果有的话)。一个符号只是一个地址和一个名字。
重定位类型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
减去指令指针的值(program counter ) 从符号中粘贴。这种重定位类型主要用于直接跳转和调用指令:
jmp foo # jump to foo
call foo # call foo
通常,无法通过查看重定位来猜测符号定义在哪个部分。实际上,重定位根本不提供任何相关信息,并且目标文件不能要求外部符号引用数据或文本。对于已定义的符号,您可以通过 运行 和 nm
实用程序找出它们所在的部分。标记为t
或T
的符号是文本,d
或D
是数据,r
或R
是只读数据,b
或 B
是 BSS。
对于你的第二个问题:是的,你可以。使用这样的 C 代码打印 _Jv_RegisterClasses
的值。注意一个符号的值是它所引用的变量的地址。
extern const void _Jv_RegisterClasses; /* or any other type */
printf("%p\n", &_Jv_RegisterClasses); /* print value of symbol */