考虑下面的代码:
$ cat foo.c
static int foo = 100;
int function(void)
{
return foo;
}
字符串
我理解libfoo.so的解散
$ gcc -m32 -fPIC -shared -o libfoo.so foo.c
$ objdump -D libfoo.so
000004cc <function>:
4cc: 55 push %ebp
4cd: 89 e5 mov %esp,%ebp
4cf: e8 0e 00 00 00 call 4e2 <__x86.get_pc_thunk.cx>
4d4: 81 c1 c0 11 00 00 add $0x11c0,%ecx
4da: 8b 81 18 00 00 00 mov 0x18(%ecx),%eax
4e0: 5d pop %ebp
4e1: c3 ret
000004e2 <__x86.get_pc_thunk.cx>:
4e2: 8b 0c 24 mov (%esp),%ecx
4e5: c3 ret
4e6: 66 90 xchg %ax,%ax
...
000016ac <foo>:
16ac: 64 00 00 add %al,%fs:(%eax)
型
在function
中,foo
的地址计算为0x 4d 4(调用__x86.get_pc_thunk.cx
后ecx
的值)+ $0x11c0 + 0x 18 = 0x 16 ac。0x 16 ac是foo
的地址。
但是我不懂拆卸
$ gcc -m32 -fPIC -shared -c foo.c
$ objdump -D foo.o
00000000 <function>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: e8 fc ff ff ff call 4 <function+0x4>
8: 81 c1 02 00 00 00 add $0x2,%ecx
e: 8b 81 00 00 00 00 mov 0x0(%ecx),%eax
14: 5d pop %ebp
15: c3 ret
00000000 <foo>:
0: 64 00 00 add %al,%fs:(%eax)
00000000 <__x86.get_pc_thunk.cx>:
0: 8b 0c 24 mov (%esp),%ecx
3: c3 ret
型
为什么是call 4 <function+0x4>
和add $0x2,%ecx
?
更新:(在objdump中添加了-r标志,-R标志会产生错误not a dynamic object, Invalid operation
。
$ objdump -D -r foo.o
00000000 <function>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: e8 fc ff ff ff call 4 <function+0x4>
4: R_386_PC32 __x86.get_pc_thunk.cx
8: 81 c1 02 00 00 00 add $0x2,%ecx
a: R_386_GOTPC _GLOBAL_OFFSET_TABLE_
e: 8b 81 00 00 00 00 mov 0x0(%ecx),%eax
10: R_386_GOTOFF .data
14: 5d pop %ebp
15: c3 ret
型
现在4
在call 4 <function+0x4>
中是有意义的,因为这个指令在文本部分的偏移量是4。我仍然不知道为什么0x2
在add $0x2,%ecx
中。
1条答案
按热度按时间ntjbwcob1#
链接器将执行重定位,使得
final value
=symbol
+offset
-PC
。注意,这个公式中的PC
是重定位本身的地址,而不是指令的地址,因为链接器不知道指令边界。然而,汇编器知道它们,可以创建适当的偏移量。让我们看看
call __x86.get_pc_thunk.cx
是如何工作的。在x86上,call
指令使用相对寻址,但PC
的值已经递增以指向以下指令。您可以在第一次转储中验证这一点:字符串
注意指令中的偏移量是
0e
。已经递增的PC
是4d4
,并且可以肯定的是跳转的目标4e2
=4d4
+0e
(所有数字都是十六进制的)。现在是重定位的版本:
型
它使用
R_386_PC32
,但这是在指令的第二个字节,而call
需要从更新的PC
偏移,这显然是4
字节多。这意味着正确的结果是4
少,因此该指令包含fffffffc
,即-4
。注意,无论call
的地址是什么,这个偏移量总是-4
。反汇编程序会自动将其添加到更新的PC
中,在本例中是8
,因此通过执行8-4
,它到达call 4
。上一篇:
R_386_GOTPC
型
__x86.get_pc_thunk.cx
函数只是将返回地址从堆栈加载到寄存器ecx
中。在本例中,此返回地址为8
。要实现的目标是将_GLOBAL_OFFSET_TABLE_
的地址放在ecx
中。我们需要知道它距离ecx
中的引用PC
有多远,并添加该距离。为此,使用R_386_GOTPC
重定位,但这将给予从地址0a
的偏移量,因为这是重定位条目所在的位置。从地址8
的偏移量当然将是2
更多。此2
是在指令中编码的。总结:存储在指令中的重定位偏移量是重定位地址与所需参考点之差:
offset
=PC
-reference
。在第一种情况下,该参考点高4
字节,在第二种情况下,低2
字节,分别给出偏移量-4
和2
。