技術 > 堆棧溢出
目錄
No. 1
  堆棧溢出原理
  堆棧 堆棧是一個在計算機科學中經常使用的抽象數據類型。堆棧中的物體具有一個特性: 最後一個放入堆棧中的物體總是被最先拿出來, 這個特性通常稱為後進先處(lifo)隊列. 堆棧中定義了一些操作. 兩個最重要的是push和pop。 push操作在堆棧的頂部加入一 個元素。pop操作相反, 在堆棧頂部移去一個元素, 並將堆棧的大小減一。
  為什麽使用堆棧?
  現代計算機被設計成能夠理解人們頭腦中的高級語言。 在使用高級語言構造程序時 最重要的技術是過程(procedure)和函數(function)。 從這一點來看, 一個過程調用可 以象跳轉(jump)命令那樣改變程序的控製流程, 但是與跳轉不同的是, 當工作完成時, 函數把控製權返回給調用之後的語句或指令。 這種高級抽象實現起來要靠堆棧的幫助。 堆棧也用於給函數中使用的局部變量動態分配空間, 同樣給函數傳遞參數和函數返 回值也要用到堆棧。
  堆棧區域
  堆棧是一塊保存數據的連續內存。 一個名為堆棧指針(sp)的寄存器指嚮堆棧的頂部。 堆棧的底部在一個固定的地址。 堆棧的大小在運行時由內核動態地調整。 cpu實現指令 push和pop, 嚮堆棧中添加元素和從中移去元素。 堆棧由邏輯堆棧幀組成。 當調用函數時邏輯堆棧幀被壓入棧中, 當函數返回時邏輯 堆棧幀被從棧中彈出。 堆棧幀包括函數的參數, 函數地局部變量, 以及恢復前一個堆棧 幀所需要的數據, 其中包括在函數調用時指令指針(ip)的值。 堆棧既可以嚮下增長(嚮內存低地址)也可以嚮上增長, 這依賴於具體的實現。 在我 們的例子中, 堆棧是嚮下增長的。 這是很多計算機的實現方式, 包括intel, motorola, sparc和mips處理器。 堆棧指針(sp)也是依賴於具體實現的。 它可以指嚮堆棧的最後地址, 或者指嚮堆棧之後的下一個空閑可用地址。 在我們的討論當中, sp指嚮堆棧的最後地址。 除了堆棧指針(sp指嚮堆棧頂部的的低地址)之外, 為了使用方便還有指嚮幀內固定 地址的指針叫做幀指針(fp)。 有些文章把它叫做局部基指針(lb-local base pointer)。 從理論上來說, 局部變量可以用sp加偏移量來引用。 然而, 當有字被壓棧和出棧後, 這 些偏移量就變了。 儘管在某些情況下編譯器能夠跟蹤棧中的字操作, 由此可以修正偏移 量, 但是在某些情況下不能。 而且在所有情況下, 要引入可觀的管理開銷。 而且在有些 機器上, 比如intel處理器, 由sp加偏移量訪問一個變量需要多條指令才能實現。 因此, 許多編譯器使用第二個寄存器, fp, 對於局部變量和函數參數都可以引用, 因為它們到fp的距離不會受到push和pop操作的影響。 在intel cpu中, bp(ebp)用於這 個目的。 在motorola cpu中, 除了a7(堆棧指針sp)之外的任何地址寄存器都可以做fp。 考慮到我們堆棧的增長方向, 從fp的位置開始計算, 函數參數的偏移量是正值, 而局部 變量的偏移量是負值。 當一個例程被調用時所必須做的第一件事是保存前一個fp(這樣當例程退出時就可以 恢復)。 然後它把sp復製到fp, 創建新的fp, 把sp嚮前移動為局部變量保留空間。 這稱為 例程的序幕(prolog)工作。 當例程退出時, 堆棧必須被清除幹淨, 這稱為例程的收尾 (epilog)工作。 intel的enter和leave指令, motorola的link和unlink指令, 都可以用於 有效地序幕和收尾工作。
  堆棧溢出
  堆棧溢出就是不顧堆棧中分配的局部數據塊大小,嚮該數據塊寫入了過多的數據,導致數據越界,結果覆蓋了老的堆棧數據。 或者解釋為 在長字符串中嵌入一段代碼,並將過程的返回地址覆蓋為這段代碼的地址,這樣當過程返回時,程序就轉而開始執行這段自編的代碼了.
包含詞
堆棧溢出原理