讓我們寫一段簡單的代碼來分析
#include <stdio.h>
void foo() {
int a = 1;
int b = 2;
int c = 3;
printf("%p\n", &a);
}
int main(int argc, char const *argv[])
{
foo();
return 0;
}
通過GDB調(diào)試节猿,我們可以查看寄存器和匯編代碼票从,方便我們理解
這里我們?cè)趍ain,foo函數(shù)加上斷點(diǎn)
(gdb) b main
Breakpoint 1 at 0x4011da: file test_rbp.c, line 13.
(gdb) b foo
Breakpoint 2 at 0x40119d: file test_rbp.c, line 4.
通過layout split命令同時(shí)查看源碼和匯編代碼
通過run命令滨嘱,首先進(jìn)入main函數(shù)峰鄙,查看此時(shí)的rbp寄存器存儲(chǔ)的地址為0x7ffe5bd314a0
通過continue命令,繼續(xù)執(zhí)行
進(jìn)入foo函數(shù)停下太雨,查看此時(shí)的rbp為0x7ffe5bd31480
查看rbp這個(gè)地址存儲(chǔ)的內(nèi)容為0x7ffe5bd314a0吟榴,正好是main函數(shù)的基地址,由此我們可以得出囊扳,棧幀的基地址里存儲(chǔ)的是上一個(gè)函數(shù)的基地址吩翻,以便在函數(shù)返回時(shí)恢復(fù)bp寄存器兜看。
我們從匯編代碼還可以看出,a的地址為%rbp-0xc狭瞎,b的地址為%rbp-4细移,c的地址為%rbp-8
因?yàn)闂牡刂酚筛叩刂废虻偷刂窋U(kuò)展,所以這里是減法熊锭。這里我們也可以發(fā)現(xiàn)弧轧,棧幀里的參數(shù)順序與代碼中的順序是不一致的。
由此碗殷,我們可以構(gòu)造出foo函數(shù)的棧幀結(jié)構(gòu)精绎。
High Address
+-----------------+
| 上一個(gè)函數(shù)的返回地址 |
+-----------------+ <--- BP + 8
| 上一個(gè)函數(shù)的BP |
+-----------------+ <--- BP (Base Pointer)
| b |
+-----------------+ <--- BP - 4
| c |
+-----------------+ <--- BP - 8
| a |
+-----------------+ <--- BP - c
| ... |
+-----------------+
| |
| 未使用的空間 |
| |
+-----------------+
Low Address