首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >抛出对齐类型时出现Clang运行时错误。编译器错误?

抛出对齐类型时出现Clang运行时错误。编译器错误?
EN

Stack Overflow用户
提问于 2015-06-17 16:19:16
回答 2查看 958关注 0票数 14

我有一个用__attribute__((aligned(16)))声明的类型。在x86_64上的OS X上使用clang构建时,当尝试throw包含此类型的值时,以下代码会导致GP错误。由于编译器生成的128位move指令必须在16字节边界上对齐,但地址未正确对齐,因此会发生该错误。

下面是一个重现问题的程序:

代码语言:javascript
复制
#include <stdint.h>
#include <stdio.h>

struct __attribute__((aligned(16))) int128 {
    uint64_t w[2];
};

int main()
{
    try {
        int128 x;
        throw x;
    } catch (int128 &e) {
        printf("%p %lu\n", &e, sizeof(e));
    }
}

以及故障位置标记为->的反汇编

代码语言:javascript
复制
a.out`main:
    0x100000db0 <+0>:   pushq  %rbp
    0x100000db1 <+1>:   movq   %rsp, %rbp
    0x100000db4 <+4>:   subq   $0x40, %rsp
    0x100000db8 <+8>:   movl   $0x10, %eax
    0x100000dbd <+13>:  movl   %eax, %edi
    0x100000dbf <+15>:  callq  0x100000e8c               ; symbol stub for: __cxa_allocate_exception
    0x100000dc4 <+20>:  movaps -0x10(%rbp), %xmm0
->  0x100000dc8 <+24>:  movaps %xmm0, (%rax)
    0x100000dcb <+27>:  movq   0x23e(%rip), %rsi         ; (void *)0x0000000100001058
    0x100000dd2 <+34>:  xorl   %ecx, %ecx
    0x100000dd4 <+36>:  movl   %ecx, %edx
    0x100000dd6 <+38>:  movq   %rax, %rdi
    0x100000dd9 <+41>:  callq  0x100000e9e               ; symbol stub for: __cxa_throw

当前寄存器:

代码语言:javascript
复制
(lldb) register read rax
       rax = 0x0000000100905b08

看起来发生的情况是__cxa_allocate_exception函数不知道它正在为其分配存储的类型的对齐要求。在我的系统上,它碰巧分配的地址以8结尾,因此不是16字节对齐的。当movaps指令试图将数据移动到该内存位置时,由于未对齐的访问而发生故障。

编译器信息(来自Xcode6.3.2的clang):

代码语言:javascript
复制
$ clang --version
Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn)
Target: x86_64-apple-darwin14.3.0
Thread model: posix

这是一个编译器错误吗?有什么办法可以解决这个问题呢?

更新:我已经将这个提交给了LLVM数据库:https://llvm.org/bugs/show_bug.cgi?id=23868

EN

回答 2

Stack Overflow用户

发布于 2015-06-17 16:39:14

再深入一点,似乎__cxa_allocate_exception从来没有被定义为理解对齐(对于Clang或GCC),所以抛出对齐的对象基本上属于UB (嗯,对齐是一个编译器特定的扩展……)。它似乎保证的唯一对齐方式是8个字节,因为这是任何内置类型(double)所需的最大对齐方式。

我能想到的最简单的解决方法就是在throw中使用未对齐的类型

代码语言:javascript
复制
struct unaligned_int128 {
    uint64_t w[2];
    unaligned_int128(const int128 &x) { w[0] = x.w[0]; w[1] = x.w[1]; }
};

int main()
{
    try {
        int128 x;
        throw unaligned_int128(x);
    } catch (unaligned_int128 &e) {
        printf("%p %lu\n", &e, sizeof(e));
    }
}
票数 4
EN

Stack Overflow用户

发布于 2019-02-26 04:45:00

根据跟踪这个问题的LLVM bug,__cxa_allocation_exception使用的对齐的内部定义已经更新,以匹配假设“最大有用的对齐”的GCC。

Clang和libunwind unwind.h标头状态:

Itanium ABI要求_Unwind_Exception对象“双字对齐”。GCC将此解释为“对目标使用最大有用的对齐”;我们也是如此。

https://bugs.llvm.org/show_bug.cgi?id=23868

因此,从技术上讲,这是一个ABI问题,已经由clang和gcc通过一个更宽松的实现解决了。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30885997

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档