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

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

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

                                                                                      www.anytao.com

 

3 元数据是什么?

元数据,就是描述数据的数据。这一概念并非CLR之独创,Metadata存在于任何对数据和数据关系中,例如程序集清单信息也被称为程序集元数据。而不同系统的元数据也相应具有本身的特点,.NET元数据也是如此。那么,CLR元数据描述的是哪些内容呢?正如前文的描述一样,编译之后,类型信息将以元数据的形式保存在PE格式文件中。.NET是基于面向对象的,所以元数据描述的主要目标就是面向对象的基本元素:类、类型、属性、方法、字段、参数、特性等,主要包括:

  • 定义表,描述了源代码中定义的类型和成员信息,主要包括:TypeDef、MehodDef、FieldDef、ModuleDef、PropertyDef等。
  • 引用表,描述了源代码中引用的类型和成员信息,引用元素可以是同一程序集的其他模块,也可以是不同程序集的模块,主要包括:AssemblyRef、TypeRef、ModuleRef、MethodsRef等。
  • 指针表,使用指针表引用未知代码,主要包括:MethodPtr、FieldPtr、ParamPtr等。
  • 堆,以stream的形式保存的信息堆,主要包括:#String、#Blob、#US、#GUIDe等。

如前文所述,我们以ILDasm.exe可以通过反编译的方式,通过执行Ctrl+M快捷键来获取该程序集所使用的MetaData信息列表,在.NET中每个模块包含了44个CLR元数据表,如下:

表记录元数据表说明
0(0)ModuleDef描述当前模块
1(0x1)TypeRef描述引用Type,为每个引用到类型保存一条记录
2(0x2)TypeDef描述Type定义,每个Type将在TypeDef表中保存一条记录
3(0x3)FieldPtr描述字段指针,定义类的字段时的中间查找表
4(0x4)FieldDef描述字段定义
5(0x5)MethodPtr描述方法指针,定义类的方法时的中间查找表
6(0x6)MethodDef描述方法定义
7(0x7)ParamPtr描述参数指针,定义类的参数时的中间查找表
8(0x8)ParamDef描述方法的参数定义
9(0x9)InterfaceImpl描述有哪些类型实现了哪些接口
10(0xa)MemberRef描述引用成员的情况,引用成员可以是方法、字段还有属性。
11(0xb)Constant描述了参数、字段和属性的常数值
12(0xc)CustomAttribute描述了特性的定义
13(0xd)FieldMarshal描述了与非托管代码交互时,参数和字段的传递方式。
14(0xe)DeclSecurity描述了对于类、方法和程序集的安全性
15(0xf)ClassLayout描述类加载时的布局信息
16(0x10)FieldLayout描述单个字段的偏移或序号
17(0x11)StandAloneSig描述未被任何其他表引用的签名
18(0x12)EventMap描述类的事件列表
19(0x13)EventPtr描述了事件指针,定义事件时的中间查找表
20(0x14)Event               描述事件
21(0x15)PropertyMap         描述类的属性列表
22(0x16)PropertyPtr         描述了属性指针,定义类的属性时的中间查找表
23(0x17)Property            描述属性
24(0x18)MethodSemantics     描述事件、属性与方法的关联
25(0x19)MethodImpl          描述方法的实现
26(0x1a)ModuleRef           描述外部模块的引用
27(0x1b)TypeSpec            描述了对TypeDef或者TypeRef的说明
28(0x1c)ImplMap             描述了程序集使用的所有非托管代码的方法
29(0x1d)FieldRVA            字段表的扩展,RVA给出了一个字段的原始值位置
30(0x1e)ENCLog              描述在Edit-And-Continue模式中哪些元数据被修改过
31(0x1f)ENCMap              描述在Edit-And-Continue模式中的映射
32(0x20)Assembly            描述程序集定义
33(0x21)AssemblyProcessor   未使用
34(0x22)AssemblyOS          未使用
35(0x23)AssemblyRef         描述引用的程序集
36(0x24)AssemblyRefProcessor未使用
37(0x25)AssemblyRefOS       未使用
38(0x26)File                描述外部文件
39(0x27)ExportedType        描述在同一程序集但不同模块,有哪些类型
40(0x28)ManifestResource    描述资源信息
41(0x29)NestedClass         描述嵌套类型定义
42(0x2a)GenericParam        描述了泛型类型定义或者泛型方法定义所使用的泛型参数
43(0x2b)MethodSpec          描述泛型方法的实例化
44(0x2c)GenericParamConstraint描述了每个泛型参数的约束

然后是6个命名堆:

说明

#String一个AscII string数组,被元数据表所引用,来表示方法名、字段名、类名、变量名以及资源相关字符串,但不包含string literals。
#Blob包含元数据引用的二进制对象,但不包含用户定义对象
#US一个unicode string数组,包含了定义在代码中的字符串(string literals),这些字符串可以直接由ldstr指令加载获取,还记得吗?我们在《第二十二回:字符串驻留(上)---带着问题思考》中对字符串创建过程的论述吗?
#GUID保存了128byte的GUID值,由元数据表引用
#~一个特殊堆,包含了所有的元数据表,会引用其他的堆。
#-一个未压缩的#~堆。除了#-堆,其他堆都是压缩的。

