我有以下代码:
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;
}
}
这是一段内核代码。当我运行它时,它在assert(0)处失败。所以显然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'不一致的问题。
请给我一些提示!
答案 0 :(得分:0)
ddd = ((struct cre_eqEntry *)(eq_obj->q.dma_mem.virtaddr + 4 * eq_obj->q.tail))->evt;
简化您的代码。执行地址/边界检查/验证。您的问题可能是您在进程/线程的地址空间中取消引用一些随机的,未初始化的地址。
答案 1 :(得分:0)
ddd = ((struct cre_eqEntry *)(eq_obj->q.dma_mem.virtaddr + 4 * eq_obj->q.tail))->evt;
可能违反了严格的别名规则(如果没有看到整个代码,就不能说100%)。
如果使用gcc / clang,请使用-fno-strict-aliasing
进行编译,除非您想重写代码以符合标准。
要做后者memcpy((u32 *)&ddd, &(struct cre_eqEntry *)(eq_obj->q.dma_mem.virtaddr + 4 * eq_obj->q.tail)->evt, sizeof ddd);
,但我想你的代码库可能在很多地方有类似的违规行为,所以作为第一步,使用编译器标志将是一种方法,看看这是否真的是问题。< / p>
幻数4
也是可疑的,请检查您的代码以检查这是否确实是正确的偏移,并检查它是否超出已分配的内存范围。