为什么没有“sub rsp"?此函数序言中的指令以及为什么函数参数存储在负 rbp 偏移量处? [英] Why is there no "sub rsp" instruction in this function prologue and why are function parameters stored at negative rbp offsets?

查看:21
本文介绍了为什么没有“sub rsp"?此函数序言中的指令以及为什么函数参数存储在负 rbp 偏移量处?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我看了一些内存分割文档是这么理解的:当一个函数被调用时,有几条指令(称为函数序言)将帧指针保存在堆栈上,将堆栈指针的值复制到基指针中并为局部变量节省一些内存.

That's what I understood by reading some memory segmentation documents: when a function is called, there are a few instructions (called function prologue) that save the frame pointer on the stack, copy the value of the stack pointer into the base pointer and save some memory for local variables.

这是我尝试使用 GDB 调试的一个简单代码:

Here's a trivial code I am trying to debug using GDB:

void test_function(int a, int b, int c, int d) {
    int flag;
    char buffer[10];

    flag = 31337;
    buffer[0] = 'A';
}

int main() {
    test_function(1, 2, 3, 4);
}

调试此代码的目的是了解调用函数时堆栈中发生的情况:因此我必须在程序执行的各个步骤(调用函数之前和执行期间)检查内存.虽然我通过检查基指针设法看到了返回地址和保存的帧指针之类的东西,但我真的不明白反汇编代码后我要写什么.

The purpose of debugging this code was to understand what happens in the stack when a function is called: so I had to examine the memory at various step of the execution of the program (before calling the function and during its execution). Although I managed to see things like the return address and the saved frame pointer by examining the base pointer, I really can't understand what I'm going to write after the disassembled code.

拆解:

(gdb) disassemble main
Dump of assembler code for function main:
   0x0000000000400509 <+0>: push   rbp
   0x000000000040050a <+1>: mov    rbp,rsp
   0x000000000040050d <+4>: mov    ecx,0x4
   0x0000000000400512 <+9>: mov    edx,0x3
   0x0000000000400517 <+14>:    mov    esi,0x2
   0x000000000040051c <+19>:    mov    edi,0x1
   0x0000000000400521 <+24>:    call   0x4004ec <test_function>
   0x0000000000400526 <+29>:    pop    rbp
   0x0000000000400527 <+30>:    ret    
End of assembler dump.
(gdb) disassemble test_function 
Dump of assembler code for function test_function:
   0x00000000004004ec <+0>: push   rbp
   0x00000000004004ed <+1>: mov    rbp,rsp
   0x00000000004004f0 <+4>: mov    DWORD PTR [rbp-0x14],edi
   0x00000000004004f3 <+7>: mov    DWORD PTR [rbp-0x18],esi
   0x00000000004004f6 <+10>:    mov    DWORD PTR [rbp-0x1c],edx
   0x00000000004004f9 <+13>:    mov    DWORD PTR [rbp-0x20],ecx
   0x00000000004004fc <+16>:    mov    DWORD PTR [rbp-0x4],0x7a69
   0x0000000000400503 <+23>:    mov    BYTE PTR [rbp-0x10],0x41
   0x0000000000400507 <+27>:    pop    rbp
   0x0000000000400508 <+28>:    ret    
End of assembler dump.

我知道将帧指针保存在堆栈上"是由push rbp"完成的,将堆栈指针的值复制到基指针中"是由mov rbp, rsp"完成的,但是我得到了什么令人困惑的是缺少用于为局部变量节省一些内存"的sub rsp $n_bytes".我在很多展览中都看到了这一点(甚至在 stackoverflow 上的某些主题中).

I understand that "saving the frame pointer on the stack" is done by " push rbp", "copying the value of the stack pointer into the base pointer" is done by "mov rbp, rsp" but what is getting me confused is the lack of a "sub rsp $n_bytes" for "saving some memory for local variables". I've seen that in a lot of exhibits (even in some topics here on stackoverflow).

我还读到参数应该与基指针有一个正偏移量(在它被堆栈指针值填充之后),因为如果它们位于调用者函数中并且堆栈向低地址增长,那么当基指针用堆栈指针值更新,编译器通过添加一些正数返回堆栈.但是我的代码似乎将它们存储在负偏移量中,就像局部变量一样.?

I also read that arguments should have a positive offset from the base pointer (after it's filled with the stack pointer value), since if they are located in the caller function and the stack grows toward lower addresses it makes perfect sense that when the base pointer is updated with the stack pointer value the compiler goes back in the stack by adding some positive numbers. But my code seems to store them in a negative offset, just like local variables.. I also can't understand why they are put in those registers (in the main).. shouldn't they be saved directly in the rsp "offsetted"?

也许这些差异是由于我使用的是 64 位系统,但我的研究并没有让我找到任何可以解释我所面临的问题的东西.

Maybe these differences are due to the fact that I'm using a 64 bit system, but my researches didn't lead me to anything that would explain what I am facing.

推荐答案

适用于 x86-64 的 System V ABI 指定 %rsp 下方 128 字节的 red zone.只要不调用任何其他函数(它是一个叶函数),这 128 个字节就属于该函数.

The System V ABI for x86-64 specifies a red zone of 128 bytes below %rsp. These 128 bytes belong to the function as long as it doesn't call any other function (it is a leaf function).

信号处理程序(和调试器调用的函数)需要尊重红色区域,因为它们实际上是非自愿的函数调用.
test_function 的所有局部变量,这是一个叶函数,适合红色区域,无需调整%rsp.(此外,该函数没有明显的副作用,并且会在任何合理的优化设置下进行优化).

Signal handlers (and functions called by a debugger) need to respect the red zone, since they are effectively involuntary function calls.
All of the local variables of your test_function, which is a leaf function, fit into the red zone, thus no adjustment of %rsp is needed. (Also, the function has no visible side-effects and would be optimized out on any reasonable optimization setting).

您可以使用 -mno-red-zone 进行编译以阻止编译器使用堆栈指针下方的空间.内核代码必须这样做,因为硬件中断没有实现红区.

You can compile with -mno-red-zone to stop the compiler from using space below the stack pointer. Kernel code has to do this because hardware interrupts don't implement a red-zone.

这篇关于为什么没有“sub rsp"?此函数序言中的指令以及为什么函数参数存储在负 rbp 偏移量处?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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