Note:对于#String和#US,一个简单的区别就是:

string hello = "Hello, World";

变量hello名,将保存在#String,而代码中字符串信息“Hello, World”则被保存在#US中。

关于元数据信息的详细描述,例如每个表包含哪些列,不同表间的关系,请参考[Standard ECMA-335]和[The .NET File Format]。

在PE文件格式中,Metadata有着复杂的结构,我试图以数据库管理数据的角度出发来理解元数据的结构和关系,所以表示元数据的逻辑结构被成为元数据表,类似于数据库表有主键和Sechema,元数据表以RID(表索引)和元-元数据表示类同的概念,以TypeDef表为例,通过数据引用关系同时与Field、Method、TypeRef等表发生关联,其他表间又有类似的关系,从而形成一个复杂的类数据库结构:

因此,元数据是保存了类型的编译后数据,是.NET程序运行的基础,我们可以在运行时动态的以反射的方式获取元数据信息,而这些信息在.NET Framework中以System.Type、MethodInfo等封装,例如截取MSDN中一个类间关系的简单示例:

对于每个CLR类型而言都可以通过Object.GetType方法返回其Type,从而任意的取到所有的运行时元数据信息:

// Release : code04, 2009/02/21                    
// Author  : Anytao, http://www.anytao.com 
// List    : Program.cs
private static void ShowMemberInfo()
{var assems = AppDomain.CurrentDomain.GetAssemblies();foreach (Assembly ass in assems){foreach (Type t in ass.GetTypes()){foreach (MemberInfo mi in t.GetMembers()){Console.WriteLine("Name:{0}, Type:{1}", mi.Name, mi.MemberType.ToString());}}}
}

执行上述方法,将获取一个长长的列表,看到很多熟悉的符号:-)

4 IL是什么?

IL,又称为CIL或者MSIL,翻译为中文就是中间语言,由ECMA组织(Standard ECMA-335)提供完整的定义和规范。顾名思义,中间语言正如它的名称所言,任何与CLR兼容的编译器所生成的都是中间语言代码,这是实现CLR跨语言的基础结构之一。IL就像一座桥梁,其指令集独立于CPU指令而存在,可以由JIT编译器在运行时翻译为本地代码执行,连接了任何遵守CLS规范的高级语言,为.NET平台提供了最基本的支持。在[你必须知道的.NET]一书中,我用一整章(第3章 “一切从IL开始”)的篇幅对IL的基本内容进行了相应的介绍,所以关于IL的基础内容例如基本类型、IL分析方法、常见指令、基本运算等,就不在本文有所赘述,只对IL基本内容进行一点小结:

  • IL是一种面向对象的机器语言,因此具有面向对象语言的所有特性,类、对象、继承、多态等仍然是IL语言的基本概念。
  • IL指令独立于CPU指令,CLR通过JIT编译机制将其转换为本地代码。
  • IL和元数据是了解CLR运行机制的重要内容,对于我们打开CLR神秘面纱有着重要的意义。

如前文[初次接触]部分论述的一样,可以通过ILDasm.exe或者Reflector工具对托管代码执行反编译来查看其IL代码,对于很多情况下IL代码分析可以解决很多高级语言隐藏的语法糖游戏,例如C#3.0提出的自动属性、隐式类型、匿名类型、扩展方法等都可以很快从IL分析中找到答案,所以适当的了解IL是必要的。那么我们在下面JIT编译时的一个片段来了解IL代码对于托管程序执行的作用。

另外,Metadata描述了静态的结构,而IL阐释了动态的执行,而IL代码是通过一个4字节大小的地址引用元数据表的。该引用被称为元数据符号(Metadata Token,也就是记录元数据表的位置信息),在ILdasm.exe工具中选中“Show token values”,就可以在IL代码中看到IL代码通过Metadata Token引用元数据表的情况:

.method /*06000003*/ private hidebysig static void  Main(string[] args) cil managed
{.entrypoint// Code size       36 (0x24).maxstack  2.locals /*11000002*/ init ([0] int32 id,[1] class Anytao.Insidenet.MetadataIL.One/*02000004*/ one,[2] class Anytao.Insidenet.MetadataIL.Two/*02000002*/ two)IL_0000:  nopIL_0001:  ldc.i4.1IL_0002:  stloc.0IL_0003:  newobj     instance void Anytao.Insidenet.MetadataIL.One/*02000004*/::.ctor() /* 06000007 */IL_0008:  stloc.1IL_0009:  ldloc.1IL_000a:  ldloc.0IL_000b:  callvirt   instance void Anytao.Insidenet.MetadataIL.One/*02000004*/::set_ID(int32) /* 06000006 */IL_0010:  nopIL_0011:  newobj     instance void Anytao.Insidenet.MetadataIL.Two/*02000002*/::.ctor() /* 06000002 */IL_0016:  stloc.2IL_0017:  ldloc.2IL_0018:  callvirt   instance string Anytao.Insidenet.MetadataIL.Two/*02000002*/::SayHello() /* 06000001 */IL_001d:  call       void [mscorlib/*23000001*/]System.Console/*01000012*/::WriteLine(string) /* 0A000011 */IL_0022:  nopIL_0023:  ret
} // end of method Program::Main

