编译器过度优化导致数据运行时和调试不一致

时间:2015-08-23 08:09:12

标签: 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_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'不一致的问题。

请给我一些提示!

2 个答案:

答案 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也是可疑的,请检查您的代码以检查这是否确实是正确的偏移,并检查它是否超出已分配的内存范围。