2007/12/11
强暴.Net程序集 之十一 (方法头的结构:窄头与宽头)
警告:本系列文章为本人原创,只作技术研究之用,您可以引用链接传播,禁止其它的转载方式,禁止用于商业或非法目的, 对于造成的一切后果本人概不负责
MethodDef的Rva定义了一个方法的位置, 每个方法体之前都有一个方法头
方法头分为tiny头 和 fat头两种格式, 方法的前两位定义是tiny还是fat头, Partition II Metadata文档描述如下:
25.4.1 Method header type values
The two least significant bits of the first byte of the method header indicate what type of header is present. These 2 bits will be one and only one of the following:
Value Value Description
CorILMethod_TinyFormat 0x2 The method header is tiny (§25.4.2) .
CorILMethod_FatFormat 0x3 The method header is fat (§25.4.3).
tiny头的格式比较简单, 只有一个字节, 除了最低的0x2外, 其余6位保存IL代码的大小
如果一个方法没有局部变量, 异常处理, 方法小于64字节, 存储栈深度为8时, 那么就使用tiny头
Partition II Metadata文档描述如下:
Start Bit Count of Bits Description
0 2 Flags (CorILMethod_TinyFormat shall be set, see §25.4.4)
2 6 Size, in bytes, of the method body immediately following this header.
fat头的格式就比较复杂, 大小是12个字节, Partition II Metadata文档中描述如下:
Offset Size Field Description
0 12 (bits) Flags Flags (CorILMethod_FatFormat shall be set in bits 0:1, see §25.4.4)
12 (bits) 4 (bits) Size Size of this header expressed as the count of 4-byte integers occupied (currently 3)
2 2 MaxStack Maximum number of items on the operand stack
4 4 CodeSize Size in bytes of the actual method body
8 4 LocalVarSigTok Meta Data token for a signature describing the layout of the local variables for the method. 0 means there are no local variables present
最开始的2个字节中低两位是表示fat头的0x3, 接下来的10是标志(见Partition II Metadata 的 25.4.4 Flags for method headers), 最高4位一直为3
接下来的2个字节是MaxStack, 是存储栈最大深度
之后的4个字节是CodeSize, 是IL代码的大小
最后的4个字节是LocalVarSigTok,是局部变量的特征标识
程序如下:
PBYTE instructions = (PBYTE)GetPtrFromRva(rva, m_pNTHeader, m_pImageBase);
if((instructions[0] & 3) == 0x2)
{
WCHAR lBuffer[64];
methodSize = instructions[0] >> 2;
codeSize = methodSize;
maxstack = 8;
localVariables = 0;
exceptionHandler = false;
initLocals = false;
}
else if((instructions[0] & 3) == 0x3)
{
USHORT flagsSize = *((USHORT*)&instructions[0]);
methodSize = ((flagsSize >> 12) & 0xf) * 4;
if((flagsSize & 0x8) != 0)
{
exceptionHandler = true;
}
else
{
exceptionHandler = false;
}
if((flagsSize & 0x10) != 0)
{
initLocals = true;
}
else
{
initLocals = false;
}
maxstack = *((USHORT*)&instructions[2]);
codeSize = *((DWORD*)&instructions[4]);
localVariables = *((DWORD*)&instructions[8]);
}