使用局部变量的编译器,无需调整RSP

有问题的编译器:了解小型程序生成的汇编代码,编译器使用两个局部变量,而无需调整堆栈指针。

不为使用局部变量而对 RSP 进行调整似乎 并不安全 ,因此 中断

似乎使编译器依赖于硬件自动切换到系统堆栈。否则,出现的第一个中断会将指令指针压入堆栈,并覆盖局部变量。

该问题的代码是:

#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

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

任何人都可以在这个中断问题上大放异彩吗?硬件确实切换到系统堆栈吗?怎么样?我理解错了吗?

回答:

这就是x86-64 ABI的所谓“红色区域”

。维基百科的摘要:

在计算中,红色区域是函数堆栈帧中超出当前堆栈指针的固定大小区域,该区域未被该函数保留。被调用方函数可以使用红色区域来存储局部变量,

。中断/异常/信号处理程序不能修改此内存区域。System V使用的x86-64

ABI要求一个128字节的红色区域,该区域直接从堆栈指针的当前值开始。

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


如果使用该选项将示例程序编译为带有 GCC (或兼容的编译器)的64位Linux程序,-mno-red-zone则会生成如下所示的代码:

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链接中观察到此代码的生成。

以上是 使用局部变量的编译器,无需调整RSP 的全部内容, 来源链接: utcz.com/qa/397454.html

回到顶部