棧:是程序存放數據內存區域之一,特點是LIFO(後進先出)。
PUSH:入棧
POP:出戰
使用場景:
1.保存動態分配的自動變量使用棧
2.函數調用時,用棧傳遞函數參數,半寸返回地址,返回值
代碼sum.c
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#define MAX (1UL << 20)
typedef unsigned long long u64;
typedef unsigned int u32;
u32 max_addend=MAX;
u64 sum_till_MAX(u32 n)
{
u64 sum;
n++;
sum=n;
if(n<max_addend)
sum+=sum_till_MAX(n);
return sum;
}
int main(int argc,char** argv){
u64 sum=0;
if((argc==2) && isdigit(*(argv[1])))
max_addend=strtoul(argv[1],NULL,0);
if(max_addend>MAX||max_addend==0){
fprintf(stderr,"Invalid number is specified\n");
return 1;
}
sum=sum_till_MAX(0);
printf("sum(0..%lu)=%llu\n",max_addend,sum);
return 0;
}
該程序計算0到命令行參數傳遞過來的數字之間所有的正數和。
圖a是函數調用前的棧,圖b是函數調用後的棧,圖c是再次函數調用後的棧。
棧上保存了函數參數,調用返回地址,上層棧幀指針和函數內部使用的自動變量。
有時,還會用棧保存寄存器,每個函數獨有,稱作棧幀。
此時,需要設置表示棧幀起始地址的幀指針(FP)。
棧指針(SP)永遠指向棧頂!
編譯程序
#gcc -g -Wall -o sum sum.c
啓動gdb調試sum
#gdb sum
(gdb) disas main
從圖中可見call指令自動把返回地址0x8048494壓入棧中
再看sum_till_MAX函數
在棧上保存上層幀的幀指針0x8048494,
然後將新的棧幀賦給幀指針%esp,
然後在棧上分配用於保存自動變量的空間,至此完成棧幀。
0x8(%ebp)指向幀指針+8字節的地址,
-0x10(%ebp)爲指針-10字節的地址
leave指令刪除棧幀,釋放當前的棧,
ret指令爲函數返回,將棧中保存的返回地址POP到程序計數寄存器,控制權返回給調用者。
這是第二次進入sum_till_MAX函數時使用backtrace
獲取當前執行位置,可以通過程序計數器PC獲得,在x86上是eip寄存器,FP是ebp寄存器
下面查看棧的內容,從表示棧頂的SP開始。
(gdb) x/40xw $sp
從棧上的返回地址信息可以看到和之前backtrace結果相同的調用跟蹤信息0x080484c1和0x0804858d
用frame命令查看現在選擇的幀,
frame 1選擇幀1
up選擇下一層的幀
用info命令的frame選項可以查看更詳細的棧幀信息
棧的大小限制
注意,如果上述sum程序不帶參數會引發段錯誤。
#./sum
發生棧溢出。
下面用gdb跟蹤,查看程序計數器PC即可看到程序執行位置
#gdb sum
(gdb) r
(gdb) x/i $pc
這正是將sum_till_MAX的參數PUSH到棧頂的命令
查看棧指針SP的位置
(gdb) p $sp
查看該進程的內存映射
(gdb) i proc mapping
最後一行的[stack]表示棧空間,頂端是0xbf401000,之前看到的棧指針是0xbf3ffff0,超出了棧的範圍發生溢出。
分析內核轉儲的時候無法使用上述命令,可以使用
(gdb) info files或者(gdb) info target得到相同信息
linux棧大小
顯示本機系統支持的棧大小
# ulimit -s
10240
修改棧大小擴大10倍
#ulimit -Ss 102400
這樣就不會棧溢出了
Linux下默認的棧空間大小是10M,可以通過ulimit -s進行查看,不同的Linux發行版本可能不太一樣。下面介紹棧空間大小修改方法。
臨時修改方法:
ulimit -s <新的棧空間大小>
永久修改方法:
1. 可以修改配置文件/etc/security/limits.conf
2. 可以將ulimit -s命令放到/etc/profile中,在任何用戶啓動的時候調用
參考《Debug.Hacks中文版 深入調試的技術和工具-調試時必須的棧知識》
————————————————
版權聲明:本文爲CSDN博主「unix21」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/unix21/article/details/8450182