Emit學習(2) - IL

来源:http://www.cnblogs.com/elvinle/archive/2016/10/27/6003716.html
-Advertisement-
Play Games

學習Emit必不可少的, 會使用到IL中間代碼. 初見IL代碼, 讓我有一種彙編的感覺, 讓我想起了, 大學時, 學習8051的彙編語言. 多的就不扯了, 直接進入正題, OpCodes指令集是不是有一種讓人望而卻步的感覺, 那麼多, 具體我沒有數過, 但是肯定是比8051的指令多不少, 應該有20 ...


學習Emit必不可少的, 會使用到IL中間代碼. 初見IL代碼, 讓我有一種彙編的感覺, 讓我想起了, 大學時, 學習8051的彙編語言. 多的就不扯了, 直接進入正題, OpCodes指令集是不是有一種讓人望而卻步的感覺, 那麼多, 具體我沒有數過, 但是肯定是比8051的指令多不少, 應該有200多個吧, 不過在實際使用的過程中, 肯定是用不到這麼多的, 所以只要掌握一些常用的就夠用了, 其餘的, 查資料就可以了(大學老師當時也是這麼教的, 實際使用中, 也確實是這樣的)

一、示例

上一篇的結束部分, 貼出了一個中文註釋版的OpCodes文件, 這部分內容跟那個文件是有很大關聯的. 貌似, 貼在這一篇更合適呢...

嗯, 還是應該從示例里去開始講

來源 : http://www.cnblogs.com/zery/p/3366175.html

static void Sum(int sum, string sumStr)
{
            int a, b, c;
            a = 1;
            b = 2;
            c = 3;
            sum = a + b + c;
            sumStr = sum.ToString();
            Console.WriteLine(sumStr);

            for (int i = 0; i < c; i++)
            {
                if (i > b)
                {
                    Console.WriteLine("滿足條件, 跳出迴圈");
                    break;
                }
            }
            Console.ReadKey();
}

 

.method private hidebysig static void Sum(int32 sum, string sumStr) cil managed
{
        .maxstack 2   //定義函數代碼所用堆棧的最大深度,也指Evaluation Stackk中最多能同時存在2個值
        .locals init (    //變數的聲明, (此時已經把num,num2,num3,num4,flag存入了Call Stack中的Record Frame中)
            [0] int32 num,
            [1] int32 num2,
            [2] int32 num3,
            [3] int32 num4,
            [4] bool flag)

        L_0000: nop        //無任何操作, 可忽略
        L_0001: ldc.i4.1   //載入 常量1 到棧中(壓棧)
        L_0002: stloc.0    //從棧中把 常量1 拿出來, 賦值給num(出棧, 此時棧中已經沒有東西了)
        L_0003: ldc.i4.2   //載入 常量2 到棧中(壓棧)
        L_0004: stloc.1 
        L_0005: ldc.i4.3 
        L_0006: stloc.2 

        L_0007: ldloc.0   //將num變數壓棧
        L_0008: ldloc.1   //將變數num2壓棧 (此時棧中有兩個值, num2在上面, num在下麵)
        L_0009: add       //將num,num2求和的結果壓棧(求和的時候, 會把兩個值都提取出來, 所以結束後, 棧中只有一個結果值)
        L_000a: ldloc.2   //將num3壓棧
        L_000b: add       //將num3,(num+num2)求和, 並壓棧, 此時棧中, 只有最後的結果值
        L_000c: starg.s sum //將棧頂的值傳給傳參sum(短格式)

        L_000e: ldarga.s sum  //載入sum的地址到堆棧上(短格式)
        L_0010: call instance string [mscorlib]System.Int32::ToString()  //調用ToString()方法, 完成格式轉換,將結果值放入堆棧中
        L_0015: starg.s sumStr   //將堆棧頂的值傳給傳參sumStr(短格式)

        L_0017: ldarg.1   //將索引為1的傳參(sumStr)載入到堆棧中
        L_0018: call void [mscorlib]System.Console::WriteLine(string)  //調用Console.WriteLine方法

        L_001d: nop 
        L_001e: ldc.i4.0 
        L_001f: stloc.3      // i = 0
        L_0020: br.s L_0043 //無條件跳轉到下麵, 去判斷 i<c 是否成立

        L_0022: nop 
        L_0023: ldloc.3   // i
        L_0024: ldloc.1   // b
        L_0025: cgt         // i > b ? 1 : 0
        L_0027: ldc.i4.0  //壓棧0
        L_0028: ceq         //比較的結果在與0比較, (i > b ? 1 : 0) == 0 ? 1 : 0
        L_002a: stloc.s flag  //將結果存入本地變數flag
        L_002c: ldloc.s flag  //載入flag到堆棧中
        L_002e: brtrue.s L_003e //為真跳轉到 L_003e

        L_0030: nop 
        L_0031: ldstr "\u6ee1\u8db3\u6761\u4ef6, \u8df3\u51fa\u5faa\u73af" //"滿足條件, 跳出迴圈"
        L_0036: call void [mscorlib]System.Console::WriteLine(string)
        L_003b: nop 
        L_003c: br.s L_004d

        L_003e: nop 
        L_003f: ldloc.3    // i
        L_0040: ldc.i4.1  // 1
        L_0041: add        // i + 1
        L_0042: stloc.3   // i = i + 1

        L_0043: ldloc.3  // i
        L_0044: ldloc.2  //c
        L_0045: clt          // i < c ? 1 : 0
        L_0047: stloc.s flag  //將結果傳給 flag
        L_0049: ldloc.s flag  //載入flag變數到堆棧中
        L_004b: brtrue.s L_0022  //為真跳轉 L_0022

        L_004d: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
        L_0052: pop   //移除當前位於計算堆棧頂部的值
        L_0053: ret     //即為  return  標記 返回值
}

