[你必须知道的.NET]第二十四回:认识元数据和IL(上)

说在,开篇之前
很早就有说说Metadata(元数据)和IL(中间语言)的想法了,一直在这篇开始才算脚踏实地的对这两个阶级兄弟投去些细关怀,虽然来得没有《第一回:恩怨情仇:is和as》那么迅速,但是Metadata和IL却是绝对重量级的内容,值得我们在任何时间关注,本文就是开始。 

                                                                                      www.anytao.com

1 引言

你可曾想到,我们的C#代码,编译之后究竟为何物?你可曾认知,我们的可执行程序,运行之时的轨迹究竟为哪般?那么,本文通过对Metadata(元数据)和IL(Intermediate Language, 中间语言)的认识开始,来逐步给出答案。在这个探索轨迹上,元数据、IL、程序集、程序域、JIT、虚分派、方法表和托管堆这些形形色色的神秘嘉宾将在某个时刻不期而遇,作为你必须知道的.NET 系列2.0版本的一部分,本文首先从认识元数据和IL这两位重量级选手开始,而其他的嘉宾也将很快登场。

2 初次接触

在事实上,编译之后的cs代码被组织为两种基本的元素:元数据(Metadata)和IL。我们可以以最简单的方式来了解程序集(*.dll)或可执行文件(*.exe)中包含的Metadata和IL的秘密,这种方式就是我们常说的反编译,打开ILDasm并加载实现准备的程序集,我们可以看到托管PE文件的相关内容:

详细的结构信息和IL代码分析,可以参见[你必须知道的.NET]第3章 “一切从IL开始”的介绍,在此就不做太多的分析。另外,我们可以通过执行“View/MetaInfo/Show!”或者Ctrl+M快捷键来获取该程序集所使用的MetaData信息列表:

 

其中该程序集使用的元数据主要有:Module、TypeRef、TypeDef、Method、Param、MemberRef、CostomAttribute、Assembly、AssemblyRef等,同时还包括#Strings、#GUID、#Blob、#US堆等。

当然,关于ILDasm工具,还有很多好玩的使用方式来满足我们探索IL代码的好奇心,例如:

  ildasm Anytao.Insidenet.MetadataIL.exe /output:my.il,将反编译结果导出为il代码格式,生成一个my.il包含了所有的IL代码和一个my.res包含了所有的资源文件。

  ildasm Anytao.Insidenet.MetadataIL.exe /text,将反编译结果以Console形式输出。

当然我们还是推荐以GUI形式来查看IL细节,组织结构良好的Class View:

  ildasm Anytao.Insidenet.MetadataIL.exe

下面首先给出参与编译的相关代码文件,然后再展开我们对Metadata和IL的讨论:

复制代码

// Release : code01, 2009/02/12                    
// Author  : Anytao, http://www.anytao.com
// List    : One.cs
public class One
{
    public int ID { get; set; }
}// Release : code02, 2009/02/12                    
// Author  : Anytao, http://www.anytao.com
// List    : Two.cs
public class Two
{
    public string SayHello()
    {
        return "Hello, world.";
    }
}// Release : code03, 2009/02/12                    
// Author  : Anytao, http://www.anytao.com 
// List    : Program.cs
class Program
{
    static void Main(string[] args)
    {
        int id = 1;
        One one = new One();
        one.ID = id;
        Two two = new Two();
        Console.WriteLine(two.SayHello());
    }
}

复制代码

 

接着,我们对上述程序的编译执行过程进行一点探索,以命令行编译器来演化其大致的编译过程,以此进一步了解托管模块,程序集和可执行文件之间的关系:

 

 

 
  • 打开Visual Studio 2008 Command Prompt,并定位到cs代码所在文件夹,编译One.cs为托管模块,执行命令: 
      csc /t:module One.cs

执行之后,将生成名为One.netmodule文件;

  • 继续执行,将多个模块打包为程序集

 csc /t:library /addmodule:One.netmodule Two.cs

 

执行之后,将生成名为Two.dll文件;

  • 最后,编译Main函数和Two.dll为可执行文件

 csc /out:Anytao.Insidenet.MetatdataIL.exe /t:exe /r:Two.dll /r:mscorlib.dll Program.cs

 

