debugging - 在例程中间调用地址
问题描述
我正在wireshark-2.6.10
使用Pin
. 在初始化期间的几个点,我可以看到一些调用,例如:
00000000004e9400 <__libc_csu_init@@Base>:
...
4e9449: 41 ff 14 dc callq *(%r12,%rbx,8)
...
此调用的目标是0x197db0
,如下所示:
0000000000197cb0 <_start@@Base>:
...
197db0: 55 push %rbp
197db1: 48 89 e5 mov %rsp,%rbp
197db4: 5d pop %rbp
197db5: e9 66 ff ff ff jmpq 197d20 <_start@@Base+0x70>
197dba: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
...
Pin
表示这是在包含例程的中间,即_start@@Base
. 但是,当我使用 达到这个目标时gdb
,我看到以下输出:
>│0x5555556ebdb0 <frame_dummy> push %rbp
│0x5555556ebdb1 <frame_dummy+1> mov %rsp,%rbp
│0x5555556ebdb4 <frame_dummy+4> pop %rbp
│0x5555556ebdb5 <frame_dummy+5> jmpq 0x5555556ebd20 <register_tm_clones>
│0x5555556ebdba <frame_dummy+10> nopw 0x0(%rax,%rax,1)
│0x5555556ebdc0 <main_window_update()> xor %edi,%edi
请注意,如果我减去偏差值,则运行时目标地址将与编译时值一致(即,0x5555556ebdb0 - 0x555555554000 = 0x197db0
)。似乎存在一个pseudo-routine
被调用的frame_dummy
inside _start@@Base
。这怎么可能?如何pseudo-routines
事先(即在执行之前)提取这些的地址?
更新:
对函数中间的这些类型的调用不存在于GIMP
and中Anjuta
(它们几乎完全是在C
源代码中编写和构建的)。但是存在于Inkscape
and Wireshark
(写在 中C++
,虽然我不认为语言是原因。这两个是从包中安装的。)。
起初,这种情况似乎只发生在初始化期间和调用main()
函数之前。但是,至少在wireshark-2.6.10
这至少发生在一个地方main()
开始之后。在这里,我们有wireshark-qt.cpp: Lines 522-524
(它是 的一部分main()
)。
/* Get the compile-time version information string */
comp_info_str = get_compiled_version_info(get_wireshark_qt_compiled_info,
get_gui_compiled_info);
这是对get_compiled_version_info()
. 在汇编中,函数在地址处被调用0x5555556e74c2 (0x1934c2 without bias)
,如下所示:
>│0x5555556e74c2 <main(int, char**)+178> callq 0x5555556f5870 <get_compiled_version_info>
│0x5555556e74c7 <main(int, char**)+183> lea 0x4972(%rip),%rdi # 0x5555556ebe40 <get_wireshark_runtime_info(_GString*)>
│0x5555556e74ce <main(int, char**)+190> mov %rax,%r13
同样,目标位于另一个函数的中间_ZN7QStringD1Ev@@Base
:
00000000001980f0 <_ZN7QStringD1Ev@@Base>:
...
1a1870: 41 54 push %r12
...
这是gdb
( 0x5555556f5870 - 0x555555554000 = 0x1a1870
) 的输出:
>│0x5555556f5870 <get_compiled_version_info> push %r12
│0x5555556f5872 <get_compiled_version_info+2> mov %rdi,%r12
│0x5555556f5875 <get_compiled_version_info+5> push %rbp
│0x5555556f5876 <get_compiled_version_info+6> lea 0x349445(%rip),%rdi # 0x555555a3ecc2
可以看出,调试器识别出这个地址是 的起始地址get_compiled_version_info()
。这是因为它可以访问debug_info
. 在我发现的所有情况下,这些符号pseudo-routines
都已从原始二进制文件中删除(因为.symtab
已从二进制文件中删除)。但奇怪的是,它位于里面_ZN7QStringD1Ev@@Base
。因此,Pin
认为get_compiled_version_info()
是在里面_ZN7QStringD1Ev@@Base
。
解决方案
这怎么可能?
frame_dummy是一个真正的 C 函数。如果Pin
认为它在中间_start
,那可能是因为:
_start
是一个汇编函数,并且- 它
.st_size
在符号表中设置不正确。
您可以通过查看来确认这一点readelf -Ws a.out | egrep ' (_start|frame_dummy)'
。
您可能正在使用与相当旧的 GLIBC 链接的二进制文件。
GLIBC 用于生成 C 运行时启动文件(从何_start
而来),方法是使用gcc -S
从 C 源代码创建程序集,然后使用sed
. 指令.size
错误是该方法的一个问题,并且从 2012 年开始不再使用x86_64
(commit)。
如何事先(即在执行之前)提取这些伪例程的地址?
Pin 不会神奇地创建这些伪程序,它们必须在readelf -Ws
原始二进制文件的输出中可见。
推荐阅读
- deep-learning - 将自定义 tiny-YOLOv3 转换为 tensorflow 格式
- c++ - 如何在不同步的情况下使用多个线程(2、4、8、16 个线程)循环打印字符串(10,100、1000 个循环)?
- javascript - 如何恢复被覆盖的本机函数
- python - Pipenv 和 ModuleNotFoundError
- swift - 如何在swiftUI中添加返回用户位置按钮?
- python - 将一列json字符串转换为数据列(API结果/输出)
- react-native - 无法理解我的应用程序上的 React-native 错误
- javascript - 在某些 div 中显示 antd 模态掩码
- java - 我可以为多个测试类使用相同的参数化数据吗
- php - “使用按钮更新记录的问题”