Class 成员偏移地址不正确
Incorrect Class Member Offset Address
我有一个问题,当我尝试访问某个文件中 class 的成员时,它没有获得该成员的实际值。但是当我尝试在其他地方访问它时,我会这样做。
文件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->function_count
时,我得到 2。
反汇编代码,在Afind_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 &rules->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 return 与预期相同的地址。在我看来,罪魁祸首似乎在第二条 mov
指令中,其中 B 中使用的偏移量 0x60e8 不正确。为什么会这样?
get_rules() returns 指向全局对象的指针,该对象较早初始化并一直保留到程序结束。
这是用 gcc 4.4.7 编译的。该项目非常庞大。此外,这只发生在调试版本中,发布版本或非优化版本似乎没有这个问题。
Sizeof in find_func_wrapper: 24968
Offset: 3093
Sizeof in B::find_func: 25032
Offset: 3101
由((&rules->function_count) - rules)
计算的偏移量
我可以通过重新排列 header 来缩小问题的来源范围。在文件 B 中将 #include "Func_Container.h"
放在其他包含之前后,我发现容器变成了正确的大小。我继续将其他 header 移动到 Func_Container
之前,直到我找到导致问题的原因。我发现有问题的 header 定义了 _GLIBCXX_DEBUG
标志。这导致某些 std 类型中的额外调试成员改变了它们的大小,因此当我对 Func_Container 的定义加载到后来的成员地址时,由于较大的类型而发生了变化。
此邮件列表中提供了该问题的示例:https://gcc.gnu.org/ml/libstdc++/2012-10/msg00077.html
我有一个问题,当我尝试访问某个文件中 class 的成员时,它没有获得该成员的实际值。但是当我尝试在其他地方访问它时,我会这样做。
文件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->function_count
时,我得到 2。
反汇编代码,在Afind_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 &rules->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 return 与预期相同的地址。在我看来,罪魁祸首似乎在第二条 mov
指令中,其中 B 中使用的偏移量 0x60e8 不正确。为什么会这样?
get_rules() returns 指向全局对象的指针,该对象较早初始化并一直保留到程序结束。
这是用 gcc 4.4.7 编译的。该项目非常庞大。此外,这只发生在调试版本中,发布版本或非优化版本似乎没有这个问题。
Sizeof in find_func_wrapper: 24968
Offset: 3093
Sizeof in B::find_func: 25032
Offset: 3101
由((&rules->function_count) - rules)
我可以通过重新排列 header 来缩小问题的来源范围。在文件 B 中将 #include "Func_Container.h"
放在其他包含之前后,我发现容器变成了正确的大小。我继续将其他 header 移动到 Func_Container
之前,直到我找到导致问题的原因。我发现有问题的 header 定义了 _GLIBCXX_DEBUG
标志。这导致某些 std 类型中的额外调试成员改变了它们的大小,因此当我对 Func_Container 的定义加载到后来的成员地址时,由于较大的类型而发生了变化。
此邮件列表中提供了该问题的示例:https://gcc.gnu.org/ml/libstdc++/2012-10/msg00077.html