最终将得到本文开始时所加载的用于反编译的程序集文件Anytao.Insidenet.MetadataIL.exe,在该执行命令中对几个指示符开关做点说明:

  • /out:Anytao.Insidenet.MetadataIL.exe,表示输出的可执行文件,及其名称
  • /t:exe,表示输出的文件类型为CUI(控制台界面程序)程序;而/t:winexe,表示输出为GUI(图形界面程序)程序
  • /r:Two.dll,表示引用刚刚生产的Two.dll程序集
  • /r:mscorlib.dll,表示因为外部程序集mscorlib.dll,因为我们的程序中使用了Console静态方法,而该方法则被定义在mscorlib.dll中。mscorlib.dll是如此的重要,我们将在本文之后的某些时候再次与mscorlib.dll握手,那时在对其进行一个详细的分析,敬请期待。

在cmd中的执行过程可以参考:

通过分步执行的方式我们对csc编译器的执行过程有个基本的了解,也同时从侧面认识了每次在Visual Studio中执行“Build“或者“ReBuild”的缩影。综上分析,我们可以简单的看到:

 

Note:在Visual Studio中,编译是分模块进行的,编译结果保存在obj目录中,最后再合并为可执行文件于bin目录,同时默认情况下,编译过程是增量式的,仅编译发生修改的模块,我将在后文给出较为详细的过程。

同时,我们还可以收获以下几个基本的结论:

  • cs代码编译之后将生成元数据和IL,并组成托管模块(Module)的基本单元。

  • 多个托管模块组成程序集,其实还包括一定的资源文件,只是没有在此体现。

  • 程序集或者可执行文件是逻辑组织的基本单元,符合基本的Windows PE文件格式,可以被x86或者x64Windows直接加载执行。

3 继续深入

一个或者多个模块,再加上资源文件就形成了程序集(Assembly),作为逻辑组织的基本单元,

事实上,此图仅仅从粗粒度对程序集的基本组成有个大致的了解,实际上程序集中包含了复杂的结构和要素,例如PE Signature、Managed Resources、Strong Name Signature Hash,而其中最核心的要素则体现在上图。

  • 程序集清单(MANIFEST)包含了程序集的自描述信息,主要包含AssemblyDef、FileDef、ManifestResourceDef和ExportedTypeDef,在反编译选项中MANIFEST包含了详细的内容。在《你必须知道的.NET》3.1节 “从Hello,world开始认识IL”对其有过详细的描述,此不赘述。
  • PE文件头,标准Windows PE头文件(PE32或PE32+),PE文件的基本信息,例如文件类型,创建时间,本地CPU信息等。
  • CLR头,包含CLR版本、模块元数据、资源等信息。
  • 资源文件。

执行View/Statisctics菜单,可以打开相关的统计信息:

复制代码

 File size            : 5632
 PE header size       : 512 (496 used)    ( 9.09%)
 PE additional info   : 1691              (30.02%)
 Num.of PE sections   : 3
 CLR header size     : 72                 ( 1.28%)
 CLR meta-data size  : 2212               (39.28%)
 CLR additional info : 0                  ( 0.00%)
 CLR method headers  : 52                 ( 0.92%)
 Managed code         : 287               ( 5.10%)
 Data                 : 2048              (36.36%)
 Unaccounted          : -1242             (-22.05%)

 Num.of PE sections   : 3
   .text    - 3072
   .rsrc    - 1536
   .reloc   - 512

 CLR meta-data size  : 2212
   Module        -    1 (10 bytes)
   TypeDef       -    4 (56 bytes)      0 interfaces, 0 explicit layout
   TypeRef       -   25 (150 bytes)
   MethodDef     -    8 (112 bytes)     0 abstract, 0 native, 8 bodies
   FieldDef      -    1 (6 bytes)       0 constant
   MemberRef     -   29 (174 bytes)
   ParamDef      -    2 (12 bytes)
   CustomAttribute-   16 (96 bytes)
   StandAloneSig -    4 (8 bytes)
   PropertyMap   -    1 (4 bytes)
   Property      -    1 (6 bytes)
   MethodSemantic-    2 (12 bytes)
   Assembly      -    1 (22 bytes)
   AssemblyRef   -    1 (20 bytes)
   Strings       -   920 bytes
   Blobs         -   328 bytes
   UserStrings   -    68 bytes
   Guids         -    16 bytes
   Uncategorized -   192 bytes

 CLR method headers : 52
   Num.of method bodies  - 8
   Num.of fat headers    - 4
   Num.of tiny headers   - 4

 Managed code : 287
   Ave method size - 35

复制代码

 我们将在后篇《深入程序集和模块》中对PE头,CLR头和资源文件进行详细论述。

  • IL代码被组织为

