MSIL是基于栈的语言
MSIL的核心就是一个运算栈,提到栈,大家都知道FILO(First In,Last Out,先进后出)这个特性。在MSIL中,所有的方法、操作数的参数都来自于这个栈上,比如一个Add方法需要两个参数,那么栈顶的两个元素就会弹出。而Add运算完成后,会返回一个值,这个值又将被压到这个栈顶。调用这个Add方法的代码类似下面这样:
ldc.i4.5
ldc.i4.8
callvirt Yuyijq.StudyIL.Add(int,int)
哦?不懂那些命令是啥意思?没关系,猜猜就可以了。你只要知道MSIL是基于栈的语言,那差不多能猜出来ldc.i4.5是往栈顶push个5的。
在MSIL中只有类、方法、字段
不管高层的语言,比如C#、VB.NET提供多少绚丽多彩的程序元素,比如委托、事件、属性。但是在MSIL中只有类、方法、字段这三种程序元素。而这些“神奇”的元素最终都依靠语言各自的编译器生成这三个元素(当然还有一些元数据)。
MSIL难么?难,如果你要知道每条命令的意思是什么,真的很难。MSIL容易学么?容易,把上面的文字再仔细看看就OK了,对于日常分析足够了。
2、 Reflector
大名鼎鼎的Reflector不用多说了,是居家必备。
3、 Debuger(Visual Studio+SOS.dll)
上面两个工具虽然很重要,但是对于一些底层的东西就爱莫能助了,这个时候我们就需要Debuger了。在Windows里首推的调试器是WinDbg。WinDbg相当的强大,不仅仅可以进行User Mode的调试,还可以进行Knerl Mode的调试。但是功能强大,必定使用起来也很麻烦,直到现在我还不能熟练的使用WinDbg。幸运的是,Visual Studio也能提供Debug的功能。
要调试.Net的程序,我们还需要一个SOS.dll的扩展。全称是Son of Strike(不知道为啥要起这么一个奇怪的名字)。SOS可以帮助Visual Studio读取.Net的数据结构。在这一节里,我们就以实例的方式学习Visual Studio+SOS.dll的使用。
我们以一个非常简单的Console程序作为“解剖”的程序。在Visual Studio(我使用的是Visual Studio Team System 2008英文版,其他版本类似)创建一个Console类型的项目后,第一步在项目属性窗口的“调试(Debug)”选项卡里选中“允许非托管代码调试(Enable unmanaged code debuging)”
输入以下代码:
namespace Yuyijq.DotNet.Chapter2
{
class StudyDebuger
{
static void Main()
{
int[] intArr = new int[5];
intArr[0] = 3;
intArr[1] = 5;
}
}
}
在Main方法第二行设置断点,F5启动调试。命中断点后,我们在立即窗口(Immediate Window)(打开立即窗口:菜单栏->调试(Debug)->立即窗口(Immediate))里输入命令:
.load sos.dll
这个命令用于加载sos扩展,sos.dll位于.Net Framework安装的目录中,如果你没有设置环境变量,那就需要在这里输入sos.dll的完整路径。
加载sos扩展之后,就可以享用sos的诸多命令了,sos的所有命令都已感叹号“!”开头,在这里我不准备介绍sos的命令,你可以使用!help获得sos所有命令的列表,然后你还可以通过!help 命令名的方法时获得每个命令的详细介绍,介绍中不仅仅有使用方法,还有示例。不需要弄明白所有命令的使用方法,常用的就这么几个:
!U,!DumpStackObjects(dso),!DumpObject(do),!DumpHeap,!DumpMT,!DumpMD,!DumpStack,!ObjSize,
!DumpDomain,!Name2EE,!DumpClass,!Threads
使用这些命令,基本上就可以印证很多书上跟你说的事儿是不是真的,看看他是不是在“胡扯”,而且你这么一动手,自己亲自印证了以后跟看书获得的资讯完全不是一回事儿。
在后面的内容中,我会常常使用这些命令来探索一些细节内容。