MSIL入門(二)通過對象看IL

来源:https://www.cnblogs.com/yyfh/archive/2020/07/07/13263078.html

前言 上一篇文章主要介紹了IL的概念以及基礎的示例代碼,在這一篇文章中我們將通過對象調用看IL。 創建對象與調用方法 class Program { static void Main(string[] args) { var obj = new MyClass(); Console.WriteLin ...


前言

上一篇文章主要介紹了IL的概念以及基礎的示例代碼,在這一篇文章中我們將通過對象調用看IL。

創建對象與調用方法

class Program
{
    static void Main(string[] args)
    {
        var obj = new MyClass();
        Console.WriteLine(obj.Say());
    }
}

class MyClass
{
    private const string Str = "Hello";

    public string Say()
    {
        return Str;
    }
}

實例欄位每次創建類型實例的時候都會進行創建,它們屬於這個類型的實例,而靜態欄位由類型的所有實例共用,並且它會在類型載入時創建。某些靜態欄位(文本欄位和映射欄位)從不分配。載入程式只需要記錄要映射的欄位的位置,併在欄位定址時定址這些位置。高級別的編譯器(IL assembler不執行此操作,將其會留給我們開發人員)把實例欄位和三種靜態欄位中的兩種靜態欄位(非文本靜態欄位)的類型,很容易從欄位標記中識別出引用欄位的類型。
當在IL中找到標記時,JIT編譯器不必深入元數據檢索並檢查欄位的標誌。此時所有IL有兩組用於欄位載入和存儲指令。實例欄位的指令為ldfld,ldflda和stfld;靜態欄位的指令是ldsfld,ldsflda和stsfld。嘗試將靜態欄位指令與stance欄位一起使用會導致JIT編譯失敗。逆向組合是可行的,但是它需要將實例指針載入到堆棧上,這當然對於靜態欄位是完全多餘的。對靜態欄位使用實例欄位指令的好處是,它允許以相同的方式訪問靜態欄位和實例欄位。

Callvirt 對象調用後期綁定方法,並且將返回值推送到計算堆棧上。

.field private static literal string Str = "Hello" //靜態公共欄位的定義 

.method private hidebysig static void
    Main(
      string[] args
    ) cil managed
  {
    .entrypoint //主函數,程式的入口
    .maxstack 1 //棧的最大深度
    .locals init (
      [0] class ConsoleApp1.MyClass obj //本地變數的定義
    )

    // [8 9 - 8 10]
    IL_0000: nop //什麼都不做

    // [9 13 - 9 37]
    IL_0001: newobj       instance void ConsoleApp1.MyClass::.ctor() //新建類型為MyClass的對象,並將對象放到堆棧
    IL_0006: stloc.0 //把計算堆棧頂部的值(obj)放到調用堆棧索引0處

    // [10 13 - 10 42]
    IL_0007: ldloc.0      //把調用堆棧索引為0處的值複製到計算堆棧
    IL_0008: callvirt     instance string ConsoleApp1.MyClass::Say() //調用MyClass.Say方法
    IL_000d: call         void  [System.Console]System.Console::WriteLine(string) //調用WriteLine
    IL_0012: nop //什麼都不做

    // [11 9 - 11 10]
    IL_0013: ret //return 

  } // end of method Program::Main

  .method public hidebysig specialname rtspecialname instance void
    .ctor() cil managed
  {
    .maxstack 8 //棧的最大深度

    IL_0000: ldarg.0 //將索引為 0 的參數(this)載入到計算堆棧上。
    IL_0001: call         instance void [System.Runtime]System.Object::.ctor() //從堆棧中取出對象,並調用基類(Object)的構造函數
    IL_0006: nop //什麼都不做
    IL_0007: ret //return 

  } // end of method Program::.ctor
class Program
{
    static void Main(string[] args)
    {
        MyClass obj = new MyClass();
        obj.Name = "Hello";
        obj.Say();
    }
}

public class MyClass
{
    public string Name { get; set; }
        
    public void Say()
    {
        Console.WriteLine(Name);
    }
}
  .class public auto ansi beforefieldinit
  ConsoleApp1.MyClass
    extends [System.Runtime]System.Object
{

  .field private string '<Name>k__BackingField' //自動生成的欄位
    //自動生成獲取屬性值的方法,帶有兩個屬性
    .custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor()
      = (01 00 00 00 )
    .custom instance void [System.Diagnostics.Debug]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [System.Diagnostics.Debug]System.Diagnostics.DebuggerBrowsableState)
      = (01 00 00 00 00 00 00 00 ) // ........
      // int32(0) // 0x00000000 

  .method public hidebysig specialname instance string
    get_Name() cil managed
  {
    .custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor()
      = (01 00 00 00 )
    .maxstack 8 //棧的最大深度

    // [17 30 - 17 34]
    IL_0000: ldarg.0      //將索引為 0 的參數(this)載入到計算堆棧上。
    IL_0001: ldfld        string ConsoleApp1.MyClass::'<Name>k__BackingField' //從堆棧取出對象,訪問對象的指定欄位,並把欄位值存入堆棧
    IL_0006: ret //return 

  } // end of method MyClass::get_Name

  .method public hidebysig specialname instance void
    set_Name(
      string 'value'
    ) cil managed
  {
    .custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor()
      = (01 00 00 00 )
    .maxstack 8 //棧的最大深度

    // [17 35 - 17 39]
    IL_0000: ldarg.0      //將第一個參數(this)載入到計算堆棧上。
    IL_0001: ldarg.1      //將第二個參數載入到計算堆棧上。
    IL_0002: stfld        string ConsoleApp1.MyClass::'<Name>k__BackingField'
    IL_0007: ret //return 

  } // end of method MyClass::set_Name

  .method public hidebysig instance void
    Say() cil managed
  {
    .maxstack 8 //棧的最大深度

    // [20 9 - 20 10]
    IL_0000: nop //什麼都不做

    // [21 13 - 21 37]
    IL_0001: ldarg.0      //將第一個參數(this)載入到計算堆棧上。
    IL_0002: call         instance string ConsoleApp1.MyClass::get_Name()
    IL_0007: call         void [System.Console]System.Console::WriteLine(string)
    IL_000c: nop //什麼都不做

    // [22 9 - 22 10]
    IL_000d: ret

  } // end of method MyClass::Say

  .method public hidebysig specialname rtspecialname instance void
    .ctor() cil managed
  {
    .maxstack 8

    IL_0000: ldarg.0      // this
    IL_0001: call         instance void [System.Runtime]System.Object::.ctor() 
    IL_0006: nop //什麼都不做
    IL_0007: ret //return 

  } // end of method MyClass::.ctor

  .property instance string Name()
  {
    .get instance string ConsoleApp1.MyClass::get_Name() //標識getter
    .set instance void ConsoleApp1.MyClass::set_Name(string) //標識setter
  } // end of property MyClass::Name
} // end of class ConsoleApp1.MyClass


.method private hidebysig static void
    Main(
      string[] args
    ) cil managed
  {
    .entrypoint //主函數,程式的入口
    .maxstack 2
    .locals init (
      [0] class ConsoleApp1.MyClass obj
    ) //本地變數定義

    // [8 9 - 8 10] 
    IL_0000: nop //什麼都不做

    // [9 13 - 9 41]
    IL_0001: newobj       instance void ConsoleApp1.MyClass::.ctor()  //新建類型為MyClass的對象,並將對象放到堆棧
    IL_0006: stloc.0      //把計算堆棧頂部的值(obj)放到調用堆棧索引0處 

    // [10 13 - 10 32]
    IL_0007: ldloc.0      //把調用堆棧索引為0處的值複製到計算堆棧
    IL_0008: ldstr        "Hello" //將字元串"Hello"存入到堆棧
    IL_000d: callvirt     instance void ConsoleApp1.MyClass::set_Name(string) //從堆棧取出對象與參數,並調用對象的指定方法
    IL_0012: nop

    // [11 13 - 11 23]
    IL_0013: ldloc.0      //把調用堆棧索引為0處的值複製到計算堆棧
    IL_0014: callvirt     instance void ConsoleApp1.MyClass::Say() //調用MyClass.Say方法
    IL_0019: nop //什麼都不做

    // [12 9 - 12 10]
    IL_001a: ret //return 

  } // end of method Program::Main


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

更多相關文章
  • 關註公眾號【程式員書單】後回覆“book”即可領取30+精品免費電子書 ​ Go 是一種簡單、小巧、令人愉悅的語言。它也有一些犄角旮旯,但絕大部分是經過精心設計的。它的學習速度令人難以置信,並且規避了其他語言中一些不那麼廣為人知的特性。 現如今越來越多的互聯網公司開始使用go語言,有的初創公司開始使 ...
  • 前言 本文的文字及圖片來源於網路,僅供學習、交流使用,不具有任何商業用途,版權歸原作者所有,如有問題請及時聯繫我們以作處理。 作者:打磨蝦 “遲到”了一個月的高考終於要來了。 正好我得到了一份山東新高考模擬考的成績和山東考試院公佈的一分一段表,以及過去三年的普通高考本科普通批首次志願錄取情況統計。2 ...
  • 一. 安裝依賴包 yum install -y wget yum install -y gcc-c++ yum install -y zlib-devel perl-ExtUtils-MakeMaker yum -y install curl-devel expat-devel gettext-de ...
  • 解決辦法: https://tunatore.wordpress.com/2015/06/15/org-jboss-tools-vpe-xulrunner-xulrunnerbundlenotfoundexception-bundle-org-mozilla-xulrunner-win32-win3 ...
  • **前言** Topological sort 又稱 Topological order,這個名字有點迷惑性,因為拓撲排序並不是一個純粹的排序演算法,它只是針對某一類圖,找到一個可以執行的線性順序。 這個演算法聽起來高大上,如今的面試也很愛考,比如當時我在面我司時有整整一輪是基於拓撲排序的設計。 但它其 ...
  • 前言 面試總是會被問到有沒有用過分散式鎖、redis 鎖,大部分讀者平時很少接觸到,所以只能很無奈的回答 “沒有”。本文通過 Spring Boot 整合 redisson 來實現分散式鎖,並結合 demo 測試結果。 首先看下大佬總結的圖 正文 添加依賴 <!--redis--> <depende ...
  • 本文屬於OData系列 目錄 武裝你的WEBAPI-OData入門 武裝你的WEBAPI-OData便捷查詢 武裝你的WEBAPI-OData分頁查詢 武裝你的WEBAPI-OData資源更新Delta 武裝你的WEBAPI-OData之EDM 武裝你的WEBAPI-OData常見問題 武裝你的WE ...
  • abp版本5.9 概述 數據遷移無非就是兩件事情,1、創建資料庫,並根據實體創建對應的表;2、添加一些初始數據 abp的數據遷移也是完成這兩件事,比較特殊的是它是多租戶saas系統,而且支持不同的租戶有獨立的資料庫。所以abp中的遷移要先遷移戶主Host,再遷移租戶Tenant的資料庫 它的遷移定義 ...
一周排行
  • 比如要拆分“呵呵呵90909086676喝喝999”,下麵當type=0返回的是中文字元串“呵呵呵,喝喝”,type=1返回的是數字字元串“90909086676,999”, private string GetStrings(string str,int type=0) { IList<strin ...
  • Swagger一個優秀的Api介面文檔生成工具。Swagger可以可以動態生成Api介面文檔,有效的降低前後端人員關於Api介面的溝通成本,促進項目高效開發。 1、使用NuGet安裝最新的包:Swashbuckle.AspNetCore。 2、編輯項目文件(NetCoreTemplate.Web.c ...
  • 2020 年 7 月 30 日, 由.NET基金會和微軟 將舉辦一個線上和為期一天的活動,包括 微軟 .NET 團隊的演講者以及社區的演講者。本次線上大會 專註.NET框架構建微服務,演講者分享構建和部署雲原生應用程式的最佳實踐、模式、提示和技巧。有關更多信息和隨時瞭解情況:https://focu... ...
  • #abp框架Excel導出——基於vue #1.技術棧 ##1.1 前端採用vue,官方提供 UI套件用的是iview ##1.2 後臺是abp——aspnetboilerplate 即abp v1,https://github.com/aspnetboilerplate/aspnetboilerp ...
  • 前言 本文的文字及圖片來源於網路,僅供學習、交流使用,不具有任何商業用途,版權歸原作者所有,如有問題請及時聯繫我們以作處理。 作者:碧茂大數據 PS:如有需要Python學習資料的小伙伴可以加下方的群去找免費管理員領取 input()輸入 Python提供了 input() 內置函數從標準輸入讀入一 ...
  • 從12年到20年,python以肉眼可見的趨勢超過了java,成為了當今It界人人皆知的編程語言。 python為什麼這麼火? 網路編程語言搜索指數 適合初學者 Python具有語法簡單、語句清晰的特點,這就讓初學者在學習階段可以把精力集中在編程對象和思維方法上。 大佬都在用 Google,YouT ...
  • 在社會上存在一種普遍的對培訓機構的學生一種歧視的現象,具體表現在,比如:當你去公司面試的時候,一旦你說了你是培訓機構出來的,那麼基本上你就涼了,那麼你瞞著不說,然後又通過了面試成功入職,但是以後一旦在公司被髮現有培訓經歷,可能會面臨被降薪,甚至被辭退,培訓機構出來的學生,在用人單位眼裡就是能力低下的 ...
  • from typing import List# 這道題看了大佬寫的代碼,經過自己的理解寫出來了。# 從最外圍的四周找有沒有為O的,如果有的話就進入深搜函數,然後深搜遍歷# 判斷上下左右的位置是否為Oclass Solution: def solve(self, board: List[List[s ...
  • import requests; import re; import os; # 1.請求網頁 header = { "user-agent":'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/537.36 (KHTML, li ...
  • import requests; import re; import os; import parsel; 1.請求網頁 header = { "user-agent":'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/537. ...