【问题标题】:Why does __builtin_return_address crash in Clang?为什么 __builtin_return_address 在 Clang 中崩溃?
【发布时间】:2021-04-14 17:50:55
【问题描述】:

我有以下 C/C++ 代码,它使用__builtin_return_address

#include <stdio.h>

#ifdef __clang__
# define optnone __attribute__((optnone))
#else
# define optnone __attribute__((optimize("O0")))
#endif

void *f() {
    return __builtin_extract_return_addr(__builtin_return_address(2));
}

optnone void nest1() {
    printf("%p\n", f());
}

optnone void nest2() {
    nest1();
}

optnone void nest3() {
    nest2();
}

optnone void nest4() {
    nest3();
}

optnone int main() {
    nest4();
}

GCC generates the following assembly 并且工作正常(不会崩溃):

f:
        push    rbp
        mov     rbp, rsp
        mov     rax, QWORD PTR [rbp+0]
        pop     rbp
        mov     rax, QWORD PTR [rax]
        mov     rax, QWORD PTR [rax+8]
        ret

Clang 编译以下程序集,crashes:

f:                                      # @f
        push    rbp
        mov     rbp, rsp
        mov     rax, qword ptr [rbp]
        mov     rax, qword ptr [rax]
        mov     rax, qword ptr [rax + 8]
        pop     rbp
        ret

崩溃的原因是什么?

【问题讨论】:

标签: c assembly clang callstack backtrace


【解决方案1】:

__builtin_return_address(),正如您从程序集中看到的那样,尝试遍历堆栈上的帧指针链。但这仅在您上面的调用者实际设置了堆栈帧并推送了它们的帧指针时才有效。您可以看到 gcc 是这种情况(其他每个函数都以 push rbp / mov rbp, rsp 开头),但对于 clang 则不然。您可以使用 -fno-omit-frame-pointer 强制 clang 这样做,然后您的代码再次运行。

【讨论】:

  • 大概这就是 OP 希望 __attribute__((optnone)) 做的事情,但如果命令行优化设置包括 -O2 或其他启用 -fomit-frame-pointer 的东西,它就不会。它至少会阻止内联。而optimize("O0") 对 clang 完全没有任何作用;它说“未知属性”。 godbolt.org/z/7q4vbP
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-04-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-23
相关资源
最近更新 更多