【问题标题】:Segfault: and the disassembly is different between objdump and gdbSegfault:objdump和gdb的反汇编不同
【发布时间】:2026-02-16 18:25:02
【问题描述】:

[深呼吸。] 我们有一个使用 WxMotif 2.6.3 弹出窗口的应用程序(GUI 库不是 - 也不是 - 我的选择)。 它在 32 位 ix86 系统上运行良好。我的任务是将其转换为 64 位应用程序。它总是段错误。 我在 RHEL 6 上,所以我使用 gcc 4.4.7 编译。咬牙切齿之后,问题似乎很明显:在 wxFrame::DoCreate 中,m_mainWidget 已设置(正确);在 wxFrame::GetMainWidget 中,它作为空指针返回。空指针导致崩溃。 使用gdb,设置m_mainWidget的指令是

mov    %rax,0x1e0(%rdx) # $rdx = 0x68b2f0

而获取 m_mainWidget 的代码是

mov    0x1f0(%rax),%rax # $rax = 0x68b2f0

在 gdb 中,我可以检查内存并查看 0x68b4d0 处的指针是否正确。为什么偏移不正确?

更令人困惑的是,当我使用 objdump 反汇编 libwx_motifd_core-2.6.so.0.3.1 时,“get”程序集是

  mov    0x1e0(%rax),%rax

在 objdump 中,get 和 set 都使用 0x1e0 作为偏移量。怎么回事?

我在这里上传了一些相关信息: GitHub

我已经包含了一个小程序,可以在我的系统上复制问题。

进一步调查,我在 wxFrame::DoCreate 的反汇编中看到,m_mainWidget 的进一步使用使用 0x1e0 作为偏移量检索值(反汇编是在我使用 -O0 的编译中,因此代码必须返回每次到内存)。 “只是为了好玩,”我在 wxFrame 中添加了一个新成员变量 - m_myMainWidget - 并在设置 m_mainWidget 之后立即设置它。然后我让 wxFrame::GetMainWidget() 返回本地值 (m_myMainWidget)。你不知道吗:当我从 gdb 中反汇编时,崩溃仍然发生并且 GetMainWidget 包含相同的 +16 偏移量。 (偏移量在我使用 objdump 反汇编的地方 not。)

【问题讨论】:

  • 这可能是编译器优化级别的差异吗?
  • 无论我使用 -O2 还是 -O0,行为都相同。
  • 会是(动态)链接问题吗?
  • 某处,你有两个翻译单元,或两个模块,用不同的编译器设置或不同的宏定义构建。结果,这两个模块在类的二进制布局上不一致。例如。 class MyWidget { MyInt a; MyInt b; }; 如果 MyInt 有时被 typedef 为 32 位整数,有时为 64 位整数,那么到 MyWidget::b 的偏移量会有所不同。
  • 查看github.com/tagged/wx/blob/master/include/wx/frame.h,有一些宏可以有条件地添加或删除类成员。这很可怕。请非常小心,您在应用程序中定义这些宏的方式与构建库时定义的方式相同。

标签: c++ assembly gdb objdump


【解决方案1】:

根据@Igor 的评论,我查看了使用-fdump-class-hierarchy 编译器选项的类布局。事实证明确实存在vtable布局不匹配,由于include/wx/app.h中的这个条件块:

#ifdef __WXDEBUG__
    virtual void OnAssert(const wxChar *file,
                          int line,
                          const wxChar *cond,
                          const wxChar *msg);
#endif // __WXDEBUG__

您需要确保使用相同的__WXDEBUG__ 设置编译代码。

【讨论】:

  • 我认为答案就在这里。我会说两个调用都在同一个翻译单元中,但我只是将 wxFrame::GetWidget 的函数定义移动到 ./src/motif/frame.cpp 文件中并重新编译,问题似乎得到了解决。我不确定 任何 宏(如 WXDEBUG)如何从一个翻译单元到另一个翻译单元不同,因为我使用 ./configure 编译了所有宏;制作;在不更改的情况下进行安装。感谢您的帮助!
  • 编译代码时未定义宏,而不是库。您的MainApp 继承自wxAppConsole,但没有WXDEBUG,它的vtable 缺少OnAssert 的条目,因此与库所期望的布局不同(因为它是用WXDEBUG 编译的)。
  • [打自己的脑袋]我真笨!谢谢一堆。你给了我一个新的工具来使用(-fdump-class-hierarch)。