本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/gumbour/archive/2009/08/30/4500424.aspx
先來看這一個小函數,猜猜他的運行結果(VC6環境)?
#include <stdio.h>
void b()
{
int data[10];
printf("helloworld!/r/n");
data[11]-=5;
}
int main()
{
b();
return 0;
}
堆棧溢出,肯定不正常,馬上有人叫起來了。
沒錯, 那麼結果是什麼呢,爲什麼會不停打印helloworld呢,我們將用堆棧揭開他的奧祕。
且看main函數彙編代碼。
很簡單, L12 調用b函數, L13對返回值賦0.
這裏有個很關鍵的東東: call
call包含2部分操作,call的下一條指令地址入棧,跳轉,也就是從效果來說,包含push 0040108D 和 jmp 00401005兩條操作。 假如,你打開內存窗口,你會看到,堆棧裏已經有0040108D 這個值了。
10: int main()
11: {
...........
12: b();
00401088 call @ILT+0(b) (00401005)
13: return 0;
0040108D xor eax,eax
14: }
再來看函數b
當你把 printf("helloworld!/r/n"); 替換爲 printf("%08x!/r/n",data[11]);時,你會發現,程序在不停的打印0040108D!, 顯而易見,你修改的data[11]其實就是函數b的返回值地址,而data[11] -= 5;更是巧妙的利用 call 00401005 這條指令正好是5個字節的特點,將返回地址正好修改到了 0040108D ,也就是說函數返回時會再次調用函數b。每次b()都會把返回值改爲b返回的地址,導致b()被不停的調用。
爲什麼data[11]正好是函數的返回值呢,讓我們來看堆棧和任務有和關係
任務(線程)都有一個堆棧,任務創建時創建,任務撤銷時撤銷。 任務的創建本質上包含2點。
1 任務資源的分配(任務TCB和任務堆棧),很多嵌入式操作系統把TCB和堆棧是分配在一起的,比如Vxworks操作系統,其任務ID,堆棧基地址,TCB指針其實指向同一塊內存。 創建任務時要指定任務大小,分配堆棧空間其實是一個特殊的malloc函數,他從堆棧空間分配,而不是從系統空間分配內存。任務堆棧windows下默認比較大,嵌入式OS則比較小,經常64k左右。 而局部變量就保存在堆棧中,當訪問局部變量越界時,就發生了我們常說的"堆棧被踩了",堆棧被踩得話後果嚴重,輕則導致某次運行結果不對(這種問題很難定位),重則導致程序崩潰,例如把上面程序改爲data[11]-=4,則程序直接崩潰。
2 任務的初始化,包含2部分,任務TCB的初始化,並且把TCB和操作系統關聯。
TCB中包含任務的很多東西, 比如任務擁有的信號量的鏈表,文件描述符的鏈表,CPU寄存器的值(任務切換時用的),任務優先級,堆棧地址,任務名稱等等,這些都需要初始化。初始化完成之後,操作系統會把這個任務TCB假如調度隊列,如果加入調度隊列時任務狀態是就緒,那麼當他拿到CPU時就可以直接運行了。
堆棧中包含任務的棧幀,也就是說在函數調用鏈(A call B,B call C,C call D,D call E),那麼堆棧中,ABCDE函數分別對應自己的一段棧幀。以E爲例 E的棧幀包含A函數的傳入參數,函數返回值,局部變量和臨時保存的寄存器值。
函數棧幀在主調函數和被掉函數中分配,在函數返回時釋放,這就是爲什麼局部變量地址在函數返回後其值可能失效。
例如 下面代碼FuncB分配的函數棧幀在FuncB執行完後又被分配給FuncC,FuncC中很可能會踩到FuncB曾經的局部變量。
FuncA{
FuncB();
FuncC();
}
任務(線程)的棧以及上面函數b的棧爲下圖。
*debug版本的函數b其實除了data[10],還在局部變量位置分配了一部分內存用來做調試,不過我們不用關係他。
*爲什麼是data[11],而不是data[10]/data[12]或者其他? x86下編譯器函數入口一般會有2條指令。
push ebp
move ebp,esp
其實就是將ebp作爲幀指針來用(函數幀即爲棧中一個函數所擁有的一段內存)。
而這樣就可以在函數中採用ebp-XXX表示局部變量,用ebp+XXX來表示傳入參數。 函數中經常會有一些push操作,
採用esp對局部變量和參數尋址遠不如用ebp來的省事了,因爲esp是經常變化的,而ebp是相對橫的的。
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/gumbour/archive/2009/08/30/4500424.aspx