复制代码

    .class public auto ansi beforefieldinit Anytao.Insidenet.MetadataIL.Two
       extends [mscorlib]System.Object
    {
      .method public hidebysig instance string 
              SayHello() cil managed
      {
        // Code size       11 (0xb)
        .maxstack  1
        .locals init ([0] string CS$1$0000)
        IL_0000:  nop
        IL_0001:  ldstr      "Hello, world."
        IL_0006:  stloc.0
        IL_0007:  br.s       IL_0009

        IL_0009:  ldloc.0
        IL_000a:  ret
      } // end of method Two::SayHello

      .method public hidebysig specialname rtspecialname 
              instance void  .ctor() cil managed
      {
        // Code size       7 (0x7)
        .maxstack  8
        IL_0000:  ldarg.0
        IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
        IL_0006:  ret
      } // end of method Two::.ctor

    } // end of class Anytao.Insidenet.MetadataIL.Two

复制代码

包装在类似于汇编模样的外衣下,我看依稀可见class, System.Object, method, public, string这些面向对象高级语言中的熟悉面孔,不同的只是多了很多benforefieldinit(参考:[你必须知道的.NET]第二十三回:品味细节,深入.NET的类型构造器), ret, maxstack, ldstr, stloc这些陌生的指令。然而IL并非一个怪胎,而正是基于其本身面向对象的汇编式风格,才造就了IL代码成为名副其实的“中间语言”的重任。通过IL代码,CLR就可在编译时由JIT编译转换为Native Code,我们将在下节继续分析这个过程的来龙去脉。

欲知后事如何,且听下文继续:-)
  • 元数据是什么?
  • IL是什么?
  • 元数据和IL在JIT编译时

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/438710.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机无法找到组件c0000135,电脑显示没有找到dwmapi.dll组件怎么办?计算机丢失dwmapi.dll的处理方法...

很多用户在操作Windows系统的过程中发现“没有找到dwmapi.dll”,如果丢失dwmapi.dll组件会导致应用程序无法运行。其实,大家可以尝试在相关网站下载所缺少的组件,或者是通过第三方软件来进行安装下载,这里小编带领大家看看具体解决…

[你必须知道的.NET]第二十五回:认识元数据和IL(中)

说在,开篇之前书接上回[第二十四回:认识元数据和IL(上)],我们对PE文件、程序集、托管模块,这些概念与元数据、IL的关系进行了必要的铺垫,同时顺便熟悉了以ILDASM工具进行反编译的基本方法认知&a…

小学计算机制作表格教案,小学信息技术《表格的制作》教案

小学信息技术《表格的制作》教案教学目标:知识目标:了解什么是网页表格能力目标:学会插入表格;掌握在表格中插入文字和图片的方法;学会设置单元格属性;掌握拆分和合并单元格。情感目标:通过研究…

[你必须知道的.NET]第二十六回:认识元数据和IL(下)

说在,开篇之前书接上回: 第二十四回:认识元数据和IL(上), 第二十五回:认识元数据和IL(中) 我们继续。 终于到了,说说元数据和IL在JIT编译时的角色了&#x…

计算机电子电路原理图,学看电路原理图入门知识积累 - 全文

一、电子电路的意义电路图是人们为了研究和工程的需要,用约定的符号绘制的一种表示电路结构的图形。通过电路图可以知道实际电路的情况。这样,我们在分析电路时,就不必把实物翻来覆去地琢磨,而只要拿着一张图纸就可以了。在设计电…

[你必须知道的.NET]第二十八回:说说Name这回事儿

1 缘起 老赵在谈表达式树的缓存(2):由表达式树生成字符串中提到,在描述Type信息时讨论FullName或者AssemblyQualifiedName提供完整的Type信息,虽是小话题,但却是值得有聊的话题。在.NET中反应一个Type名称…

library的英语怎么读音_【英语角】———学习方法分享

点击蓝字 关注我们每天学习一点点单词的记忆是一件很让人头疼的事情,但单词又是学习英语的基石,非常重要。那么有什么方法能让单词记忆变得简单有效呢?不妨试试下面这些方法吧。1、卡片记忆自制单词卡片,随身带着,有空…

计算机作文叙事,电脑争夺战叙事作文

电脑争夺战叙事作文在生活、工作和学习中,大家一定都接触过作文吧,作文是通过文字来表达一个主题意义的记叙方法。那么你有了解过作文吗?下面是小编帮大家整理的电脑争夺战叙事作文,欢迎阅读与收藏。这是一个温暖的下午&#xff0…

