接著上篇文章內(nèi)容
我們繼續(xù)構(gòu)造兩個(gè)函數(shù)的棧幀懈词,GDB調(diào)試,當(dāng)程序在main函數(shù)停下時(shí)框喳,查看寄存器
從匯編代碼可以看出,執(zhí)行完foo函數(shù)后厦坛,回到main函數(shù)的返回地址是0x4011e4五垮。
當(dāng)前的寄存器狀態(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 個(gè)字節(jié)(32 位系統(tǒng))或 8 個(gè)字節(jié)(64 位系統(tǒng))呢蛤。這個(gè)返回地址存儲(chǔ)了函數(shù)執(zhí)行完畢后要返回到的指令地址惶傻,用于指示程序繼續(xù)執(zhí)行的位置。
32 位系統(tǒng)(x86):返回地址通常占用 4 個(gè)字節(jié)其障,因?yàn)樵?32 位系統(tǒng)中地址空間是 32 位長(zhǎng)银室。
64 位系統(tǒng)(x86-64):返回地址通常占用 8 個(gè)字節(jié),因?yàn)樵?64 位系統(tǒng)中地址空間是 64 位長(zhǎng)。
這個(gè)返回地址在函數(shù)調(diào)用時(shí)被壓入棧中蜈敢,用于在函數(shù)執(zhí)行完畢后返回到調(diào)用位置辜荠。當(dāng)函數(shù)執(zhí)行結(jié)束時(shí),程序?qū)倪@個(gè)返回地址取出地址值扶认,跳轉(zhuǎn)到該地址以繼續(xù)執(zhí)行程序侨拦。
我們打印rbp+8地址存儲(chǔ)的內(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)造出兩個(gè)函數(shù)的棧幀結(jié)構(gòu)。
這里叠纹,我們也可以思考出季研,函數(shù)調(diào)用棧的解析過程:
因?yàn)楫?dāng)前函數(shù)的BP一定在寄存器里,是已知的誉察,然后根據(jù)當(dāng)前函數(shù)的BP前后數(shù)據(jù)可查到上個(gè)函數(shù)的返回地址和BP与涡,依次類推,可以回溯出所有函數(shù)的調(diào)用棧持偏。
High Address
+-----------------+
| 上個(gè)函數(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