【发布时间】:2012-08-17 17:19:23
【问题描述】:
我有这个小sn-p代码(这是我遇到的问题的最小工作示例):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void xorBuffer(unsigned char* dst, unsigned char* src, int len)
{
while (len != 0)
{
*dst ^= *src;
dst++;
src++;
len--;
}
}
int main()
{
unsigned char* a = malloc(32);
unsigned char* b = malloc(32);
int t;
memset(a, 0xAA, 32);
memset(b, 0xBB, 32);
xorBuffer(a, b, 32);
printf("result = ");
for (t = 0; t < 32; t++) printf("%.2x", a[t]);
printf("\n");
return 0;
}
此代码应该执行两个 32 字节内存缓冲区的异或(从概念上讲,这应该执行 a = a ^ b)。由于 0xAA ^ 0xBB = 0x11,它应该打印“11”三十二次。
我的问题是,当我在 MinGW-GCC (Windows) 下编译它时,它在调试模式下完美运行(无优化),但是当启用从 -O3 开始的优化时,在 xorBuffer 循环中途会因 SIGILL 崩溃。此外,如果我将 printf 放入有问题的循环中,它会再次完美运行。我怀疑堆栈损坏,但我只是看不出我在这里做错了什么。
尝试在启用了优化的情况下使用 GDB 进行调试是一个失败的原因,因为所有 GDB 都向我展示了针对每个变量的“变量优化”(当然,如果我尝试将变量打印出来,它会突然起作用) .
有人知道这里到底发生了什么吗?我在这个问题上花费了太长时间,我真的需要正确解决它才能继续前进。我的猜测是我缺少一些基本的 C 指针知识,但对我来说,代码看起来是正确的。它可能来自缓冲区增量,但据我所知,sizeof(unsigned char) == 1,所以它应该一个一个地遍历每个字节。
不管怎样,即使在我的 Linux 机器上对 GCC 进行了优化,代码也能正常工作。
那么...这里有什么问题?谢谢!
根据要求,整个程序的汇编输出:
使用-O2:clicky
使用-O3:clicky
我在 GCC 4.6.2(与 MinGW 一起运行)上观察到了这种行为
【问题讨论】:
-
使用
O2怎么样?O3风险很大。 SIGILL 表示 - 信号,由非法指令引起。对我来说看起来像一个编译器错误。或者我错过了什么。 -
这在我的 gcc 4.4.3 上完美运行。如果没有人注意到任何事情,您可以尝试向我们展示由 gcc 生成的汇编代码,在这两种情况下 - 使用
O3和O2(如果工作正常;否则 - 优化级别较低) -
@Thomas:使用 -O2 和 -O3 发布。破坏它的最小更改将最有可能帮助我们快速找到错误。
-
我当然不是 x86 汇编方面的专家,但似乎 O3 版本是 a) 展开循环 b) 使用 SIMD 指令。您确定所有
-march和/或/任何选项都可以正确指定您正在构建的确切处理器吗?获取错误 ISA 的说明可能会导致崩溃...... -
@unwind 我在 Sandy Bridge i5-2500k 上使用 -march=native。看起来 GCC 确实生成了一条与我的 CPU 指令集不兼容的指令,但这意味着它一定是错误地检测到了我的处理器,因为我给它的是原生的。我认为您在这里一针见血,因为 -O3 使用 -march=core2 标志工作。