如何在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是错误的。