c - 为什么函数的参数被写入主堆栈帧而不是函数堆栈帧?

标签 c gcc stack gdb

所以我在 gdb 中反汇编了这段 C 代码:

0x08048474 <main+0>: push ebp
0x08048475 <main+1>: mov ebp,esp
0x08048477 <main+3>: sub esp,0x8
0x0804847a <main+6>: and esp,0xfffffff0
0x0804847d <main+9>: mov eax,0x0
0x08048482 <main+14>: sub esp,eax
0x08048484 <main+16>: cmp DWORD PTR [ebp+8],0x1
0x08048488 <main+20>: jg 0x80484ab <main+55>
0x0804848a <main+22>: mov eax,DWORD PTR [ebp+12]
0x0804848d <main+25>: mov eax,DWORD PTR [eax]
0x0804848f <main+27>: mov DWORD PTR [esp+4],eax
0x08048493 <main+31>: mov DWORD PTR [esp],0x80485e5
0x0804849a <main+38>: call 0x804831c <printf@plt>
0x0804849f <main+43>: mov DWORD PTR [esp],0x0
0x080484a6 <main+50>: call 0x804833c <exit@plt>
0x080484ab <main+55>: mov eax,DWORD PTR [ebp+12]
0x080484ae <main+58>: add eax,0x4
0x080484b1 <main+61>: mov eax,DWORD PTR [eax]
0x080484b3 <main+63>: mov DWORD PTR [esp],eax
0x080484b6 <main+66>: call 0x8048414 <check_authentication>
0x080484bb <main+71>: test eax,eax
0x080484bd <main+73>: je 0x80484e5 <main+113>
0x080484bf <main+75>: mov DWORD PTR [esp],0x80485fb
0x080484c6 <main+82>: call 0x804831c <printf@plt>
0x080484cb <main+87>: mov DWORD PTR [esp],0x8048619
0x080484d2 <main+94>: call 0x804831c <printf@plt>
0x080484d7 <main+99>: mov DWORD PTR [esp],0x8048630
0x080484de <main+106>: call 0x804831c <printf@plt>
0x080484e3 <main+111>: jmp 0x80484f1 <main+125>
0x080484e5 <main+113>: mov DWORD PTR [esp],0x804864d
0x080484ec <main+120>: call 0x804831c <printf@plt>
0x080484f1 <main+125>: leave
0x080484f2 <main+126>: ret
End of assembler dump.

我的主要问题围绕这些:

0x080484b3 <main+63>: mov DWORD PTR [esp],eax
0x080484b6 <main+66>: call 0x8048414 <check_authentication>

当我此时单步执行 esp = 0xbffff7e0 时。当我进入 check_authentication 函数 esp = 0xbffff7a0 时。这些行正在写入 (char *) 的地址,该地址是 check_authentication 的参数,但它们将其写入 0xbffff7e0,而不是在 0xbffff7a0 - 0xbffff7e0 的堆栈帧内。我能想到的唯一理由是,堆栈在创建时分配了填充,因为这可能是填充,编译器这样做是为了节省空间?有谁知道是不是这样?为什么它不写入 esp-4 处的地址,而该地址实际上位于函数的堆栈帧内?

编辑:添加内存输出以帮助我糟糕的解释

main() 内部:

(gdb) x/4xw $esp
0xbffff7e0: 0xb8000ce0 0x08048510 0xbffff848 0xb7eafebc

check_authentication()内部:

(gdb) x/32xw $esp
0xbffff7a0: 0x00000000 0x08049744 0xbffff7b8 0x080482d9
0xbffff7b0: 0xb7f9f729 0xb7fd6ff4 0xbffff7e8 0x00000000
0xbffff7c0: 0xb7fd6ff4 0xbffff880 0xbffff7e8 0xb7fd6ff4
0xbffff7d0: 0xb7ff47b0 0x08048510 0xbffff7e8 0x080484bb
0xbffff7e0: 0xbffff9b7 0x08048510 0xbffff848 0xb7eafebc

主0xbffff7e0 = 0xe00c00b8

在 check_authentication 0xbffff7e0 = 0xb7f9ffbf

更改发生在跳转到 check_authentication 之前,但更改是针对 check_authentication 的,所以为什么它在 0xbffff7e0 处,这是 mains() esp 指向的位置,而不是在 check_function 的堆栈帧内。我绞尽脑汁想弄清楚这个问题。

最佳答案

没有“x86 中分配的堆栈帧”。堆栈是一个连续的内存区域,SP 指向“堆栈顶部”(其最低地址)。 程序集不是存储在某个随机地址,而是存储在 [ESP] 中,因此它位于函数的堆栈帧内 - 在 EBP 和当前 ESP 包含之间。 p> <小时/>

PUSH 操作码的定义与以下 C 语句类似:

*--SP = value;   // decrease pointer first, then store

POP

value = *SP++;   // take the value pointed to, then increase pointer
<小时/>

现在,在 CALL check_authentication 之前的这一行,编译器不会生成 PUSHPOP 对,而是执行相当于

*SP = value;

关于c - 为什么函数的参数被写入主堆栈帧而不是函数堆栈帧?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35966570/

相关文章:

c++ - 有哪些不同的可能方法可以降低给定程序中 vector 数组实现堆栈的时间复杂度……?

c - XC8 寄存器声明冲突(例如 TRIS、SSP1CON1 等)

c++ - GLib 类型的位大小和对更奇异的(想想 16 位字符)平台的可移植性

c - 我应该从代表人力资源管理系统中员工的抽象数据类型中抽象出数据库 API 吗?

c - 使用结构在学生列表中找到最大的平均值

c - 为什么没有在 C 中定义 char 的符号?

c++ - 关于 __attribute__ 和 noinline (GCC) 的问题

macos - _SCDynamicStoreCopyProxies 上的错误未找到符号

C 相邻堆栈寻址

c - c 文件的局部变量未在堆栈中创建,其 GCC 编译代码,