複習一下MSIL的一些問題

2021-06-03 02:19:51 字數 2879 閱讀 8092

前陣子俺一直沉迷在遊戲和**中,最近玩累了。

於是回過頭來,突然發現有些東西感覺就像抓不住的水一樣就要被淡忘了。

也許是需要複習一下了,可不能把以前學的全忘光了……

當然,以我的懶惰,所謂的複習也就 基本是隨興複習,沒什麼計畫的亂來了。

msil和堆疊形影不離,兩者的關係就像手術室中的醫生和**。

醫生負責動手術(**部分),**負責把各種工具給醫生準備好(資料部分),以備醫生呼叫。

從一開始我就覺得,堆疊這玩意就像是乙個彈夾,講究先進後出。其基本的操作也就兩種「壓子彈」(push)和「扣扳機發射子彈」(pop)。

話說當乙個方法執行之前和執行完後都需要保證堆疊是空的(官方語言叫堆疊平衡——個人認為和做手術的時候醫生絕對不能把手術刀遺漏到病人身體裡是以乙個意思)。

---------下面看段**

乙個全域性變數和乙個方法

static string s;

string test1()

-------------以下是這個方法的il

.method private hidebysig instance string

test1() cil managed

// end of method iltest1::test1

我們現在來分析乙個方法的il,為什麼突然要貼**呢,因為我覺得這段簡單的**可以很容易的說明堆疊的一些情況。

.method private hidebysig instance string

test1() cil managed

這段是方法宣告,先看看這個宣告

.method告訴大家了,我是乙個方法。

private代表私有。

hidebysig 就相當於new,這個可以自己翻翻書。

instance string  test1() cil managed也就不用說了。

---------------下面接下來講方法內容,

.maxstack  1 這句話定義了彈夾(堆疊)的大小,只有可憐的1啊。。。為什麼是1呢,這就要往下看了。

.locals init ([0] string ss,

[1] string cs$1$0000)  定義了兩個本地變數 string 型別的 ss和 cs$1$0000,其中ss是程式設計師定義的變數,cs$1$0000是系統定義的變數

il_0000:  nop                              --空指令 (這時候堆疊沒有值,彈夾是空的)

il_0001:  ldstr      "123"            --把"123"放到堆疊上(壓了一顆子彈進去,現在彈夾裡有了一顆子彈)

il_0006:  stloc.0                        --把"123"再放到第乙個本地變數裡([0] string ss)相當於 ss = "123"(把子彈射出去了,現在彈夾空了)

il_0007:  ldloc.0                        --把第乙個本地變數再放回堆疊裡(把[0] string ss 壓進彈夾裡了,現在彈夾又變成有一顆子彈)

il_0008:  stsfld     string iltest.iltest1::s   --把堆疊裡的值送到全域性變數 s  中(又把子彈射出去了,現在彈夾又空了)

il_000d:  ldsfld     string iltest.iltest1::s   --把全域性變數 s 放回堆疊(把 s 壓進彈夾裡了,現在彈夾又變成有一顆子彈)

il_0012:  stloc.1                         --把堆疊裡的值再放到第二個本地變數裡([1] string cs$1$0000)(把子彈射出去了,現在彈夾空了)

il_0013:  br.s       il_0015        --跳轉到il_0015指令去,其實就是嚇一跳指令

il_0015:  ldloc.1                         --把第二個本地變數再放回堆疊裡([1] string cs$1$0000壓進彈夾裡了,現在彈夾又變成有一顆子彈)

il_0016:  ret                                --把堆疊裡的值返回給被呼叫者 (現在方法完了,堆疊又沒有值了,彈夾又空了)

看完這段il,也許發現了,這個方法的堆疊上從頭到尾都只有乙個值。而這就是為什麼方法一開始就把堆疊的大小設為1的原因。

那麼這個「1」有多大呢?是乙個位元組嗎,還是乙個字?

其實堆疊裡的每個單元稱之為slot,每個slot裡都可以放乙個託管的物件。int,struct,type等等。所以這個「1」有多大呢,那就要看slot裡放的是什麼了。

到這裡就出來個問題,那麼這個堆疊(我們稱之為方法堆疊吧)是從**來的呢?

那麼我們就要去看另一條il語句了,

在manifest裡有一條il:

.stackreserve 0x00100000,

這句話定義了這個現在的執行緒堆疊大小為0x100000,

也就是1m大小。

而我們所說的方法堆疊其實就是從.stackreserve 0x00100000這個地方劃出來的。

大家應該很熟悉這個介面吧,這是呼叫堆疊介面。

它會告訴你現在執行的這個方法的來龍去脈,告訴你這個方法從**來,中間爬過了多少的山,涉過了多少的河。。。

那麼我們的vs是怎麼記下的這些記錄呢?

原來當clr每呼叫乙個方法時,會從那1m(.stackreserve

0x00100000)的執行緒堆疊中分配出一塊記憶體來儲存這些資訊(我們稱之為堆疊幀)。

下圖是這些記憶體的布局

裡的evaluation stack也是個堆疊的名字,其實這個堆疊就是剛才我們在方法裡一直用來用去的那個

方法堆疊。

為什麼要從il扯到 堆疊來呢,因為我們有時候都會碰到乙個問題

---呼叫遞迴方法的時候經常會產生堆疊溢位的錯誤,

總結一下DLL宣告的一些問題

有關dll的問題現在資料很多,但是很多人寫dll時經常出現呼叫程式無法找到相關的匯出函式的問題,這裡主要的原因是dll在宣告時出的問題。在這裡主要有兩個問題,乙個是呼叫約定的問題,乙個是函式名修飾的問題,而這兩個問題又是相互影響的。一 宣告為 extern c int declspec dllexp...

移動支付遇到的一些問題彙總一下

話說好久不寫部落格,也是醉了.算了不提了.這兩天在弄支付寶,結果出來一大堆問題,比如不能跳轉支付介面,crash,記憶體洩露等等.現在成功了,感覺還是不錯的,把問題彙總一下,由於自己手法不好,大家別笑.公鑰私鑰這就不說了,官網有教程,照著來就行了 我的問題大多是plist檔案配置的問題 plist要...

Linux下的一些問題

執行yum命令報一下錯誤 error rpmdb bdb0113 thread process 9818 140220803434304 failed bdb1507 thread died in berkeley db library error db5 error 30973 from dben...