调用例程中的地址

我正在使用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,1)
 │0x5555556ebdc0 <main_window_update()>                           xor    %edi,%edi

请注意,如果我减去偏差值,则运行时目标地址将与编译时间值(即0x5555556ebdb0 - 0x555555554000 = 0x197db0)一致。似乎在pseudo-routine内部存在一个名为frame_dummy的{​​{1}}。那怎么可能?如何预先(即在执行之前)提取这些_start@@Base的地址?

更新:

pseudo-routinesGIMP中不存在对函数中间的这些类型的调用(它们几乎完全用Anjuta编写,并且是从源代码构建的)。但是存在于CInkscape中(用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认为Pinget_compiled_version_info()内部。

alan0633 回答:调用例程中的地址

  

那怎么可能?

frame_dummy是真正的C函数。如果Pin认为它在_start的中间,则可能是因为:

  1. _start是一个汇编函数,并且
  2. .st_size在符号表中的设置错误。

您可以通过查看readelf -Ws a.out | egrep ' (_start|frame_dummy)'来确认。

您可能正在使用与相当老的GLIBC链接的二进制文件。

GLIBC用于生成C运行时启动文件(因此_start来自),方法是使用gcc -S从C源代码创建程序集,然后使用sed拆分和编辑程序集。弄错.size指令是该方法的一个问题,{2012年(commit)不再在x86_64上使用。

  

如何预先(即在执行之前)提取这些伪例程的地址?

Pin不会神奇地创建这些伪例程,它们必须在原始二进制文件的readelf -Ws输出中可见。

本文链接:https://www.f2er.com/3019307.html

大家都在问