快速业务通道

开发学习之.Net中PE文件的结构

作者 佚名技术 来源 NET编程 浏览 发布时间 2012-03-13
e的地址和大小。

  根据笔者当前的认识,v-table只有在此托管文件需要和非托管环境交互的时候才有用(比如这个托管代码要被一个非托管环境调用),在纯的托管环境下可能是没用的。当然,大家都知道C#作为典型的OO语言,也有虚函数的概念,但它的虚函数实现机制和C++中的v-table的实现方式有什么不同,我暂时还不清楚。

  2.文本段(.Text section)

  整个CLR Header是放置在一个文本段中的。这是一个只读的段,包含了元数据表、IL代码、引入表等,整个结构如下图所示:

开发学习之.Net中PE文件的结构_网页教学网webjx.com整理 

  这个段里的各个部分并非同时生成的,上图用带序号的方框来提示这一点,序号低的先生成。

  3.资源

  在托管文件中可以嵌入两种不同类型的资源:非托管的平台相关的资源,或者托管资源。这两种资源存储在PE文件的不同section里(其中托管资源已经在上面的文本段内出现过了,不是吗?),其中非托管资源被放在一个单独的.rsrc段里,而托管资源放在文本段里。

  需要注意的是,IL汇编器在每个托管可执行文件中只能嵌入一个资源文件(.RES)。IL反汇编器会定位到这个section,然后把section中的所有内容作为一个.RES文件释放出来。

  三.元数据的结构

  使用过.net的Reflection功能的人对元数据可能多少都有点概念,它是对整个托管模块的逻辑结构的完整描述,包含了所有在模块中声明和引用的元素。从结构上来说,所有元数据类似于一个关系数据库,里面的数据体现为一组交叉引用的表(而不是树或者什么其他数据结构),并且任何数据都只有一份(其他用到这个数据的位置都将包含一个指向此数据的引用)。从用途上来说,这些表分为三类:定义表(definition table)、引用表(reference table)和清单表(manifest table)。

  整个元数据是一个二进制的数据块,你只能通过工具来查看已生成程序集的元数据信息,如ildasm.exe(你可以在“视图”菜单里找到关于元数据信息显示的命令)。

  (1)元数据结构概览

  下面贴出来的显示信息,是我用ildasm.exe统计了自己写的一个很小的Demo程序中的元数据信息,先放在这里,可以和后面提到的内容相互参考:

  可以看到,在元数据中除了上面我们提到的那些表以外,还有一些用于记录UserString,Guid的堆数据,后面会提到。

  (2)元数据中的父子关系

  元数据中包含很多“父子关系”,如“类--方法”、“方法--参数”等等。如果你想找到和某个父数据对应的所有子数据,遍历这个子数据所在的表可是个糟糕的选择。事实上,对于这种一对多关系,汇编器在构造元数据表的时候,并不仅仅使用数据间的引用关系,而且使用了数据的排列顺序来帮助定位。每个父数据都只含有一个指向其第一个子数据的引用,其子数据的结尾靠下一个父数据的起始引用来定位。这就要求子数据要依照他们的父数据来排序(符合这种条件的元数据被称为“优化的”、“压缩的”元数据,而IL汇编器一般都是生成这种元数据)。下图是书中给出的class-method父子关系的元数据表示意图:

  开发学习之.Net中PE文件的结构_网页教学网webjx.com整理

  (3)元数据结构

  前面曾经提到过,元数据其实就是一个二进制的数据块,所以元数据的内部,就是一个个的named stream。这些stream又分为两种类型,除了前面提到过的Table,还有一类是以Heap的形式体现(见上文代码段中的注释)。下图是书中给出的一个完整的元数据结构图:

  开发学习之.Net中PE文件的结构_网页教学网webjx.com整理

  上面以#开头的就是元数据中可能出现的6个命名流,他们的用途分别是

  #Strings:用来存储元数据项的名字,如类名、方法名等 //Heap Stream

  #Blob: 用来存储一些内部的对象实例,如默认值什么的 //Heap Stream

  #US: 用户定义的字符串常量 //Heap Stream

  #GUID: 包含各种全局统一标志符 //Heap Stream

  #~: “优化的”、“压缩的”元数据,里面的元数据表以优化方式存储(我们在父子关系中刚刚提到过的) //Table Stream

  #-: 非优化的元数据(和#~不能共存) //Table Stream

  其中(#~或#-)、#GUID、#Strings是必不可少的。

  另外,元数据既然被存储在很多表里,那么CLR是如何定位一个元数据项的呢(怎么样定位到某个表的某一行)?这里,它使用了一种叫做Token的机制,每个token占4个字节,其中高位字节表示表序号,剩余三个字节表示表内的行序号。具体这些序号被称为RID(record index),其中行序号从1开始,表序号从0开始。

凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!

分享到: 更多

Copyright ©1999-2011 厦门凌众科技有限公司 厦门优通互联科技开发有限公司 All rights reserved

地址(ADD):厦门软件园二期望海路63号701E(东南融通旁) 邮编(ZIP):361008

电话:0592-5908028 传真:0592-5908039 咨询信箱:web@lingzhong.cn 咨询OICQ:173723134

《中华人民共和国增值电信业务经营许可证》闽B2-20100024  ICP备案:闽ICP备05037997号