本文介绍了减去ESP或RSP寄存器会产生哪个异常? (堆栈增长)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图了解如何准确地分配/分配用于堆栈的内存页面.

I'm trying to understand how exactly memory pages for stack is allocated/assigned.

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

I wrote the following proof-of-concept C-code which obviously causes segmentation fault (on x86_64 Linux):

#include <string.h>

int main()
{
    char a;

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

    return 0;
}

以下汇编代码片段(AT& T语法)是由gcc从上述C程序生成的:

The following fragment of assembly code (AT&T syntax) is generated by gcc from above C-program:

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

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

If I add subq $5555555, %rsp manually before calling 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寄存器后分配了堆栈的虚拟内存页导致了一些硬件异常,并且调用了分配的异常处理程序(当然,在内核空间中).

Then segmentation fault disappears because virtual memory pages for stack was assigned after subtracting rsp register caused some hardware exception and assigned exception handler was called (of course, in kernel space).

我知道在这里调用memset会导致较小的页面错误"异常.但这是另一回事(即分配物理内存页).

I know that calling memset here will cause "minor page fault" exceptions. But it's a different story (i.e. allocating physical memory pages).

我的问题是:调用subq $5555555, %rsp时生成了哪个异常?我建议这将是堆栈错误"异常,但我没有找到确切的证据.

My question is: Which exception was generated when subq $5555555, %rsp is invoked? I suggest it would be "stack fault" exception but I did not find exact proof for it.

推荐答案

我知道了.首先,减去rsp寄存器不会执行任何操作.其次,当我们尝试写入非映射堆栈区域时,较小页面错误"异常处理程序将在内核空间中调用.然后,此页面错误处理程序将检查它是合法的还是非法的.我认为页面错误处理程序与线程的当前堆栈指针进行比较(在我们的情况下,它是保存值rsp的寄存器).如果尝试在进程中写入的地址高于当前堆栈指针,则页面错误处理程序将扩展进程的虚拟地址空间并将其映射到物理页面,否则处理程序会将SIGSEGV发送给该进程.

I figured it out. First of all, subtracting rsp register does nothing. Second, when we try to write to non-mapped stack area "minor page fault" exception handler is invoked in kernel space. Then this page fault handler checks whether it was legal write or non-legal. I think page fault handler compares with current stack pointer of the thread (in our case it's saved value rsp register). If address where process try to write is upper than current stack pointer then page fault handler expand process's virtual address space and maps this virtual page to physical page, otherwise handler sends SIGSEGV to the process.

我使用GDB和/proc/[pid]/maps检查了以下片段:

I examined the following fragment by using GDB and /proc/[pid]/maps:

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)进行时,栈地址范围就会如我上面解释的那样扩展.

When subq $1500016, %rsp is invoked stack address range isn't changed.But when first write happens by movb $44, -1500016(%rbp), stack address range is expanded as I explained above.

这篇关于减去ESP或RSP寄存器会产生哪个异常? (堆栈增长)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-17 15:12