【发布时间】:2018-02-02 05:48:45
【问题描述】:
这就是我通过阅读一些内存分割文档的理解:在调用函数时,有几条指令(称为函数序言)将帧指针保存在堆栈上,将堆栈指针的值复制到基指针中并为局部变量节省一些内存。
这是我尝试使用 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.
我知道“将帧指针保存在堆栈上”是由“push rbp”完成的,“将堆栈指针的值复制到基指针中”是由“mov rbp, rsp”完成的,但我得到了什么困惑的是缺少“为局部变量节省一些内存”的“sub rsp $n_bytes”。我在很多展览中都看到了这一点(甚至在 stackoverflow 上的某些主题中)。
我还读到参数应该与基指针有一个正偏移(在它被堆栈指针值填充之后),因为如果它们位于调用者函数中并且堆栈向低地址增长,那么当基指针用堆栈指针值更新,编译器通过添加一些正数返回堆栈。但是我的代码似乎将它们存储在负偏移量中,就像局部变量一样。我也不明白为什么将它们放在那些寄存器中(主要)..它们不应该直接保存在 rsp“偏移量“?
也许这些差异是由于我使用的是 64 位系统,但我的研究并没有让我找到任何可以解释我所面临问题的东西。
【问题讨论】:
-
你能在你的 test_function 中添加对另一个函数的调用吗?看起来 rsp 没有更新,因为它没有在您的函数中使用。如果你调用另一个函数,它必须被更新。
-
是的,我制作了另一个名为“second_test()”的简单函数,只打印了一个字符串。现在在 test_function 中,我有 rsp 的子指令!谢谢
标签: c assembly stack x86-64 red-zone