初识元数据(Metadata)
前文已经介绍过,编译后生成的托管文件包含4 部分内容:PE32(+) 头,CLR 头,元数据以及 IL 代码。
metadata 是一块包含若干个表的二进制数据,这些标分为3 种类别: 定义表(definition tables), 参照表(reference tables) 以及 manifest 表。表 2-1 列出了一些常见的定义表:
元数据 定义表名 | 说明 |
---|---|
ModuleDef | 总是包含一个标示模块的条目,它包含模块的文件名,文件名后缀,模块版本id。 |
TypeDef | 模块中定义的每个类型的条目,它包含了类型名称,父类型,一些标志位 (public, private, 等等) 以及在MethodDef 表中对应方法的索引号,在FieldDef 表中对应字段的索引号,在PropertyDef 表中对应属性的索引号,在EventDef 表中对应事件的索引号。 |
MethodDef | 模块中每个方法的条目,它包含方法名,一些标志位 (private, public, virtual, abstract, static, final, 等等), 签名, 以及对应 IL 代码的偏移量。另外它还能参照到 ParamDef 表中对应的条目。 |
FieldDef | 模块中每个字段的条目,它包含字段名,类型,一些标志位 (private, public, 等等) |
ParamDef | 模块中每个参数的条目,它包含参数名,类型,一些标志位 (in, out, retval, 等等) |
PropertyDef | 模块中每个属性的条目,它包含属性名,类型,一些标志位 |
EventDef | 模块中每个事件的条目,它包含事件名,类型,一些标志位 |
编译器同时也检测源代码参照到的类型,并建立参照表,图 2-2 列出了一些常见的:
元数据参照表名 | 说明 |
---|---|
AssemblyRef | 模块中每个参照程序集的条目,包含了程序集的名称(不含路径,后缀名),版本号,culture 以及公钥令牌 (通常是从公钥生成的一小组哈希值)。另外他还包含了一些标志位和一个哈希值,这个哈希值是这个参照程序集的校验码,CLR 目前不使用这个哈希值,以后可能会用。 |
ModuleRef | 模块中每个参照模块的条目,包含了模块文件名及后缀名(不含路径) |
TypeRef | 模块中每个参照类型的条目,包含类型名称以及一个指向该类型的参照。 |
MemberRef | 模块中每个参照成员(字段,方法,属性以及事件)的条目,包含了成员的名称,签名,以及对应类型的 TypeRef 指针。 |
使用以下命令,用 ILDasm.exe 来察看元数据表:
ILDasm Program.exe
选择 View/MetaInfo/Show! 菜单项 (或按 Ctrl+M),切换到较易读的显示风格:
===========================================================
ScopeName : Program.exe
MVID : {CA73FFE8-0D42-4610-A8D3-9276195C35AA}
===========================================================
Global functions
-------------------------------------------------------
Global fields
-------------------------------------------------------
Global MemberRefs
-------------------------------------------------------
TypeDef #1 (02000002)
-------------------------------------------------------
TypDefName: Program (02000002)
Flags : [Public] [AutoLayout] [Class] [Sealed] [AnsiClass]
[BeforeFieldInit] (00100101)
Extends : 01000001 [TypeRef] System.Object
Method #1 (06000001) [ENTRYPOINT]
-------------------------------------------------------
MethodName: Main (06000001)
Flags : [Public] [Static] [HideBySig] [ReuseSlot] (00000096)
RVA : 0x00002050
ImplFlags : [IL] [Managed] (00000000)
CallCnvntn: [DEFAULT]
ReturnType: Void
No arguments.
Method #2 (06000002)
-------------------------------------------------------
MethodName: .ctor (06000002)
Flags : [Public] [HideBySig] [ReuseSlot] [SpecialName]
[RTSpecialName] [.ctor] (00001886)
RVA : 0x0000205c
ImplFlags : [IL] [Managed] (00000000)
CallCnvntn: [DEFAULT]
hasThis
ReturnType: Void
No arguments.
TypeRef #1 (01000001)
-------------------------------------------------------
Token: 0x01000001
ResolutionScope: 0x23000001
TypeRefName: System.Object
MemberRef #1 (0a000004)
-------------------------------------------------------
Member: (0a000004) .ctor:
CallCnvntn: [DEFAULT]
hasThis
ReturnType: Void
No arguments.
TypeRef #2 (01000002)
-------------------------------------------------------
Token: 0x01000002
ResolutionScope: 0x23000001
TypeRefName: System.Runtime.CompilerServices.CompilationRelaxationsAttribute
MemberRef #1 (0a000001)
-------------------------------------------------------
Member: (0a000001) .ctor:
CallCnvntn: [DEFAULT]
hasThis
ReturnType: Void
1 Arguments
Argument #1: I4
TypeRef #3 (01000003)
-------------------------------------------------------
Token: 0x01000003
ResolutionScope: 0x23000001
TypeRefName: System.Runtime.CompilerServices.RuntimeCompatibilityAttribute
MemberRef #1 (0a000002)
-------------------------------------------------------
Member: (0a000002) .ctor:
CallCnvntn: [DEFAULT]
hasThis
ReturnType: Void
No arguments.
TypeRef #4 (01000004)
-------------------------------------------------------
Token: 0x01000004
ResolutionScope: 0x23000001
TypeRefName: System.Console
MemberRef #1 (0a000003)
-------------------------------------------------------
Member: (0a000003) WriteLine:
CallCnvntn: [DEFAULT]
ReturnType: Void
1 Arguments
Argument #1: String
Assembly
-------------------------------------------------------
Token: 0x20000001
Name : Program
Public Key :
Hash Algorithm : 0x00008004
Version: 0.0.0.0
Major Version: 0x00000000
Minor Version: 0x00000000
Build Number: 0x00000000
Revision Number: 0x00000000
Locale: <null>
Flags : [none] (00000000)
CustomAttribute #1 (0c000001)
-------------------------------------------------------
CustomAttribute Type: 0a000001
CustomAttributeName:
System.Runtime.CompilerServices.CompilationRelaxationsAttribute ::
instance void .ctor(int32)
Length: 8
Value : 01 00 08 00 00 00 00 00 > <
ctor args: (8)
CustomAttribute #2 (0c000002)
-------------------------------------------------------
CustomAttribute Type: 0a000002
CustomAttributeName: System.Runtime.CompilerServices.RuntimeCompatibilityAttribute ::
instance void .ctor()
Length: 30
Value : 01 00 01 00 54 02 16 57 72 61 70 4e 6f 6e 45 78 > T WrapNonEx<
: 63 65 70 74 69 6f 6e 54 68 72 6f 77 73 01 >ceptionThrows <
ctor args: ()
AssemblyRef #1 (23000001)
-------------------------------------------------------
Token: 0x23000001
Public Key or Token: b7 7a 5c 56 19 34 e0 89
Name: mscorlib
Version: 4.0.0.0
Major Version: 0x00000004
Minor Version: 0x00000000
Build Number: 0x00000000
Revision Number: 0x00000000
Locale: <null>
HashValue Blob:
Flags: [none] (00000000)
User Strings
-------------------------------------------------------
70000001 : ( 2) L"Hi"
Coff symbol name overhead: 0
===========================================================
===========================================================
===========================================================
这里你可以看到 Program.exe 包含一个名为Program 的 TypeDef,这个类型是一个继承自System.Object 的 public sealed 的类。该类有两个方法:Main 和 .ctor (构造函数),Main 是一个 public, static 的方法,没有返回值没有参数;构造函数是一个 public 方法也没有返回值没有参数。其中还有一个 this 指针,指向被构造好的该对象地址。
在ILDasm 中选择 View/Statistics 菜单项后,以下信息被显示:
File size : 3584
PE header size : 512 (496 used) (14.29%)
PE additional info : 1411 (39.37%)
Num.of PE sections : 3
CLR header size : 72 ( 2.01%)
CLR meta-data size : 612 (17.08%)
CLR additional info : 0 ( 0.00%)
CLR method headers : 2 ( 0.06%)
Managed code : 20 ( 0.56%)
Data : 2048 (57.14%)
Unaccounted : -1093 (-30.50%)
Num.of PE sections : 3
.text - 1024
.rsrc - 1536
.reloc - 512
CLR meta-data size : 612
Module - 1 (10 bytes)
TypeDef - 2 (28 bytes) 0 interfaces, 0 explicit layout
TypeRef - 4 (24 bytes)
MethodDef - 2 (28 bytes) 0 abstract, 0 native, 2 bodies
MemberRef - 4 (24 bytes)
CustomAttribute- 2 (12 bytes)
Assembly - 1 (22 bytes)
AssemblyRef - 1 (20 bytes)
Strings - 184 bytes
Blobs - 68 bytes
UserStrings - 8 bytes
Guids - 16 bytes
Uncategorized - 168 bytes
CLR method headers : 2
Num.of method bodies - 2
Num.of fat headers - 0
Num.of tiny headers - 2
Managed code : 20
Ave method size - 10
这里可以查看到文件大小,以及各部分的组成。(注意:ILDasm.exe 显示的文件大小并不准确,这似乎是个bug)