【发布时间】: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,有一些宏可以有条件地添加或删除类成员。这很可怕。请非常小心,您在应用程序中定义这些宏的方式与构建库时定义的方式相同。