ldc.i4.1:  i4--int32, 1--數值, 合起來就是  載入int32的數值1到堆棧中

stloc.0: 0--前面聲明的locals變數組中的第0個  將堆棧頂的值付給locals0變數

ldloc.0: 載入locals0變數到堆棧中

add : 將棧頂的兩個值求和, 並將結果壓棧

二、常用的指令

維基百科:https://en.wikipedia.org/wiki/List_of_CIL_instructions

來源:http://blog.csdn.net/joyhen/article/details/47276433

1. 常用的載入類指令

ldarg (及多個變化形式)

ld -- load , arg -- argument, 對這個大家都不陌生吧, 就不多解釋了

載入方法的參數的值到棧中。除了泛型ldarg(需要一個索引作為參數),還有後其他很多的變化形式。'.'有個數字尾碼的ldarg操作碼來指定需要載入的參數。

a -- address, s -- short

ldarga/ldarga.s表示的是載入參數的地址, 而不是載入參數的值

ldc (及多個變化形式)

c -- constant, const這個關鍵字大家肯定都很熟了, constant表示常量

載入一個常數到棧中

Ldc.I4.2   i4表示是int32的值(1個表示8位), 2表示常量

ldfld (及多個變化形式) 載入一個對象實例的成員到棧中
ldloc (及多個變化形式)

loc -- locals

載入一個本地變數到棧中

ldobj 獲得一個堆對象的所有數據,並將它們放置到棧中. OpCodes:將地址指向的值類型對象複製到計算堆棧的頂部。
ldstr 載入一個字元串數據到棧中

 

2. 常用的彈出操作指令

pop  刪除當前棧頂的值,但是並不影響存儲的值
starg

st -- store

存儲棧頂的值到給出方法的參數,根據索引確定這個參數. OpCodes:將位於計算堆棧頂部的值存儲到位於指定索引的參數槽中

stloc (及多個變化形式) 彈出當前棧頂的值並存儲在一個本地變數列表中,根據所以確定這個參數
stobj 從棧中複製一個特定的類型到指定的記憶體地址
stfld 用從棧中獲得的值替換對象成員的值

 

 3. 常用的其他操作類指令

add, sub, mul, div, rem

用於兩個數加減乘除求模, 並將結果推送到計算堆棧上 

and, or, not, xor 用於在兩個值上進行二進位操作
ceq, cgt, clt

用不同的方法比較兩個在棧上的值

c -- compare

ceq:是否相等 -- 如果這兩個值相等,則將整數值 1 (int32) 推送到計算堆棧上;否則,將 0 (int32) 推送到計算堆棧上

