编译器使用本地variables而不调整RSP

问题编译器:了解从小程序生成的汇编代码 ,编译器使用两个局部variables而不调整堆栈指针。

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

这个问题的代码是:

#include <stdio.h> int main() { for(int i=0;i<10;i++){ int k=0; } } 

该编译器生成的汇编代码是:

 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 

局部variables是[rbp-0x8]k [rbp-0x4]

任何人都可以照亮这个中断问题吗? 硬件是否切换到系统堆栈? 怎么样? 我的理解错了吗?

Solutions Collecting From Web of "编译器使用本地variables而不调整RSP"

这是x86-64 ABI的所谓“红色区域”。 维基百科的一个总结:

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

在64位Linux用户代码中,只要不超过128字节,就可以。 这是叶功能最显着的优化,即不调用其他功能的功能,


如果您要使用-mno-red-zone选项将示例程序作为64位Linux程序与GCC (或兼容的编译器)一起编译,您将看到如下所示的代码:

 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将显示如下代码:

 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链接中观察到。