【问题标题】:Incorrect Class Member Offset Address不正确的类成员偏移地址
【发布时间】:2015-04-29 20:14:57
【问题描述】:

我有一个问题,当我尝试访问某个文件中的某个类的成员时,它没有获得该成员的实际值。但是当我尝试在其他地方访问它时,我会这样做。

文件 A:

find_func_wrapper ( Func_Container * rules, char * func_name ) {
    ulong count = rules->function_count;
    cout << "A count: " << count << endl;
    B::find_func( rules, func_name );
}

main () {
    Func_Container *rules = get_rules();
    find_func_wrapper( rules, func_name );
}

文件 B:

B::find_func ( Func_Container * rules, char * func_name ) {
    ulong count = rules->function_count;
    cout << "B count: " << count << endl;
}

当我运行它时,我得到:

A count: 2
B count: 0

当计数成员设置为 2。使用 gdb 单步执行代码时,在 A 和 B 中,当我使用 print rules-&gt;function_count 时,我得到 2。

反汇编代码,在 A find_func_wrapper 中。

1885            ulong count = rules->function_count;
=> 0x0000000006004be5 <+294>:   mov    -0xa8(%rbp),%rax
   0x0000000006004bec <+301>:   mov    0x60a8(%rax),%rax
   0x0000000006004bf3 <+308>:   mov    %rax,-0x38(%rbp)

还有print &amp;rules-&gt;function_count = 0x11684158 和print rules = 0x1167e0b0
而在 B::find_func

2652        ulong count = rules->function_count;
   0x00000000062494a1 <+75>:    mov    -0x4f8(%rbp),%rax
   0x00000000062494a8 <+82>:    mov    0x60e8(%rax),%rax
   0x00000000062494af <+89>:    mov    %rax,-0x50(%rbp)

打印规则的地址和 ->function_count 返回与预期相同的地址。对我来说,罪魁祸首似乎在第二条 mov 指令中,其中 B 中使用的偏移量 0x60e8 不正确。为什么会发生这种情况?

get_rules() 返回一个指向全局对象的指针,该对象在之前初始化并一直保留到程序结束。

这是用 gcc 4.4.7 编译的。该项目非常庞大。此外,这只发生在调试版本中,发布版本或非优化版本似乎没有这个问题。

Sizeof in find_func_wrapper: 24968
    Offset: 3093
Sizeof in B::find_func: 25032
    Offset: 3101

由((&amp;rules-&gt;function_count) - rules)计算的偏移量

【问题讨论】:

  • 这听起来与对齐有关。通常,当您将类存储到文件时,您会在标题之前指定对齐方式。在 Visual Studio 中类似于 #pragma pack(1)
  • 确保两个 TU 共享相同的 Func_Container 定义并进行清理和重建。 Visual Studio 有时会搞砸并忘记重新编译目标文件。
  • 你确定这两个文件是用相同的标志编译的吗?这听起来像 func_container 可能有可选的 ifdef 字段。在两个函数中打印 sizeof(func_container)。
  • 在重新安排了一些事情之后,我发现这似乎是因为 _GLIBCXX_DEBUG。 B 中包含的第一个标头定义了这一点。如果我包含 Func_Container 的标题,它可以正常工作。我没有立即在 Func_Container 的定义中看到 #ifdef 依赖于该值的任何内容,但我不知道它会导致编译器做什么。
  • 请将您的最后一条评论添加为更详细的答案,并转发给下一个人。

标签: c++ gcc assembly compilation


【解决方案1】:

我能够通过重新排列标题包含来缩小问题的来源。在将#include "Func_Container.h" 放在文件B 中的其他包含之前,我发现容器的大小正确。我继续在Func_Container 之前移动其他标题,直到找到导致问题的标题。我发现有问题的标头定义了_GLIBCXX_DEBUG 标志。这导致某些 std 类型中的额外调试成员改变了它们的大小,所以当我对 Func_Container 的定义被加载到后来的成员地址时,由于更大的类型而发生了变化。

此邮件列表中提供了一个问题示例:https://gcc.gnu.org/ml/libstdc++/2012-10/msg00077.html

【讨论】:

    猜你喜欢
    • 2019-10-18
    • 2012-09-15
    • 1970-01-01
    • 2016-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-12
    • 1970-01-01
    相关资源
    最近更新 更多