C 编译器过度优化导致数据运行时和调试不一致
我有以下代码:C 编译器过度优化导致数据运行时和调试不一致,c,C,我有以下代码: struct cre_eqEntry * cre_eventGet(struct cre_eqObj *eq_obj) { struct cre_eqEntry *eqe = cre_queueTailNode(&eq_obj->q); Memcpy(&tmpEqo, eq_obj, sizeof(struct cre_eqObj)); volatile u32 ddd = 0; ddd = ((struct cre_e
struct cre_eqEntry *
cre_eventGet(struct cre_eqObj *eq_obj)
{
struct cre_eqEntry *eqe = cre_queueTailNode(&eq_obj->q);
Memcpy(&tmpEqo, eq_obj, sizeof(struct cre_eqObj));
volatile u32 ddd = 0;
ddd = ((struct cre_eqEntry *)(eq_obj->q.dma_mem.virtaddr + 4 * eq_obj->q.tail))->evt;
CPUMemFenceReadWrite();
if (!ddd) {
tmp = eq_obj->q.tail;
assert(0);
return NULL;
}
}
这是一段内核代码。当我运行它时,它在assert0失败。显然ddd应该是0。但当我使用GDB调试核心转储并打印出“struct cre_eqEntry*eq_obj->q.dma_mem.virtaddr+4*eq_obj->q.tail->evt”时,令人惊讶的是,该值不是0
所以我开始怀疑这是编译器过度优化的问题。以下是反汇编代码:
00000000000047ec <cre_eventGet>:
47ec: 55 push %rbp
47ed: 48 89 fe mov %rdi,%rsi
47f0: ba 80 00 00 00 mov $0x80,%edx
47f5: 53 push %rbx
47f6: 48 89 fb mov %rdi,%rbx
47f9: 48 83 ec 18 sub $0x18,%rsp
47fd: 0f b7 6f 24 movzwl 0x24(%rdi),%ebp
4801: 0f b7 47 28 movzwl 0x28(%rdi),%eax
4805: 0f af e8 imul %eax,%ebp
4808: 48 63 ed movslq %ebp,%rbp
480b: 48 03 6f 18 add 0x18(%rdi),%rbp
480f: 48 8d 3d 00 00 00 00 lea 0x0(%rip),%rdi # 4816 <cre_eventGet+0x2a>
4816: e8 00 00 00 00 callq 481b <cre_eventGet+0x2f>
481b: 0f b7 43 28 movzwl 0x28(%rbx),%eax
481f: 48 8b 53 18 mov 0x18(%rbx),%rdx
4823: c7 44 24 0c 00 00 00 movl $0x0,0xc(%rsp)
482a: 00
482b: c1 e0 02 shl $0x2,%eax
482e: 48 98 cltq
4830: 8b 04 02 mov (%rdx,%rax,1),%eax
4833: 89 44 24 0c mov %eax,0xc(%rsp)
4837: 0f ae f0 mfence
483a: 8b 44 24 0c mov 0xc(%rsp),%eax
483e: 85 c0 test %eax,%eax
4840: 74 14 je 4856 <cre_eventGet+0x6a>
就我所见,汇编代码与C代码做了相同的事情
所以现在我想不出是什么导致了“ddd”不一致的问题
请给我一些提示 ddd=struct cre\u eqEntry*eq\u obj->q.dma\u mem.virtaddr+4*eq\u obj->q.tail->evt
简化代码。执行地址/边界检查/验证。您的问题可能是您正在取消引用进程/线程地址空间中的一些随机、未初始化的地址。ddd=struct cre\u eqEntry*eq\u obj->q.dma\u mem.virtaddr+4*eq\u obj->q.tail->evt;可能违反了严格的别名规则,在没有看到整个代码的情况下,不能说100%确定
如果使用gcc/clang,请使用-fno严格别名编译,除非您希望重写代码以符合标准
对于后者,memcpyu32*&ddd,&struct cre_eqEntry*eq_obj->q.dma_mem.virtaddr+4*eq_obj->q.tail->evt,ddd的大小;但我猜您的代码库在许多地方可能有类似的违规行为,因此作为第一步,使用编译器标志将是一种查看这是否真的是问题的方法
神奇数字4也是可疑的,请检查您的代码,以检查这是否真的是正确的偏移量,并检查它是否超出分配的内存范围。当然,只有在未定义NDEBUG的情况下,此assert调用才会生成错误消息。如果有,就执行!ddd。这不意味着ddd应该是非零的吗?或者我遗漏了什么?是另一个核心还是一个设备修改了ptr->evt?你有没有试过在gdb中运行它,并在cre_Event上设置一个断点来查看一步一步发生了什么?这是你的吗?如果是这样,它似乎并不完整;请阅读我刚刚链接到的页面。确保你的代码是最小的,目前这不是一个问题;你的代码是如此之小,以至于它还没有编译,可编译这是你目前的问题,可验证我们无法验证任何东西,因为我们无法编译。一旦你提供了这样一个例子,我想你会发现问题几乎肯定不是过度优化;你很可能把我们的注意力从真正的问题上移开了。我相信volatile在这里没有效果。如果内存围栏实际上是围栏,那么它是冗余的;如果围栏没有围栏,那么它实际上也没有帮助。