兩個(gè)以上的局部變量的棧分配程序如下:
# vi test3.c
int main()
{
int i, j=2, k=4;
i=3;
i=++i;
k=i+j+k;
return k;
}
本文引用地址:http://www.ex-cimer.com/article/201611/320806.htm 編譯該程序后,用mdb反匯編得出如下結(jié)果:
# gcc test3.c -o test3
# mdb test3
Loading modules: [ libc.so.1 ]
> main::dis
main: pushl %ebp
main+1: movl %esp,%ebp ; main至main+1,創(chuàng)建Stack Frame
main+3: subl $0x18,%esp ; 為局部變量i,j,k分配棧空間,并保證棧16字節(jié)對(duì)齊
main+6: andl $0xf0,%esp
main+9: movl $0,%eax
main+0xe: subl %eax,%esp ; main+6至main+0xe,再次保證棧16字節(jié)對(duì)齊
main+0x10: movl $2,-8(%ebp) ; j=2
main+0x17: movl $4,-0xc(%ebp) ; k=4
main+0x1e: movl $3,-4(%ebp) ; i=3
main+0x25: leal -4(%ebp),%eax ; 將i的地址裝入到EAX
main+0x28: incl (%eax) ; i++
main+0x2a: movl -8(%ebp),%eax ; 將j的值裝入到 EAX
main+0x2d: movl -4(%ebp),%edx ; 將i的值裝入到 EDX
main+0x30: addl %eax,%edx ; j+i,結(jié)果存入EDX
main+0x32: leal -0xc(%ebp),%eax ; 將k的地址裝入到EAX
main+0x35: addl %edx,(%eax) ; i+j+k,結(jié)果存入地址ebp-0xc即k中
main+0x37: movl -0xc(%ebp),%eax ; 將k的值裝入EAX,作為返回值
main+0x3a: leave ; 撤銷Stack Frame
main+0x3b: ret ; main函數(shù)返回
>
問題:為什么3個(gè)變量分配了0x18字節(jié)的棧空間?
在2個(gè)變量的時(shí)候,分配??臻g的指令是:subl $8,%esp
而在3個(gè)局部變量的時(shí)候,分配??臻g的指令是:subl $0x18,%esp
3個(gè)整型變量只需要0xc字節(jié),為何實(shí)際上分配了0x18字節(jié)呢?
答案就是:保持16字節(jié)棧對(duì)齊。
gcc默認(rèn)的編譯是要16字節(jié)棧對(duì)齊的,subl $8,%esp會(huì)使棧16字節(jié)對(duì)齊,而8字節(jié)空間只能滿足2個(gè)局部變量,如果再分配4字節(jié)滿足第3個(gè)局部變量的話,那棧地址就不再16字節(jié)對(duì)齊的,而同時(shí)滿足空間需要而且保持16字節(jié)棧對(duì)齊的最接近的就是0x18。
如果,各定義一個(gè)50字節(jié)和100字節(jié)的字符數(shù)組,在這種情況下,實(shí)際分配多少??臻g呢?答案是0x8+0x40+0x70,即184字節(jié)。
下面動(dòng)手驗(yàn)證一下:
# vi test4.c
int main()
{
char str1[50];
char str2[100];
return 0;
}
# mdb test4
Loading modules: [ libc.so.1 ]
> main::dis
main: pushl %ebp
main+1: movl %esp,%ebp
main+3: subl $0xb8,%esp ; 為兩個(gè)字符數(shù)組分配??臻g,同時(shí)保證16字節(jié)對(duì)齊
main+9: andl $0xf0,%esp
main+0xc: movl $0,%eax
main+0x11: subl %eax,%esp
main+0x13: movl $0,%eax
main+0x18: leave
main+0x19: ret
> 0xb8=D ; 16進(jìn)制換算10進(jìn)制
184
> 0x40+0x70+0x8=X ; 表達(dá)式計(jì)算,結(jié)果指定為16進(jìn)制
b8
>
問題:定義了多個(gè)局部變量時(shí),棧分配順序是怎樣的?
局部變量棧分配的順序是按照變量聲明先后的順序,同一行聲明的變量是按照從左到右的順序入棧的,在test2.c中,變量聲明如下:
int i, j=2, k=4;
而反匯編的結(jié)果中:
movl $2,-8(%ebp) ; j=2
movl $4,-0xc(%ebp) ; k=4
movl $3,-4(%ebp) ; i=3
其中不難看出,i,j,k的棧中的位置如下圖:
+----------------------------+------> 高地址
| EIP (_start函數(shù)的返回地址) |
+----------------------------+
| EBP (_start函數(shù)的EBP) | <------ main函數(shù)的EBP指針(即SFP框架指針)
+----------------------------+
| i (EBP-4) |
+----------------------------+
| j (EBP-8) |
+----------------------------+
| k (EBP-0xc) |
+----------------------------+------> 低地址
評(píng)論