框架指標的省略(FPO)

2021-06-09 06:47:08 字數 3434 閱讀 6907

框架指標省略(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...