[你必须知道的.NET]第二十九回:.NET十年(上)

引言 语言是程序开发者行走江湖的手上利器,各大门派的高手在论坛、博客为了自家门派争吵不已早是技术世界中的亮丽风景,虽多少为刚刚踏入江湖的新手提供了思考的素材,但也同时迷惑了初出茅庐的前行方向。 本文不欲计较门派的高下&#xff0…

springboot 做表白墙_华广表白墙 第六期|hsl每天都想和你嘻嘻哈哈

1回复第五期 10 没了就没了,不值得就要留恋219级人力4班的银发女生看见你的第一眼就觉得你是一个天使,你的眼睛真的把我迷住了。如果可以的话能不能加你的微信,谢谢?3捞一下13号(周日晚上)21.15左右在校门口益禾堂买奶茶的小姐姐 金发 牛仔…

51系列计算机字长,计算机等级考试之MsOffice练习题第51套

为了让广大各位考生更好的复习,帮考网小编整理提供了2012计算机等级考试一级MsOffice精选题(51),以供各位考生复习参考,希望对考生复习有所帮助。/计算机二级2012计算机等级考试一级MsOffice精选题(51)1)。 正确的IP地址是A) 202.112.111.1B)…

navcat定时备份mysql_Linux实现MYSQl数据库的定时备份

今天给大家分享一下如何在Linux下实现MYSQl数据库的定时备份。前提需要保证你的Linux服务器已经安装了MYSQl数据库服务。1、创建shell脚本vim backupdb.sh创建脚本内容如下:#!/bin/shdb_user"root"db_passwd"123456"db_name"userdb"n…

[你必须知道的.NET]第三十一回,深入.NET 4.0之,从“新”展望

总体来说,这是一篇介绍性的文章,不会涉及过多技术细节和研究过程。但是,作为拉开序幕的第一页,本文以提纲挈领的方式展开对.NET 4.0的初次体验。从What’s new的角度,开始我对.NET 4.0新特性的探索之旅。既然是介绍&am…

苹果计算机磁盘格式,Mac怎么将ntfs格式的磁盘格式化

1. 首先下载NTFS For Mac。下载之后就可以读取NTFS磁盘。2. 插入要格式化的NTFS磁盘。您可以在Mac OS X下通过命令行格式化NTFS磁盘。按照以下步骤进行操作:启动命令行:应用程序 》 工具 》 终端; 输入diskutil获取帮助。格式化命令图:使用di…

[你必须知道的.NET]第三十二回,,深入.NET 4.0之,Tuple一二

Tuple,是函数式编程的概念之一,早见于Elang、F#等动态语言。不过,我第一次听说Tuple还早在2005年园子的Ninputer大牛提出在.NET 2.0实现Tuple的基本想法,我们可以通过以下地址仰慕当时的历史片段: 探讨.NET 2.0中Tuple…

支持商用吗_可商用的插画素材 | 美翻了

好素材在手,天下我有啊...哈哈哈喽大家周末好,那上周公子做的那份工作型插画模板呢,很多小伙伴都来问我素材是哪里找的,自己画的吗当然不是了!其实我在文章中已经提到了,那有的人可能之前用过或可以自己找到…

永恒边境白羊座服务器维护,永恒边境升级攻略 速升50级技巧

永恒边境怎么升级快?分享永恒边境升级攻略,下面我们就一起来看看永恒边境速刷主线支线任务技巧,希望对大家有所帮助。20-30级篇在这个阶段,我们就主线任务和支线任务大家都不要错过了,都要好好抓住,我还可以…

格式化css文件,css文件格式化脚本的方法

这次给大家带来css文件格式化脚本的方法,css文件格式化脚本的注意事项有哪些,下面就是实战案例,一起来看一下。#!/usr/bin/python# -*- coding: UTF-8 -*-import sys,osdef format(ddt):ddt ddt.replace(\n,)#去除换行ddtddt.replace(;},}).…

[你必须知道的.NET]第三十四回,object成员,不见了!

在.NET世界了,object是公认的造物主,其麾下的7大成员,个顶个的横行在任何系统的任何代码角落。 public class Object {public Object();public virtual bool Equals(object obj);public static bool Equals(object objA, object objB);publi…

直接请求接口_http类型的post和get接口测试

我们做接口测试时候,会发现通常需要测试的接口类型有好几种,比较多的是http类型的接口,其他还有webservice接口,rpc接口等等,本次主要说下http类型的接口我们该怎么测试,还有该测试哪些东西。HTTP接口概念:…