编译器使用局部变量而不调整 RSP [英] Compiler using local variables without adjusting RSP

查看:25
本文介绍了编译器使用局部变量而不调整 RSP的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有问题的编译器:了解从小程序编译器使用两个局部变量,不调整栈指针.

In question Compilers: Understanding assembly code generated from small programs the compiler uses two local variables without adjusting the stack pointer.

不调整RSP以使用局部变量似乎中断安全,因此编译器似乎依赖硬件在发生中断时自动切换到系统堆栈.否则,出现的第一个中断会将指令指针压入堆栈并覆盖局部变量.

Not adjusting RSP for the use of local variables seems not interrupt safe and so the compiler seems to rely on the hardware automatically switching to a system stack when interrupts occur. Otherwise, the first interrupt that came along would push the instruction pointer onto the stack and would overwrite the local variable.

那个问题的代码是:

#include <stdio.h>

int main()
{
    for(int i=0;i<10;i++){
        int k=0;
    }
}

那个编译器生成的汇编代码是:

The assembly code generated by that compiler is:

00000000004004d6 <main>:
  4004d6:       55                      push   rbp
  4004d7:       48 89 e5                mov    rbp,rsp
  4004da:       c7 45 f8 00 00 00 00    mov    DWORD PTR [rbp-0x8],0x0
  4004e1:       eb 0b                   jmp    4004ee <main+0x18>
  4004e3:       c7 45 fc 00 00 00 00    mov    DWORD PTR [rbp-0x4],0x0
  4004ea:       83 45 f8 01             add    DWORD PTR [rbp-0x8],0x1
  4004ee:       83 7d f8 09             cmp    DWORD PTR [rbp-0x8],0x9
  4004f2:       7e ef                   jle    4004e3 <main+0xd>
  4004f4:       b8 00 00 00 00          mov    eax,0x0
  4004f9:       5d                      pop    rbp
  4004fa:       c3                      ret    

局部变量是 [rbp-0x8] 处的 i[rbp-0x4] 处的 k.

The local variables are i at [rbp-0x8] and k at [rbp-0x4].

谁能解释一下这个中断问题?硬件确实切换到系统堆栈吗?如何?我的理解有误吗?

Can anyone shine light on this interrupt problem? Does the hardware indeed switch to a system stack? How? Am I wrong in my understanding?

推荐答案

这就是 x86-64 ABI.维基百科的摘要:

在计算中,红色区域是函数堆栈帧中超出当前堆栈指针的固定大小区域,该区域未由该函数保留.被调用函数可以使用红色区域来存储局部变量无需修改堆栈指针的额外开销.这个内存区域不会被中断/异常/信号处理程序修改.System V 使用的 x86-64 ABI 规定了一个 128 字节的红色区域,该区域直接在堆栈指针的当前值下方开始.

In computing, a red zone is a fixed-size area in a function's stack frame beyond the current stack pointer which is not preserved by that function. The callee function may use the red zone for storing local variables without the extra overhead of modifying the stack pointer. This region of memory is not to be modified by interrupt/exception/signal handlers. The x86-64 ABI used by System V mandates a 128-byte red zone which begins directly under the current value of the stack pointer.

在 64 位 Linux 用户代码中是可以的,只要使用不超过 128 个字节即可.这是叶函数最突出使用的优化,即不调用其他函数的函数,

In 64-bit Linux user code it is OK, as long as no more than 128 bytes are used. It is an optimization used most prominently by leaf-functions, i.e. functions which don't call other functions,

如果您使用 -mno-red-zone 选项将示例程序编译为带有 GCC(或兼容编译器)的 64 位 Linux 程序,您d 看到这样生成的代码:

If you were to compile the example program as a 64-bit Linux program with GCC (or compatible compiler) using the -mno-red-zone option you'd see code like this generated:

main:
        push    rbp
        mov     rbp, rsp
        sub     rsp, 16;     <<============  Observe RSP is now being adjusted.
        mov     DWORD PTR [rbp-4], 0
.L3:
        cmp     DWORD PTR [rbp-4], 9
        jg      .L2
        mov     DWORD PTR [rbp-8], 0
        add     DWORD PTR [rbp-4], 1
        jmp     .L3
.L2:
        mov     eax, 0
        leave
        ret

可以在这个godbolt.org 链接.

对于 32 位 Linux 用户程序,不调整堆栈指针是一件坏事.如果您将问题中的代码编译为 32 位代码(使用 -m32 选项)main 将显示如下代码:

For a 32-bit Linux user program it would be a bad thing not to adjust the stack pointer. If you were to compile the code in the question as 32-bit code (using -m32 option) main would appear something like the following code:

main:
        push    ebp
        mov     ebp, esp
        sub     esp, 16;     <<============  Observe ESP is being adjusted.
        mov     DWORD PTR [ebp-4], 0
.L3:
        cmp     DWORD PTR [ebp-4], 9
        jg      .L2
        mov     DWORD PTR [ebp-8], 0
        add     DWORD PTR [ebp-4], 1
        jmp     .L3
.L2:
        mov     eax, 0
        leave
        ret

可以在这个gotbolt.org 链接.

这篇关于编译器使用局部变量而不调整 RSP的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