接著上篇文章內(nèi)容
我們繼續(xù)構(gòu)造兩個函數(shù)的棧幀,GDB調(diào)試,當程序在main函數(shù)停下時,查看寄存器

從匯編代碼可以看出,執(zhí)行完foo函數(shù)后,回到main函數(shù)的返回地址是0x4011e4。
當前的寄存器狀態(tài)如下
(gdb) info registers rbp
rbp 0x7fffe1de03f0 0x7fffe1de03f0
(gdb) info registers rsp
rsp 0x7fffe1de03e0 0x7fffe1de03e0
(gdb) info registers rip
rip 0x4011da 0x4011da <main+15>
(gdb)
繼續(xù)執(zhí)行程序,在foo函數(shù)停下,查看寄存器

從上篇文章,我們知道,BP寄存器存的地址里存的是main函數(shù)的BP地址,那返回地址呢?
在 x86 架構(gòu)中,返回地址通常占用 4 個字節(jié)(32 位系統(tǒng))或 8 個字節(jié)(64 位系統(tǒng))。這個返回地址存儲了函數(shù)執(zhí)行完畢后要返回到的指令地址,用于指示程序繼續(xù)執(zhí)行的位置。
32 位系統(tǒng)(x86):返回地址通常占用 4 個字節(jié),因為在 32 位系統(tǒng)中地址空間是 32 位長。
64 位系統(tǒng)(x86-64):返回地址通常占用 8 個字節(jié),因為在 64 位系統(tǒng)中地址空間是 64 位長。
這個返回地址在函數(shù)調(diào)用時被壓入棧中,用于在函數(shù)執(zhí)行完畢后返回到調(diào)用位置。當函數(shù)執(zhí)行結(jié)束時,程序?qū)倪@個返回地址取出地址值,跳轉(zhuǎn)到該地址以繼續(xù)執(zhí)行程序。
我們打印rbp+8地址存儲的內(nèi)容,恰好是main函數(shù)的返回地址,0x4011e4 <main+25>
(gdb) info registers rbp
rbp 0x7fffe1de03d0 0x7fffe1de03d0
(gdb) x/a 0x7fffe1de03d8
0x7fffe1de03d8: 0x4011e4 <main+25>
(gdb)
由此,我們可以構(gòu)造出兩個函數(shù)的棧幀結(jié)構(gòu)。
這里,我們也可以思考出,函數(shù)調(diào)用棧的解析過程:
因為當前函數(shù)的BP一定在寄存器里,是已知的,然后根據(jù)當前函數(shù)的BP前后數(shù)據(jù)可查到上個函數(shù)的返回地址和BP,依次類推,可以回溯出所有函數(shù)的調(diào)用棧。
High Address
+-----------------+
| 上個函數(shù)的BP |
+-----------------+ <--- BP (0x7fffe1de03f0)
| ... |
+-----------------+ <--- SP (0x7fffe1de03e0)
| main的返回地址 | 0x4011e4 <main+25>
+-----------------+ <--- BP + 8 (0x7fffe1de03d8)
| main函數(shù)的BP | 0x7fffe1de03f0
+-----------------+ <--- BP (0x7fffe1de03d0)
| b |
+-----------------+ <--- BP - 4
| c |
+-----------------+ <--- BP - 8
| a |
+-----------------+ <--- BP - c
| ... |
+-----------------+
| |
| 未使用的空間 |
| |
+-----------------+
Low Address