框架指標省略(frame pointer omission)(fpo)
fpo是一種優化,它壓縮或者省略了在棧上為該函式建立框架指標的過程。這個選項加速了函式呼叫,因為不需要建立和移除框架指標(esp,ebp)了。同時,它還解放出了乙個暫存器,用來儲存使用頻率較高的變數。只在intelcpu的架構上才有這種優化。
目前已經討論過的任何一種呼叫約定都儲存了前一函式中棧的資訊(壓棧ebp,然後讓ebp = esp,再移動esp來儲存區域性變數)。乙個fpo的函式可能會儲存前一函式的棧指標(esp,ebp),但是並不為當前的函式呼叫設立ebp。相反,他使用ebp來儲存一些其他的變數。debugger 會計算棧指標,但是debugger必須得到乙個使用fpo的提醒,該提醒是基於fpo型別的資訊的來完成的。
這項特性可以在ms visual c++專業版和企業版中開啟。使用的是編譯器的/oy選項。
fpo的資料結構可以在microsoft的sdk中的winnt.h中找到,其中包含了描述棧框架內容的資訊。這些資訊被使用在debugger上,或者其他的需要在棧中尋找fpo函式的程式中。kv命令可以顯示出包括fpo資訊在內的額外的執行時資訊。
0:000> kv
childebp retaddr
0012ff74 00401009 addemup!addemup (fpo: [2,0,0])
0012ff80 00401115 addemup!main+0x9 (fpo: [0,0,0])
0012ffc0 77e87903 addemup!maincrtstartup+0xb4
0012fff0 00000000 kernel32!baseprocessstart+0x3d (fpo: [non-fpo]
上面的例子中,括號括起來的fpo資料結構的意義分別是:
fpo資料表示形式
(fpo: [ebp addr][x,y,z])
x代表作為引數壓棧了的dwords個數
y代表作為區域性變數壓棧了的dwords個數
z代表在開場**中(prologue)壓棧了的暫存器個數
ebp addr代表
僅在ebp在開場**中儲存了的時候顯示
上面的例子中,由於debugger有正確的symbol,所以debugger會計算出棧底(frame pointer)的位置,而不是在ebp之中儲存它。比如說,第乙個引數的位置是棧底+0x8,返回值的位置是棧底+0x4. 開啟了fpo之後,這些值就不能通過ebp + 0x8這樣拿到了,跟ebp等值的棧底(frame pointer)需要計算才能拿到。
僅僅靠上面的資訊來理解fpo還是感覺有點雲裡霧裡的。
。我總結了一些要點在下面,方便大家更好的理解fpo的一些概念。
下表列出了同樣功能,但是fpo選項不同的彙編**。
未開啟fpo的函式的彙編**
開啟了fpo的函式的彙編**
myfunction:
push ebp
mov ebp, esp
sub esp,
mov eax, [ebp+8]
: :
mov esp, ebp
pop ebp
retd
myfunction:
sub sp,
mov eax, [esp+4+]
: :
add sp,
retd
注意,這裡訪問第乙個引數的**是 mov eax, [ebp+8]
注意,這裡訪問第乙個引數的**是 mov eax, [esp+4+]
下兩表分別列出了同樣功能,但是fpo選項棧內容分配,以及引數的訪問方式。
未開啟fpo的指標指向
棧中的內容
[ebp-04]
[ebp-01][ebp+00]
[ebp+04]
[ebp+08]
第乙個區域性變數的首位址
第乙個區域性變數的最後乙個位元組上乙個ebp的值
返回值,即呼叫該函式之前的eip暫存器的值
第乙個引數的首位址
說明:
因為引數都是從右至左壓棧的,所以ebp+8是最後乙個壓棧的引數,所以是第乙個引數。
因為被呼叫函式中,先將esp向上移動出所有區域性變數的尺寸,然後根據ebp的位置從下到上,區域性變數從第乙個往最後乙個賦值的,所以ebp-1是第乙個區域性變數的最後乙個位元組。
開啟了fpo的指標指向
棧中的內容
[esp]
…
[esp+08]
[esp+11]
[esp+12]
[esp+16]
…
[esp+20]最後乙個區域性變數的第乙個位元組
… 第乙個區域性變數的首位址
第乙個區域性變數的最後乙個位元組
返回值
第乙個引數的首位址
… 前乙個函式的區域性變數
說明:
假設當前fpo的資料為(fpo: [1,2,0])
即引數有1個dwords(4位元組)區域性變數2個dwords(8位元組)壓棧的暫存器為0個(0位元組)
frame pointer omission (fpo) and consequences when debugging, part 1
. frame pointer omission (fpo) and consequences when debugging, part 2
.觀察fpo函式
只要當前函式和前乙個函式的symbol被正確載入的話,debugger就可以計算出棧底指標的位置。
因為ebp被保留下來用作通用暫存器了,並沒有用來建立棧框架,所以沒有必要將這個暫存器壓入棧中。這就是為什麼它不再指向前乙個ebp的原因。
如果fpo函式擁有區域性變數,debugger計算出來的棧底位置指向第乙個區域性變數。
如果fpo函式沒有任何的區域性變數,debugger計算出來的棧底位置指向第乙個被保留下來的暫存器。
如果fpo函式沒有任何區域性變數,也沒有保留的暫存器,debugger計算出來的棧底位置指向沒被使用的棧空間。
讓人迷惑的地方是,當乙個fpo函式,使用fastcall呼叫約定的時候。函式沒有棧底指標,引數也沒有被壓在棧上。儘管如此,這些函式通常都比較小。反彙編前面的函式,就可以看到暫存器是如何被載入的了。
學友認為,上面的話可以總結如下:fpo函式沒有儲存ebp,所以訪問引數等的時候就無法使用ebp了。所以fpo函式依靠symbol中的資訊來計算乙個類似於ebp指向的位置的指標。不同的是,ebp指向的是棧中儲存的前乙個棧底的位置。而現在是指向乙個盡可能接近原始ebp的,在棧中盡可能靠下(大位址端)的位置。
組合語言基礎之七 框架指標的省略(FPO)
框架指標省略 frame pointer omission fpo fpo是一種優化,它壓縮或者省略了在棧上為該函式建立框架指標的過程。這個選項加速了函式呼叫,因為不需要建立和移除框架指標 esp,ebp 了。同時,它還解放出了乙個暫存器,用來儲存使用頻率較高的變數。只在intelcpu的架構上才有...
均幅指標策略框架
均幅指標 atr 是取一定時間週期內的股價波動幅度的移動平均值,主要用於研判買賣時機。均幅指標是顯示市場變化率的指標,由威爾德 welles wilder 在 技術交易系統中的新概念 一書中首次提出,目前已成為眾多指標經常引用的技術量。威爾德發現較高的atr值常發生在市場底部,並伴隨恐慌性拋盤。當其...
Column 省略背上的鍋
今天修改實體類時專案啟動報錯 新增一對多後啟動報錯,新增 column後,正常啟動 getter setter entity table name product type view public class producttypeview id column name product type i...