cgt:是否大於 -- 如果第一個值大於第二個值,則將整數值 1 (int32) 推送到計算堆棧上;反之,將 0 (int32) 推送到計算堆棧上。

cgt.un -- 比較兩個無符號的或不可排序的值, un -- unsigned 無符號

clt:是否小於 -- 如果第一個值小於第二個值,則將整數值 1 (int32) 推送到計算堆棧上;反之,將 0 (int32) 推送到計算堆棧上。

box, unbox

在引用類型和值類型之間轉換

box: 裝箱

unbox: 拆箱

ret 退出方法和返回一個值
beq, bgt,bge,ble, blt, switch

控制方法中的條件分支

b -- break, eq,e -- equal

beq:如果兩個值相等,則將控制轉移到目標指令;

bgt:如果第一個值 > 第二個值,則將控制轉移到目標指令

bge:如果第一個值 >= 第二個值,則將控制轉移到目標指令

ble:如果第一個值 <= 第二個值,則將控制轉移到目標指令

blt:如果第一個值 < 第二個值,則將控制轉移到目標指令

switch:實現跳轉表

所有的分支控制操作碼都需要給出一個CIL代碼標簽作為條件為真的跳轉目的地

brtrue

如果 value 為 true、非空或非零,則將控制轉移到目標指令

br/br.s

br:(無條件)中止到代碼標簽

br.s:無條件地將控制轉移到目標指令(短格式)

call 調用一個成員
newarr, newobj

在記憶體中創建一個新的數組或新的對象類型

newarr:將對新的從零開始的一維數組(其元素屬於特定類型)的對象引用推送到計算堆棧上

newobj:創建一個值類型的新對象或新實例,並將對象引用(O 類型)推送到計算堆棧上

 

未完待續......


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • array_keys($arr, $search_value, $strict); ——數組中獲取鍵名的集合。 //參數1 要檢索的數組;參數2 要檢索的鍵值 預設NULL; 參數3 是否嚴格比較( )預設false。參數3是在php5.0加入的 輸出:array(3) { [0]=> string ...
  • 一、Mysql資料庫 1.什麼是資料庫? 資料庫(Database)是按照數據結構來組織、存儲和管理數據的倉庫, 每個資料庫都有一個或多個不同的API用於創建,訪問,管理,搜索和複製所保存的數據。 我們也可以將數據存儲在文件中,但是在文件中讀寫數據速度相對較慢。 所以,現在我們使用關係型資料庫管理系 ...
  • 題目:已知線性表LA和LB中的數據元素按值非遞減有序排列,現要求將LA和LB歸併為一個新的線性表LC,且LC中的數據元素仍按值非遞減有序排列。例如,設 LA=(3,5,8,11) LB=(2,6,8,9,11,15,20) 則 LC=(2,3,5,6,8,8,9,11,11,15,20) 線性表見前 ...
  • 上一篇的介紹中, 並沒有介紹到對象的創建過程, 這一篇主要就介紹一下, 對象的創建過程. 其實熟悉了IL語法之後, 完全可以用Reflector反編譯代碼去查看. 而且正因為有這個工具, 可以對照著Reflecotr中的IL代碼去寫Emit的IL. 好了, 開始正題了, 還是從實例開始: 一、示例 ...
  • asp.net Get和Post傳參和接收參數 Get請求: 對於傳參:test.aspx?name=%e5%bc%a0%e4%b8%89 接收參數的方法: Request.QueryString[“name”] HttpContext.Current.Request[“name”] 兩者接收到的參 ...
  • 在我們以前的項目了,做攝像頭的圖片採集,我們一般還是需要做一個封裝處理的,在較新版本的DevExpress控制項裡面,增加了一個CameraControl控制項,可以直接調用攝像頭顯示的,因此也可以做頭像採集等功能,本文介紹如何基於這個控制項做相關的圖像採集操作。 ...
  • 實例構造器和類(引用類型) 在構造引用類型對象時,在調用類型的實例構造前,為對象分配的記憶體總是被清零。 如果類的修飾符為 ,那麼編譯器生成的預設構造器的可訪問性為 ;否則,構造器會被賦予 訪問性。 一個類型可以有多個構造器,每個構造器必須有不同的簽名,而且每個都可以有不同的可訪問性。類的實例構造器在 ...
  • http://stephencleary.com/projects/ ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...