通过GDB调试理解程序栈结构及相关技术疑问咨询
GDB调试x86-64汇编栈帧疑问解答
汇编代码
segment .text global main main: push rbp mov rbp, rsp
GDB分步调试输出
push rbp (gdb) info register rbp rsp rbp 0x1 0x1 rsp 0x7fffffffe738 0x7fffffffe738 (gdb) info frame Stack level 0, frame at 0x7fffffffe740: rip = 0x401140 in main (file.asm:12); saved rip = 0x7ffff7ddd790 source language asm. Arglist at 0x7fffffffe730, args: Locals at 0x7fffffffe730, Previous frame's sp is 0x7fffffffe740 Saved registers: rip at 0x7fffffffe738 (gdb) info symbol 0x7ffff7ddd790 __libc_start_call_main + 128 in section .text of /usr/lib/libc.so.6 (gdb) nexti mov rbp, rsp (gdb) info register rbp rsp rbp 0x1 0x1 rsp 0x7fffffffe730 0x7fffffffe730 (gdb) info frame Stack level 0, frame at 0x7fffffffe740: rip = 0x401141 in main (stack.asm:13); saved rip = 0x7ffff7ddd790 source language asm. Arglist at 0x7fffffffe730, args: Locals at 0x7fffffffe730, Previous frame's sp is 0x7fffffffe740 Saved registers: rbp at 0x7fffffffe730, rip at 0x7fffffffe738 next instruction (gdb) info register rbp rsp rbp 0x7fffffffe730 0x7fffffffe730 rsp 0x7fffffffe730 0x7fffffffe730 (gdb) info frame Stack level 0, frame at 0x7fffffffe740: rip = 0x401144 in main (stack.asm:14); saved rip = 0x7ffff7ddd790 source language asm. Arglist at 0x7fffffffe730, args: Locals at 0x7fffffffe730, Previous frame's sp is 0x7fffffffe740 Saved registers: rbp at 0x7fffffffe730, rip at 0x7fffffffe738
疑问
- 执行
push rbp指令时,首次出现的saved rip = 0x7ffff7ddd790是否为__libc_start_call_main函数栈的初始地址? - 执行第一条
push rbp指令时,info frame与寄存器信息显示栈帧大小为8字节(位于frame at 0x7fffffffe740与rsp 0x7fffffffe738之间),这8字节中存储的是什么内容?如何查看? - 执行第一条
push rbp指令时,若局部变量和参数位于栈帧内,且栈帧范围为0x7fffffffe740到0x7fffffffe738,为何Arglist和Locals的地址为0x7fffffffe730,超出该栈帧范围?
解答
不是。这个
saved rip是从__libc_start_call_main跳转到main函数后,返回时要执行的下一条指令地址,也就是__libc_start_call_main + 128的位置,并非__libc_start_call_main栈的初始地址。当main执行完毕后,CPU会跳回这个地址继续执行libc的收尾逻辑。这8字节里存的是调用
main时保存的返回地址(也就是刚才提到的saved rip的值0x7ffff7ddd790)。可以用GDB的x/gx 0x7fffffffe738命令查看这个地址的内容,x是检查内存的命令,gx表示按8字节(64位)十六进制格式显示。这是因为你还没完成栈帧的初始化(未执行
mov rbp, rsp),GDB此时对栈帧的识别有偏差。在x86-64的标准栈帧中,rbp是栈帧基址,执行mov rbp, rsp后,rbp才会指向当前栈帧的底部,此时GDB才能准确识别局部变量和参数的范围。而在执行push rbp后、mov rbp, rsp前,rbp还是旧值0x1,GDB无法正确解析当前栈帧的边界,所以显示的Arglist和Locals地址是不准确的,等执行完mov rbp, rsp后,栈帧结构才会正确建立。
内容的提问来源于stack exchange,提问作者kilerin
相关产品推荐
相关产品推荐