其中,按照ECMA定义的规范,元数据第一个字节表示引用的元数据表,而其余三个字节则表示在相应元数据表中的记录,例如06000003表示了引用了MethodDef(06)表的000003项Main方法。

我们可以通过Type的MetadataToken属性在运行时反射获取类型的元数据符号,例如:

static void Main(string[] args)
{Console.WriteLine(typeof(One).MetadataToken);
}

 

 

有了上述所有的准备,我们就可以着手分析元数据和IL在程序执行时的角色和关联。

欲知后事如何,且听下文继续:-)
  • 《第二十四回:认识元数据和IL(上)
  • 》元数据和IL在JIT编译时

                                                                                      www.anytao.com


 

支持anytao的创业产品Worktile
Worktile,新一代简单好用、体验极致的团队协同、项目管理工具,让你和你的团队随时随地一起工作。完全免费,现在就去了解一下吧。
https://worktile.com

参考文献

  • 《你必须知道的.NET》第3章 “一切从IL开始”
  • DonBox,《.NET本质论》
  • http://www.sloppycode.net/articles/inside-net-assemblies-and-metadata.aspx
  • http://www.codeproject.com/KB/dotnet/dotnetformat.aspx

 

支持(0) 反对(0)

  

#10楼 2009-02-25 09:57 yy125

关注中,元数据和IL是不是和语言无关呢,我用vb写,是不是也生成一样的元数据和IL呢

支持(0) 反对(0)

  

#11楼 [楼主] 2009-02-25 10:06 Anytao

@yy125 
对,这是.NET跨语言的基础,不同的高级语言(基于.NET平台,这是前提)由各自编译器编译之后生成的元数据和IL是统一的。

支持(0) 反对(0)

  

#12楼 2009-02-25 23:45 未登录的包建强

anytao,你这篇写得确实不错,干净利落,一针见血。 
下面说但是, 
你用反射来说明元数据,有点自圆其说。我建议用BinaryStream,代码如下: 
FileStream s = new FileStream("C:\\mdata\\b.exe", FileMode.Open); 
BinaryReader r = new BinaryReader(s); 

byte a, b; 
a = r.ReadByte(); 
b = r.ReadByte(); 

哥哥我就是要一个字节一个字节地去读exe文件,当然,这招儿也是从老外那里学来的。 
参考文献:http://www.cnblogs.com/Jax/archive/2009/01/02/1366888.html

支持(0) 反对(0)

  

#13楼 2009-02-25 23:54 未登录的包建强

@Anders 
《.NET 设计规范--.NET约定、惯用法与模式》,这本书我有,回头我送你好了,算是给我干女儿的见面礼。 
@胖赵 
就是来搅黄你生意的。娃哈哈。。。

支持(0) 反对(0)

  

#14楼 [楼主] 2009-02-26 10:26 Anytao

@未登录的包建强 
不知道说啥了:-)

支持(0) 反对(0)

  

#15楼 2009-02-26 22:54 波波塔

#String 一个AscII string数组 ... 

如果 string 中文test="中文等也是用AscII 存储在 #string里面的吗?

支持(0) 反对(0)

  

#16楼 2009-03-04 21:15 JacksonLin

严重支持

支持(0) 反对(0)

  

#17楼 2009-12-22 14:49 飛翔的小豬

=============================================
•引用表,描述了源代码中引用的类型和成员信息,引用元素可以是同一程序集的其他模块,也可以是不同程序集的模块,主要包括:AssemblyRef、TypeRef、ModuleRef、MethodsRef等。
=============================================
引用表中应该不包括MethodsRef,不存在单独的FieldRef和MethodRef,因为MemberRef包括了指向字段和方法的引用,你的44个CLR元数据表中也没有包含,不知道是不是笔误。
看你的文章要比看专著来的轻松得多。
小弟班门弄斧了。

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

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

相关文章

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

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

[你必须知道的.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接口概念:…

css3加载中动画效果,CSS3实现加载中的动画效果

Loading 的菊花图形组合的不太好,基本上实现这个功能了动画解析这个动画用到的 CSS3 特性:transform 主要使用 transform 属性的 rotate,将线条组合成 Loading 图形 (也就是常见的菊花图形)animation 实现将线条颜色由浅到深,再由深到浅来回变…

[你必须知道的.NET]第三十五回,判断dll是debug还是release,这是个问题

问题的提出 晚上翻着群里的聊天,发现一个有趣的问题:如何通过编码方式来判断一个dll或者exe为debug build还是release build?由于没有太多的讨论,所以我只好自己找点儿办法,试图解决这个问题,为夜生活带点…