这异常可以在减去ESP或RSP注册生成? (堆叠生长)(Which exception can

2019-10-21 13:59发布

我想了解堆栈内存页面究竟是如何分配/分配。

我写了下面的证明了概念的C代码,这显然会导致分段错误(在x86_64的Linux):

#include <string.h>

int main()
{
    char a;

    memset( (&a - 4444444), 0, 3333333 );

    return 0;
}

汇编代码下面的片段(AT&T的语法)是通过从上述C-程序GCC产生:

subq    $16, %rsp
leaq    -1(%rbp), %rax
subq    $4444444, %rax
movl    $3333333, %edx
movl    $0, %esi
movq    %rax, %rdi
call    memset

如果我添加subq $5555555, %rsp调用之前手动memset

subq    $16, %rsp
leaq    -1(%rbp), %rax
subq    $4444444, %rax
movl    $3333333, %edx
movl    $0, %esi
movq    %rax, %rdi
subq    $5555555, %rsp /* added manually */
call    memset

然后分割故障消失,因为堆栈的虚拟内存页面被扣除后分配rsp寄存器造成了一定的硬件异常和分配异常处理程序被调用(当然,在内核空间)。

我知道打电话memset这里将造成“小缺页”异常。 但它是一个不同的故事(即分配的物理内存页)。

我的问题是:当产生哪些异常subq $5555555, %rsp调用? 我认为这将是“堆栈错误”异常,但我没有找到它确切的证据。

Answer 1:

我想到了。 首先,减去rsp寄存器什么也不做。 其次,当我们试图写信给非映射堆栈区“小缺页”异常处理程序在内核空间调用。 接着这个页面故障处理程序检查它是否合法写或不合法的。 我认为页错误处理程序与线程的当前堆栈指针进行比较(在我们的情况下,它保存的值rsp寄存器)。 如果地址在过程中尽量写,比目前的堆栈指针上,然后页面错误处理程序扩展进程的虚拟地址空间,并为虚拟页面,物理页映射,否则处理程序发送SIGSEGV的过程。

我用GDB和/ PROC / [PID] /地图审查了下列片段:

subq    $1500016, %rsp
movq    %fs:40, %rax
movq    %rax, -8(%rbp)
xorl    %eax, %eax
movb    $44, -1500016(%rbp)
movb    $55, -1100016(%rbp)
movb    $66, -600016(%rbp)

subq $1500016, %rsp调用堆栈地址范围不会改变。 但是,当第一写入由发生movb $44, -1500016(%rbp)堆栈如我上面所解释的地址范围被扩展。



Answer 2:

目前该行也不例外。

然而, memset的序幕代码将导致当它试图通过将它们保存到堆栈保存寄存器的访问冲突,由于堆栈指针是无效的。

在大多数环境中,只有触发额外栈页面被提交单个保护页面。 在这种情况下访问冲突不会受到日益增长的栈处理,该程序将简单地崩溃。

如果你的操作系统实际上没有处理过程中引起的寄存器保存,它会犯堆叠中的所有中间页和重试操作(访问冲突PUSH指令)。 然后,那中间的页面将通过内部循环中成功写入memset

当然,如果相减将导致RSP为堆栈增长保留的地址空间之外点,所有的赌注都关闭。 你甚至可能会导致一些其他线程的堆栈增长。



文章来源: Which exception can be generated when subtracting ESP or RSP register? (stack growing)