如何在x86上捕获数据对齐错误(在Sparc上也称为SIGBUS)

即使在i386上,是否有可能捕获数据对齐错误? 也许通过设置i386特定的机器寄存器或类似的东西。

在Solaris-Sparc上我在这种情况下收到一个SIGBUS,但在i386上一切都很好。

环境:

  • 32位应用程序
  • Ubuntu Karmic
  • gcc / g ++ v4.4.1

编辑 :这就是为什么我这样问:

  • 我们的应用程序在使用SIGBUS的Sol-Sparc上崩溃了。 出于调试的目的,我会尝试在i386平台上获得类似的行为。
  • 我们的Sol-sparc机器非常慢,因此编译和调试需要很长时间。 我们的i386机器速度令人难以置信(8核,32G内存)。
  • 即使在i386平台上,数据对齐错误也会带来性能损失。 因此,我想尽可能修复数据对齐错误。

为了扩展Vokuhila-Oliba的答案,看看“SO86上的SOF错误对齐指针。 ”线程似乎gcc可以生成具有错误对齐的内存访问的代码。 AFAIK你对此没有任何控制权。

对gcc编译代码启用对齐检查是个坏主意。 您可能会因为良好的 C代码而出现SIGBUS错误。

ReEdited:很抱歉

与此同时,我发现了一个处理该主题的英特尔CPU文

请参阅英特尔®64和IA-32架构软件开发人员手册 。

似乎很难把所有这些东西放在一起。 然而,这听起来并非完全不可能。 有趣的章节是4.10.5检查对齐

编辑 (来自上述文件的一些简明材料):

第5-60页

 Interrupt 17 Alignment Check Exception (#AC) to enable alignment checking, the following conditions must be true: AM flag is set(bit 18 of control regisster CR0) AC flag is set (bit 18 of the EFLAGS) The CPL is 3 (protected mode or virtual-8086 mode). 

另外 – 在14.8.2.6中 – 提到了存储器控制器错误 。 换句话说,我不知道它是否相同:

 table 14-11, Encoding of MMM and CCCC Sub-Fields Address/Command Error AC 011 

英特尔在支持未对齐负载方面非常重要。 如果我必须在Intel平台上检测到这样的负载,我想我必须修改valgrind来将未对齐的负载视为错误。 这样的修改并非易事,但是valgrind的设计理念是用户可以创建新的“工具”。 我认为对memcheck工具的简单修改会检测到你的未对齐引用。 并且错误报告非常好。

我在SOF上找到了一个非常简单的解决方案! 请参阅: x86上的未对齐指针 。

 int main(int argc, char **argv) { # if defined i386 /* EDIT: enable AC check */ asm("pushf; " "orl $(1<<18), (%esp); " "popf;"); # endif char d[] = "12345678"; /* yep! - causes SIGBUS even on Linux-i386 */ return 0; } 

但我必须承认,我不明白为什么这项任务

char d [] =“12345678”;

假设是错位的?

编辑:

在SPARC机器上, char d []的赋值行没有SIGBUS。

许多年后:如果您的gcc / clang足够新(GCC 4.9,clang 3.3?),您可以使用未定义的行为清理程序( -fsanitize=undefined )构建代码,以获取有关给定平台上未对齐访问的警告(但请记住,不同的平台有不同的对齐要求,不同的编译器会选择不同的布局等)。 有关详细信息,请参阅https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html和https://developers.redhat.com/blog/2014/10/16/gcc-undefined-behavior-sanitizer-ubsan/ 。

英特尔从一开始就建立了未对齐的转移 – 这是x86全新的卖点之一。 我理解你想要捕获未对齐访问的原因,但我不认为这是可能的。

编辑:非常高兴被certificate是错误的。