【发布时间】:2019-09-19 13:04:21
【问题描述】:
我编写了以下示例来掌握 PLT/GOT 部分。
共享库libshar代码:
shared.h
int sum(int a, int b);
shared.c
#include "shared.h"
int sum(int a, int b){
return a + b;
}
可执行的bin_shared代码:
#include <stdio.h>
#include "shared.h"
int main(void){
printf("Starting the programm... \n");
int s = sum(1, 2); //<=== I expected the dynamic linker would be called here
int s2 = sum(2, 3);
printf("s = %d, s2 = %d\n", s, s2);
}
所以我编译了共享库并将其与可执行文件链接,并编写了以下 gdb-script 以进入动态链接器代码。我希望它会在第一次调用 sum 时执行。
set pagination off
file build/bin_shared
b main
commands
layout asm
info proc mappings
end
r
我遇到了两个问题:
I.当main函数入口的断点被命中时,info proc mappings显示libshar.so已经被映射:
0x7ffff7bd3000 0x7ffff7bd4000 0x1000 0x0 /home/me/c/build/libshar.so
0x7ffff7bd4000 0x7ffff7dd3000 0x1ff000 0x1000 /home/me/c/build/libshar.so
0x7ffff7dd3000 0x7ffff7dd4000 0x1000 0x0 /home/me/c/build/libshar.so
0x7ffff7dd4000 0x7ffff7dd5000 0x1000 0x1000 /home/me/c/build/libshar.so
sum 共享库函数尚未被调用。为什么已经迫不及待地加载了?
II.第一次输入sum@plt时看到如下asm:
0x555555554690 <sum@plt> jmp QWORD PTR [rip+0x200932] # 0x555555754fc8
这是指向 GOT 的指针:
(gdb) disassemble 0x555555754fc8
Dump of assembler code for function _GLOBAL_OFFSET_TABLE_:
但问题是此时单指令步进将gdb 直接放入
0x7ffff7bd3580 <sum> lea eax,[rdi+rsi*1]
意味着指向GOT的指针已经被实际的函数指针覆盖,但gdb仍然显示GOT指针。这是为什么呢?
我提取了jmp到GOT地址处的原始内存,希望找到被覆盖的地址,但看起来不像:
(gdb) x/2xg 0x555555554690
0x555555554690 <sum@plt>: 0x01680020093225ff 0xffffffd0e9000000
【问题讨论】:
-
库在启动时加载,而不是按需加载。我无法重现您的问题,第一次步骤指令将我带到动态链接器。
-
@Jester 所以库只是映射到内存中,但是
.plt部分的跳转地址当时没有解析。对吗? -
也许是某个地方的 gdb 设置?我的带我到
_dl_runtime_resolve_xsavec () at ../sysdeps/x86_64/dl-trampoline.h:71GNU gdb (Debian 7.12-6) 7.12.0.20161007-git -
也许您出于某种原因在环境中设置了
LD_BIND_NOW。您也可以尝试set step-mode on,它不应该真的有任何影响,但谁知道...您也可以在jmp QWORD PTR [rip+0x200932]之后放置一个断点(最好是硬件断点),这通常是入口指向的位置(应该是一个push和另一个jmp)。 -
@Jester 问题出在 gcc 链接器上。我使用了一个 CMake 项目,似乎 gcc 链接器需要添加
-zlazy标志。至少在设置它之后,我在第一次通话时也得到了_dl_runtime_resolve_xsavec。谢谢。
标签: c linux assembly gdb shared-libraries