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
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...