最近,我正在尝试在x86_64中测试clang-8的“影子调用堆栈”功能。但是,当我运行“影子”程序时,即使它是“ 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;
}
主要功能的汇编代码在这里:
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寄存器的问题吗?谁能帮我?预先感谢。
问题是,runtime environment
必须初始化gs
寄存器以指向可以存储影子调用堆栈的位置。这不是很明确的说,但是可以从the Clang documentation:
ShadowCallStack当前仅支持x86_64和aarch64。编译器-rt当前未提供运行时,因此编译的应用程序必须提供运行时。
在标准运行时中,gs
寄存器无处指向,因此写访问失败并出现分段错误。 Android libc提供了这样的运行时。
但是,影子调用堆栈功能不仅效率低下,而且在x86_64上也不安全,在更高版本中已将其删除。如果您确实要使用此功能,则应仔细考虑。如果仍然这样做,则必须准备正确初始化gs
寄存器的运行时环境。