通过阅读一些内存分段文档,我理解了这一点:当一个函数被调用时,有一些指令(称为函数序言)将帧指针保存在堆栈上,复制堆栈指针的值进入基指针并为局部变量保存一些内存。
这是我尝试使用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);
}
调试此代码的目的是了解调用函数时堆栈中发生的情况:因此我必须在执行程序的各个步骤(在调用函数之前和执行期间)检查内存。虽然我通过检查基指针设法看到返回地址和保存的帧指针之类的东西,但我真的无法理解我在反汇编代码之后要写的内容。
拆卸:
(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.
我理解&#34;将帧指针保存在堆栈上#34;由&#34;完成push rbp&#34;,&#34;将堆栈指针的值复制到基指针&#34;由&#34; mov rbp,rsp&#34;完成但令我困惑的是缺少一个&#34; sub rsp $ n_bytes&#34; for&#34;为局部变量保存一些内存&#34;。我在很多展览中都看到了这一点(即使是在stackoverflow上的一些主题)。
我还读到,参数应该与基指针有一个正偏移(在它填充堆栈指针值之后),因为如果它们位于调用函数中并且堆栈朝着较低的地址增长,它会使完美的感觉是,当使用堆栈指针值更新基指针时,编译器会通过添加一些正数来返回堆栈。但是我的代码似乎将它们存储在负偏移中,就像局部变量一样。我也无法理解为什么它们被放入那些寄存器中(在主要中)..不应该直接保存它们rsp&#34;抵消&#34;?
也许这些差异是由于我使用64位系统这一事实,但我的研究并没有引导我去解释我所面临的任何事情。
答案 0 :(得分:6)
System V ABI for x86-64指定red zone
低于%rsp
的128个字节。这128个字节属于该函数,只要它不调用任何其他函数(它是leaf function
)。中断处理程序需要尊重红色区域,因为它们实际上是非自愿的函数调用。你的test_function
的所有局部变量(叶子函数)都适合红色区域,因此没有调整需要%rsp
。 (此外,该功能没有明显的副作用,并且会在任何合理的优化设置上进行优化)。
答案 1 :(得分:2)
但我的代码似乎将它们存储在负偏移量中,就像局部变量
一样
第一个x86_64参数在寄存器上传递,而不是在堆栈上传递。因此,当rbp
设置为rsp
时,它们不在堆栈中,并且不能处于正偏移量。
他们只被推到:
保存第二个函数调用的寄存器状态。
在这种情况下,这不是必需,因为它是leaf function。
使寄存器分配更容易。
但是优化的分配器可以在没有memory spill的情况下做得更好。
如果你有以下情况会有所不同:
缺少&#34; sub rsp $ n_bytes&#34; for&#34;为局部变量保存一些内存&#34;。
问题的叶子功能部分红色区域缺少sub rsp
已经在Why does the x86-64 GCC function prologue allocate less stack than the local variables?