UPDATE3:Clang issue submitted因为我现在确信这是一个以前没有报告的编译器错误.(LLVM bug跟踪器中有许多类似但不同的问题.感谢所有真心想帮忙的人.

UPDATE2:原来这个bug确实需要使用-n(--nmagic)选项.在没有使用C库(-nostdlib Clang选项)的情况下构建的二进制文件上也会发生同样的崩溃.因此,构建NMAGIC二进制文件显然与这个问题无关.

UPDATE:LLVM自己的链接器LLD支持-n(--nmagic)选项,所以我安装了它并try 了一下.发生完全相同的segfault.由于LLVM自己的链接器支持构建NMAGIC二进制文件,这强烈表明它should在使用他们的编译器(Clang)时也可以工作.我会提交一份bug报告.

Original Post:
I've come across a C++ issue where instantiating some objects in programs compiled by Clang segfaults. Thanks in advance to anyone who can help shed light on the issue.

Just建议Clang正在生成SSE movaps指令来初始化一些char数组,而正是这些指令在某些情况下似乎会导致segfault.

我已经在多个Linux系统上使用binutils链接器与Clang 16和Clang 17进行了测试,结果相同.我不确定是否在其他x86—64操作系统或其他链接器下也会出现同样的问题.当使用GCC编译器的版本而不是Clang时,问题确实发生了not个.

在以下最小条件集下,某些对象会发生段故障:

  • x86—64代码生成
  • 启用优化(—O1或以上)
  • [EDIT—这是错误的segfault do not需要-n(--nmagic)链接器选项.所有必要的是构建一个不使用标准C库的二进制文件(Clang的-nstdlib选项).在这里,我还应该指出,使用-fno-builtin选项没有什么区别.

这里是要复制的最小代码.在x86—64 Linux系统上编译以下代码[EDIT:移除不必要的链接器选项]:

$ clang -O1 -nostdlib -fno-stack-protector -static ClangSegv.s clang_segv.cc -o clang_segv

clang_segv. cc:

struct SegV
{
    void set(const char *s) { char *b = buf; while ( *s ) { *b++ = *s++; } *b = '\0'; }
    char  buf[128] = "";
    char *cursor   = buf; // needed for segfault
};

int
main()
{
    SegV v;
    v.set("aa");
    return 0;
}

ClangSegv.s

.intel_syntax noprefix

.global _start
_start:
    xor rbp,rbp             # Zero stack base pointer

    xor r9,r9
    pop rdi                 # Pop argc off stack -> rdi for 1st arg to main()
    mov rsi,rsp             # Argv @top of stack -> rsi for 2nd arg to main()
    call main               # Call main()... return result ends up in rax

    xor r9,r9
    mov rdi,rax             # Move main()'s return to 1st argument for exit()
    mov rax,231             # exit_group() syscall
    syscall                 # Tell kernel to exit program

这个例子是我能想出的最小的再现器,与原始代码没有相似之处,我注意到问题,即两者都有字符数组的对象.更改代码可以掩盖或揭开问题,这通常意味着一个编码错误,但我在这个简单的例子中找不到一个.

我的调试器似乎认为问题是Clang生成的初始化'buf'字符数组的指令: Image of debugger suggesting issue with movaps instructions.

我的progrger说Clang生成了以下代码来初始化char buf[128]:

0x400171 xorps  %xmm0,%xmm0
0x400174 movaps %xmm0,-0x10(%rsp)
0x400179 movaps %xmm0,-0x20(%rsp)
0x40017e movaps %xmm0,-0x30(%rsp)
0x400183 movaps %xmm0,-0x40(%rsp)
0x400188 movaps %xmm0,-0x50(%rsp)
0x40018d movaps %xmm0,-0x60(%rsp)
0x400192 movaps %xmm0,-0x70(%rsp)
0x400197 movaps %xmm0,-0x80(%rsp)
0x40019c lea    -0x80(%rsp),%rax

并且SegFault由第一Movapps指令生成.

显然,我希望数组的初始化不应该segfault.

不管是像我在这个例子中所做的那样使用类内初始化,还是使用初始化器列表初始化.这两种方法都有同样的问题.

我认为问题可能是clang thinks生成的代码对象成员的对齐方式与成员的对齐方式不匹配.我可能是错的,但是如果我在 struct 或char数组中添加alignas(32),问题就消失了.我不知道为什么我需要在32字节对齐.令人困惑的是(对我来说),在16字节对齐并不能掩盖问题.

如果我只是告诉Clang不要生成任何带有-mno-sse的SSE指令,问题也会消失,但我不希望失go 这些优化.在这种情况下,Clang使用movq指令来初始化数组,而不是movaps.

如果我放弃初始化char数组成员,而在构造函数中手动执行,问题也会消失,但当然,这会降低效率.

在我看来,这看起来像是编译器的bug.还是我只是用错了?

谢谢!

推荐答案

SOLVED:In_start堆栈是already对齐的,所以通过在我的启动代码中弹出8个字节,我实际上在调用main()之前是misaligning.SysV x86—64 ABI要求堆栈在任何调用之前对齐,因此Clang完全合理地假设堆栈在进入main()时以某种方式对齐,并相应地生成代码.换句话说:This is not a bug.(再说一次,它与使用--nmagic链接器选项无关,这是完全可以使用的.

Linux相关问答推荐

OpenCV编译错误&未定义的引用&Quot;

如何在带模式的文件频繁更改的管道中使用grep-f带模式的文件?

在Linix&;Mac中运行Reaction本机项目时出现问题

通过添加1位数字替换最后4位数字(不包括0x)

Azure Linux B1s VM-Jenkins Sever已安装,但主页未打开

/proc/mounts 没有像 /proc/self/mountinfo 这样的源信息

如何将一个变量的 2 行添加到另一个变量的特定行?

linux 提取字符串中可能是第二常见模式的部分

从 curl 命令输出中获取值

在 Windows 上通过 SSH 运行 django 应用程序

如何在文本文件中向左移动特定单元格

进程Forking 后 pthread_key_create() 生成的密钥会发生什么?

XML 编辑/查看软件

判断条件是否为假

在亚马逊 ec2 linux 微型实例上的 virtualenv 中安装 scipy 时遇到问题

Linux 配置/制作,--prefix?

.NET Core 中的跨平台文件名处理

如何限制堆大小?

使用 WGET 运行 cronjob PHP

如何用逗号而不是空格分割列表