c - 如何在 x86_64 中使用 clang-8 的 "shadow call stack"特性?

标签 c assembly clang x86-64 callstack

最近,我正在尝试在 x86_64 中测试 clang-8 的“影子调用堆栈”功能。但是当我运行“shadowed”程序时,即使它是一个“Hello_World”程序,它也会不断抛出段错误。
我的编译命令是“clang-8 -fsanitize=shadow-call-stack normal.c”。
“normal.c”只是一个简单的 hello_world c 程序:

#include <stdio.h>
int main(int argc, char *argv[])
{
    printf("Hello World!\n");
    return 0;
}

main函数的汇编代码在这里:
   0x0000000000401130 <+0>: mov    (%rsp),%r10
   0x0000000000401134 <+4>: xor    %r11,%r11
   0x0000000000401137 <+7>: addq   $0x8,%gs:(%r11)
   0x000000000040113c <+12>:    mov    %gs:(%r11),%r11
   0x0000000000401140 <+16>:    mov    %r10,%gs:(%r11)
   0x0000000000401144 <+20>:    push   %rbp
   0x0000000000401145 <+21>:    mov    %rsp,%rbp
   0x0000000000401148 <+24>:    sub    $0x20,%rsp
   0x000000000040114c <+28>:    movl   $0x0,-0x4(%rbp)
   0x0000000000401153 <+35>:    mov    %edi,-0x8(%rbp)
   0x0000000000401156 <+38>:    mov    %rsi,-0x10(%rbp)
   0x000000000040115a <+42>:    movabs $0x402004,%rdi
   0x0000000000401164 <+52>:    mov    $0x0,%al
   0x0000000000401166 <+54>:    callq  0x401030 <printf@plt>
   0x000000000040116b <+59>:    xor    %ecx,%ecx
   0x000000000040116d <+61>:    mov    %eax,-0x14(%rbp)
   0x0000000000401170 <+64>:    mov    %ecx,%eax
   0x0000000000401172 <+66>:    add    $0x20,%rsp
   0x0000000000401176 <+70>:    pop    %rbp
   0x0000000000401177 <+71>:    xor    %r11,%r11
   0x000000000040117a <+74>:    mov    %gs:(%r11),%r10
   0x000000000040117e <+78>:    mov    %gs:(%r10),%r10
   0x0000000000401182 <+82>:    subq   $0x8,%gs:(%r11)
   0x0000000000401187 <+87>:    cmp    %r10,(%rsp)
   0x000000000040118b <+91>:    jne    0x401192 <main+98>
   0x0000000000401191 <+97>:    retq   
   0x0000000000401192 <+98>:    ud2

当我运行这个程序时,它抛出:
Program received signal SIGSEGV, Segmentation fault.
0x0000000000401137 in main ()

clang-8 documentation ,它标识此功能使用 x86 的 gs 寄存器。但实际运行表明存在一些问题。是gs寄存器的问题吗?谁能帮我?提前致谢。

最佳答案

问题是,运行时环境必须初始化 gs register 指向一个可以存储影子调用堆栈的位置。这不是很明确地说,但可以从 the Clang documentation 推导出来:

ShadowCallStack currently only supports x86_64 and aarch64. A runtime is not currently provided in compiler-rt so one must be provided by the compiled application.



使用标准运行时,gs register 指向无处,因此写入访问失败并出现段错误。 Android libc 提供了这样的运行时。

但是,影子调用堆栈功能在 x86_64 上被认为不仅效率低下,而且不安全,并且在以后的版本中被删除。如果你真的想使用这个功能,你应该仔细考虑。如果您仍然这样做,那么您必须使用 gs 准备运行时环境注册正确初始化。

有一个系统调用 arch_prctl() (未由libc 包裹),可用于设置gs登记:
arch_prctl(ARCH_SET_GS, baseaddr);

这可能是一个好的开始,但必须在填充影子调用堆栈之前(即在 main() 之前)调用它。一个好处是在 _start() 中初始化它函数,通常位于单元crt1.o或类似。

关于c - 如何在 x86_64 中使用 clang-8 的 "shadow call stack"特性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59281598/

相关文章:

c - Mac OS X 塞拉利昂 : Undefined symbols for architecture x86_64

使用 Clang 进行交叉编译 - `crtbeginS.o: No such file or directory`

c - 将 MASM 对象与 C 对象链接会给出错误的结果

从 FORTRAN 调用 C 代码

c - 使用 C 中的套接字通过多个客户端传输文件时出现格式错误

c - 如何在 C 中使用 scanf() 从键盘写入 '\n'

visual-studio - 为什么寄存器 ax 中的内存整数之和是正确的,而寄存器 eax 中的内存整数之和却不是正确的?

c - 在以下 NASM 任务中需要帮助

assembly - 为什么 GCC 会产生 ANDL $-16?

c++ - Clang 不编译代码,但 gcc 和 msvc 编译了它