Hello World
Spiga

使用WinDbg获得托管方法的汇编代码

2009-04-01 22:42 by 老赵, 25408 visits

这是一个没有多大价值的小实验,对于大家了解.NET编程等方面几乎没有任何好处,尽管老赵一直强调“基础”,例如扎实的算法和数据结构能力,并且对一些必要的支持,例如操作系统,计算机体系结构,计算机网络有足够的了解,拥有“常识”,在需要的时候有足够的能力去深入了解便可;但是对于还有一些科目,例如“编译原理”,它虽然可以加强对于一个人对程序的理解,但是我也并不觉得这是一条“必经之路”。了解黑盒内部肯定是有好处的,但是是否值得学习还要进行权衡,至少要考虑(1)了解这些对于一个人究竟好处有多大,是否真那么关键;(2)同样了解这些知识,需要了解到多深,是否我们走的是了解这些的“必经之路”。同样,对于那种动辄一个问题就深入“IL”,“系统底层”的做法,老赵对此持保留态度1。当然,对于亲手进行一番尝试和探索的做法,我总是支持的,这表明了一种严谨的治学态度——但是,前提是我们并不是“以此为荣”而去搞这些(老赵也一直强调,谁说搞应用层的技术含量就比搞所谓“底层”要差了),在搞这些之前也已经有必要的根基。我们是为了探索而去研究,不是为了研究而去研究。

有时候,我们需要查看一个托管方法的汇编指令是怎么样的。记得在大学的时候,我们使用gcc -s和objdump来获得一个c程序代码的汇编指令。但是对于.NET程序来说,我们肯定无法轻松地获得这些内容。因为所有的.NET程序都是编译成IL代码的,而只有在运行时才会被JIT编译成本机代码。因此,我们必须要在程序运行之后,再使用某种方式去“探得”汇编指令为何——除非我们可以让JIT在不运行程序的时候编译IL代码,老赵不知道该怎么做,可能需要朋友的提点。

为了进行这个实验,我们先来写一些简单的示例代码:

namespace TestAsm
{
    public static class TestClass
    {
        public static int TestMethod(int i)
        {
            return i;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Before JIT.");
            Console.ReadLine();

            TestClass.TestMethod(1);

            Console.WriteLine("After JIT");
            Console.ReadLine();

            TestClass.TestMethod(1);
        }
    }
}

大家可以新建一个TestAsm项目,将以上代码复制粘贴,并使用Debug模式编译(避免TestMethod方法被内联,这会导致TestMethod永远不会被JIT)2,便可以得到一个TestAsm.exe,这就是我们的试验目标。可以看到代码中调用了两遍TestClass.TestMethod方法,并且分别在调用前使用Console.ReadLine中断,这使我们有了有机会使用WinDbg来进行一番探索。我们先进行一番准备工作:

  1. 运行TestAsm.exe,看到Before JIT字样(最好不要在VS里调试运行,因为这会加入VS的的调试模块——虽然这并不影响试验)。
  2. 打开WinDbg(假设您已经设好了Symbol Path),按F6(或File - Attach to a Process),选择TestAsm.exe并确定。
  3. 加载SOS(例如.load C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\sos.dll)。

现在我们就已经做好了准备。那么我们第一步是什么呢?自然是要找出TestClass.TestMethod方法的“位置”,于是先使用!name2ee命令获得TestClass类的信息:

0:003> !name2ee *!TestAsm.TestClass
Module: 70ca1000 (mscorlib.dll)
--------------------------------------
Module: 00942c5c (TestAsm.exe)
Token: 0x02000002
MethodTable: 0094306c
EEClass: 0094133c
Name: TestAsm.TestClass

“!name2ee *!TestAsm.TestClass”命令的含义是“遍历所有已加载模块,查找TestAsm.TestClass类型”。如果需要的话,您也可以使用“!name2ee modulename typename”的方式来查找指定模块中的指定类型。从输出中我们可以看到MethodTable的地址是0094306c。于是我们使用!dumpmt -md <address>命令来查看TestClass类型的方法描述符(Method Descriptor):

0:003> !dumpmt -md 0094306c
EEClass: 0094133c
Module: 00942c5c
Name: TestAsm.TestClass
mdToken: 02000002  (C:\...\TestAsm\bin\Debug\TestAsm.exe)
BaseSize: 0xc
ComponentSize: 0x0
Number of IFaces in IFaceMap: 0
Slots in VTable: 5
--------------------------------------
MethodDesc Table
   Entry MethodDesc      JIT Name
70e66a70   70ce4934   PreJIT System.Object.ToString()
70e66a90   70ce493c   PreJIT System.Object.Equals(System.Object)
70e66b00   70ce496c   PreJIT System.Object.GetHashCode()
70ed72f0   70ce4990   PreJIT System.Object.Finalize()
0094c040   00943060     NONE TestAsm.TestClass.TestMethod(Int32)

且看TestMethod的JIT栏的状态:“NONE”,这意味着这个方法还没有经过JIT的编译,如果我们此时通过!u <address>命令来查看方法的汇编指令就会看到:

0:003> !u 0094c040
Unmanaged code
0094c040 e8755d9571      call    mscorwks!PrecodeFixupThunk (722a1dba)
0094c045 5e              pop     esi
0094c046 0000            add     byte ptr [eax],al
0094c048 60              pushad
0094c049 30940000000000  xor     byte ptr [eax+eax],dl
0094c050 0000            add     byte ptr [eax],al
0094c052 0000            add     byte ptr [eax],al
0094c054 0000            add     byte ptr [eax],al
0094c056 0000            add     byte ptr [eax],al
0094c058 0000            add     byte ptr [eax],al

这段代码的目的是将方法执行过程导向到JIT进行编译,再执行编译后的本机代码。由于JIT还没有发生,因此我们还无法获得TestMethod方法的汇编指令。

于是我们在WinDbg里按F5(或Debug - Go)让程序继续执行。此时您可以去控制台按下回车,这样就会执行TestMethod方法,接着控制台上会显示After JIT字样,并再一次中断。这样我们可以回到WinDbg按下Ctrl+Break(或Debug - Break)重新进入调试。我们重新查看TestClass的Descriptor,就会发现:

0:003> !dumpmt -md 0094306c
EEClass: 0094133c
Module: 00942c5c
Name: TestAsm.TestClass
mdToken: 02000002  (C:\...\TestAsm\bin\Debug\TestAsm.exe)
BaseSize: 0xc
ComponentSize: 0x0
Number of IFaces in IFaceMap: 0
Slots in VTable: 5
--------------------------------------
MethodDesc Table
   Entry MethodDesc      JIT Name
70e66a70   70ce4934   PreJIT System.Object.ToString()
70e66a90   70ce493c   PreJIT System.Object.Equals(System.Object)
70e66b00   70ce496c   PreJIT System.Object.GetHashCode()
70ed72f0   70ce4990   PreJIT System.Object.Finalize()
01a100d8   00943060      JIT TestAsm.TestClass.TestMethod(Int32)

从JIT栏中可以看出,TestMethod方法的已经经过了JIT,而它的Entry地址也与刚才不同,因为再次调用方法时,已经不需要经过JIT了。现在我们便可继续!u来查看TestMethod的汇编指令:

0:003> !u 01a100d8
Normal JIT generated code
TestAsm.TestClass.TestMethod(Int32)
Begin 01a100d8, size 2d
>>> 01a100d8 55              push    ebp
01a100d9 8bec            mov     ebp,esp
01a100db 83ec08          sub     esp,8
01a100de 894dfc          mov     dword ptr [ebp-4],ecx
01a100e1 833d142e940000  cmp     dword ptr ds:[942E14h],0
01a100e8 7405            je      01a100ef
01a100ea e892a3ae70      call    mscorwks!JIT_DbgIsJustMyCode (724fa481)
01a100ef 33d2            xor     edx,edx
01a100f1 8955f8          mov     dword ptr [ebp-8],edx
01a100f4 90              nop
01a100f5 8b45fc          mov     eax,dword ptr [ebp-4]
01a100f8 8945f8          mov     dword ptr [ebp-8],eax
01a100fb 90              nop
01a100fc eb00            jmp     01a100fe
01a100fe 8b45f8          mov     eax,dword ptr [ebp-8]
01a10101 8be5            mov     esp,ebp
01a10103 5d              pop     ebp
01a10104 c3              ret

关于上面的这段汇编代码,大家可以不去深究,因为这是使用Debug模式编译下的结果,其中的指令会包含一些调试信息(如call mscorwks!JIT_DbgIsJustMyCode)。现在我们也可以看出在JIT前后,一个方法入口点的变化。那么您是否会思考,那么TestMethod在被调用的时候,它的入口点的改变,是如何让调用方得知的呢?难道JIT之后,所有调用TestMethod的方法,其汇编指令还要有所变化吗?为此,我们可以再关注一下Program.Main方法的汇编指令:

0:003> !name2ee *!TestAsm.Program
Module: 70ca1000 (mscorlib.dll)
--------------------------------------
Module: 00942c5c (TestAsm.exe)
Token: 0x02000003
MethodTable: 0094300c
EEClass: 009412d8
Name: TestAsm.Program
0:003> !dumpmt -md 0094300c
EEClass: 009412d8
Module: 00942c5c
Name: TestAsm.Program
mdToken: 02000003  (C:\...\TestAsm\bin\Debug\TestAsm.exe)
BaseSize: 0xc
ComponentSize: 0x0
Number of IFaces in IFaceMap: 0
Slots in VTable: 6
--------------------------------------
MethodDesc Table
   Entry MethodDesc      JIT Name
70e66a70   70ce4934   PreJIT System.Object.ToString()
70e66a90   70ce493c   PreJIT System.Object.Equals(System.Object)
70e66b00   70ce496c   PreJIT System.Object.GetHashCode()
70ed72f0   70ce4990   PreJIT System.Object.Finalize()
0094c015   00943004     NONE TestAsm.Program..ctor()
01a10070   00942ff8      JIT TestAsm.Program.Main(System.String[])
0:003> !u 01a10070
Normal JIT generated code
TestAsm.Program.Main(System.String[])
Begin 01a10070, size 57
>>> 01a10070 55              push    ebp
01a10071 8bec            mov     ebp,esp
01a10073 50              push    eax
01a10074 894dfc          mov     dword ptr [ebp-4],ecx
01a10077 833d142e940000  cmp     dword ptr ds:[942E14h],0
01a1007e 7405            je      01a10085
01a10080 e8fca3ae70      call    mscorwks!JIT_DbgIsJustMyCode (724fa481)
01a10085 90              nop
01a10086 8b0d3020bd02    mov     ecx,dword ptr ds:[2BD2030h] ("Before JIT.")
*** WARNING: Unable to verify checksum for C:\Windows\assembly\...\mscorlib.ni.dll
01a1008c e84737966f      call    mscorlib_ni+0x6d37d8 (713737d8) (...)
01a10091 90              nop
01a10092 e8f141966f      call    mscorlib_ni+0x6d4288 (71374288) (...)
01a10097 90              nop
01a10098 b901000000      mov     ecx,1
01a1009d ff1568309400    call    dword ptr ds:[943068h] (...TestMethod(Int32), ...)
01a100a3 90              nop
01a100a4 8b0d3420bd02    mov     ecx,dword ptr ds:[2BD2034h] ("After JIT")
01a100aa e82937966f      call    mscorlib_ni+0x6d37d8 (713737d8) (...)
01a100af 90              nop
01a100b0 e8d341966f      call    mscorlib_ni+0x6d4288 (71374288) (...)
01a100b5 90              nop
01a100b6 b901000000      mov     ecx,1
01a100bb ff1568309400    call    dword ptr ds:[943068h] (...TestMethod(Int32), ...)
01a100c1 90              nop
01a100c2 90              nop
01a100c3 8be5            mov     esp,ebp
01a100c5 5d              pop     ebp
01a100c6 c3              ret

请注意最后标红的两个地址“943068h”,它并不是call指令的目标,而是表示call指令的目标是“该地址所存dword的址”。于是我们通过dd <address>命令查看该地址的值:

0:003> dd 943068h
00943068  01a100d8 00000000 0000000c 00040011
00943078  00000004 70f10508 00942c5c 009430a4
00943088  0094133c 00000000 00000000 70e66a70
00943098  70e66a90 70e66b00 70ed72f0 00000080

还记得01a100d8这个地址吗?向上翻翻,您会发现这就是JIT之后TestMethod方法的入口点。可以料得,在JIT之前,dd 943068h的结果是0094c040,因为这就是TestMethod在JIT之前的入口点。在TestMethod第一次被调用时,call指令会进入JIT,而第二次调用以后,call指令便可以直接访问方法的汇编指令了。

其实,如果要查看汇编指令,更简单的方法可能是在VS中设置断点,然后通过“Go to Disassmbly”来查看汇编代码。不过有时候我们却无法借助VS,例如在《浅谈尾递归的优化方式》一文中,我们的试验目标是通过IL编译得来的(因为C#编译器不会生成IL指令tail.)。这时候,我们就需要出动WinDbg了。当然,您也可以对进程进行dump之后,使用WinDbg来“Open Crash Dump”再进行分析——不过如果你要查看某个方法的汇编指令,还是要确保它已经经过了JIT。而本文没有使用dump的方式进行调试,也是因为想要演示一下JIT前后的改变3

 

注1:事实上经老赵观察发现,动辄喜欢用IL解释的人,大都是因为他理解得不够;而对问题充分理解之后,往往也就不需要用IL,或长篇IL代码了。就像CLR via C#,中间有多少是用IL说明问题的呢?而且真正的好书,好的教学方式,都是尽可能避免用低抽象的内容来说明问题的,因为重在“分析”,而不是使用的手段本身。手段本身应该尽可能的简化。因此MIT已经使用Python替代Scheme进行教学了,而很多大学操作系统课程也用了Java。

注2:使用[MethodImpl(MethodImplOptions.NoInlining)]对方法进行标记之后,JIT时应该也不会被内联,可以一试。

注3:如果事先使用ngen.exe对程序集进行处理,则托管方法就会变成PreJIT状态,在调试时便可以直接查看其汇编指令。

Creative Commons License

本文基于署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名赵劼(包含链接),具体操作方式可参考此处。如您有任何疑问或者授权方面的协商,请给我留言

Add your comment

46 条回复

  1. 包建强
    *.*.*.*
    链接

    包建强 2009-04-01 12:05:00

    我不建议这么玩。这样会搞出很多非IL的语法来,让我们无所适从。
    WinDbg只是一种手段,而不是主流。就像我昨天提到用UltraEdit32这个工具来解读汇编代码,道理是一样的。 ILAsm才是王道。

  2. Justin
    *.*.*.*
    链接

    Justin 2009-04-01 12:10:00

    顶了!!!

  3. 老赵
    admin
    链接

    老赵 2009-04-01 12:10:00

    --引用--------------------------------------------------
    包建强: 我不建议这么玩。这样会搞出很多非IL的语法来,让我们无所适从。

    WinDbg只是一种手段,而不是主流。就像我昨天提到用UltraEdit32这个工具来解读汇编代码,道理是一样的。
    ILAsm才是王道。
    --------------------------------------------------------
    我说过是主流了么?你没看到我文章一开始第一段在写什么吗?
    UltraEdit32怎么看汇编代码?我觉得它没法看,因为没有经过JIT你得不到汇编代码,要不你写一篇文章吧。
    IL为什么是王道了?我觉得对于95%的.NET编程人员来说,了解它也没有太大意义。
    其实我观察下来发现,动辄喜欢用IL解释的人,是因为他理解得不够;而对问题充分理解之后,往往也就不需要用IL,或长篇IL代码了。就像CLR via C#,中间有多少是用IL说明问题的?
    真正的好书,好的教学方式,都是尽可能避免用低抽象的内容来说明问题的,因为重在“分析”,而不是使用的手段本身。手段本身应该尽可能的简化。
    因此MIT已经使用Python替代Schema进行教学了,而很多大学操作系统课程也用了Java。

  4. 老赵
    admin
    链接

    老赵 2009-04-01 12:15:00

    @包建强
    还有就是WinDbg是不是主流的问题,在.NET编程上,它自然不是主流。但是在排错方面,它几乎是最后的保障,这个意义上来说,WinDbg就是主流,绝对的主流。
    当然,WinDbg最终还是辅助工具,排错考虑的是思考问题分析问题。
    // 我觉得你是,不会搞什么就说那个非主流所以不用搞,自己搞了点什么就觉得那是王道大家都要来学习。记得上次你好像搞了WPF/WF就看不起WCF了,呵呵,明明它们之间就没有任何竞争关系。

  5. Justin
    *.*.*.*
    链接

    Justin 2009-04-01 12:21:00

    火药味挺浓啊,最近怎么老看你俩掐呢,哈
    btw:目前我支持老赵

  6. 老赵
    admin
    链接

    老赵 2009-04-01 12:22:00

    --引用--------------------------------------------------
    Justin: 火药味挺浓啊,最近怎么老看你俩掐呢,哈
    btw:目前我支持老赵
    --------------------------------------------------------
    我最见不得包子出来乱说话,给个命题不给理由,给个结论不给方式(比如UltraEdit看汇编),要知道再咋样他也算是个MVP,在社区里说话要负责的。

  7. 生鱼片
    *.*.*.*
    链接

    生鱼片 2009-04-01 12:39:00

    --引用--------------------------------------------------
    真正的好书,好的教学方式,都是尽可能避免用低抽象的内容来说明问题的,因为重在“分析”,而不是使用的手段本身。手段本身应该尽可能的简化。

    因此MIT已经使用Python替代Schema进行教学了,而很多大学操作系统课程也用了Java。
    --------------------------------------------------------
    up,好的方式是使用最简单的描述和方式来说明复杂的问题。

  8. 包建强
    *.*.*.*
    链接

    包建强 2009-04-01 12:40:00

    额。又发飚了。

    UltraEdit32工具看托管文件的方法,不明究竟的话,是比较累。我只是举个例子。并不推荐啦。

    WinDbg生成那些额外的语法,确实不是ILAsm中的,难以做到逐一解释清楚。

    所以还是用ILDASM最爽啊,那个GUI就是干这个用的呢?为什么还要用别的呢。我真的没看出来其他工具的优势所在。

  9. 江南白衣-未登录[未注册用户]
    *.*.*.*
    链接

    江南白衣-未登录[未注册用户] 2009-04-01 12:44:00

    呵呵,支持老赵

  10. Zhuang miao
    *.*.*.*
    链接

    Zhuang miao 2009-04-01 12:45:00

    哈哈哈,干起来了~

  11. hehe a[未注册用户]
    *.*.*.*
    链接

    hehe a[未注册用户] 2009-04-01 12:49:00

    搬个板凳慢慢看口水战

  12. gjcn
    *.*.*.*
    链接

    gjcn 2009-04-01 12:54:00

    又一个用WinDbg的人。队伍大了

  13. mctor[未注册用户]
    *.*.*.*
    链接

    mctor[未注册用户] 2009-04-01 13:01:00


    Schema -> Scheme

  14. 老赵
    admin
    链接

    老赵 2009-04-01 13:15:00

    @包建强
    那是汇编,是机器码,和IL没有关系了。你说那么多,用ILDASM试试看作我现在说的事情就知道了,似乎你真是一点都不了解WinDbg的用处阿。
    ILASM看来看去还是IL,静态的IL,WinDbg往往用来看动态运行期间的状态,两者不能互相替代的。
    还有就是,你用UrtraEdit打开dll能看到IL,这没错,但是我这里看的是“汇编指令”,是IL经过JIT的结果,而不是“IL”,你觉得UrtraEdit该怎么看呢?运行期间dump一个内存快照再用UrtraEdit看?

  15. 老赵
    admin
    链接

    老赵 2009-04-01 13:19:00

    --引用--------------------------------------------------
    gjcn: 又一个用WinDbg的人。队伍大了
    --------------------------------------------------------
    平时不喜欢从这个角度说明问题,所以不太写文章……其实用了很久了,有时候没法不用WinDbg啊。

  16. lexc[未注册用户]
    *.*.*.*
    链接

    lexc[未注册用户] 2009-04-01 14:37:00

    刚试了1下,ngen install TestAsm.exe ,初次执行,JIT列已经不是None。而是PreJIT。也可以看到汇编代码

  17. 老赵
    admin
    链接

    老赵 2009-04-01 14:41:00

    @lexc
    ngen,不错。

  18. lexc[未注册用户]
    *.*.*.*
    链接

    lexc[未注册用户] 2009-04-01 14:49:00

    --引用--------------------------------------------------
    Jeffrey Zhao: @lexc
    ngen,不错。
    --------------------------------------------------------
    但它JIT列不是JIT而是PreJIT,可能跟第一次运行时的编译还是有差异的,希望赵兄继续研究哈

  19. 老赵
    admin
    链接

    老赵 2009-04-01 14:51:00

    @lexc
    PreJIT就是指在运行前就进行的JIT了,肯定会有差别,比如内联上。继续研究就不应该靠我了吧,要自己进行比较好,呵呵。

  20. Terry Sun
    *.*.*.*
    链接

    Terry Sun 2009-04-01 16:45:00

    哪里来的0028306c, 应该是0094306c

  21. Dylan.S.Ma
    *.*.*.*
    链接

    Dylan.S.Ma 2009-04-01 16:59:00

    (*^__^*) 志同道合!

    LZ

    前两天我弄了偏关于WinDBG的文章,
    这东西其实也没什么用处,可能很多人都不会用这个,
    在。net中还是MDBG 用处比较大 !

  22. Dylan.S.Ma
    *.*.*.*
    链接

    Dylan.S.Ma 2009-04-01 17:16:00

    我觉得 包建强 是正确的
    WinDBG 确实没有多少人用,微软倒是用的挺多的,毕竟自己的东西,对于调试运行时的程序还是不错,可以发现一些未知的问题! 就像LZ将的,曾经一个同事用这个给我就演示了GC的运行机制!
    这次。net大会上张银奎 先生 讲解过这个,



    我列举一下我所知道的这方面知识:
    1) WinDBG不是专门用于调试.Net程序的工具,它更偏向于底层,可用于内核和驱动调试。进行普通的.Net程序调试还是使用微软专为.Net开发的调试工具MDBG更方便一些。但是WinDBG能看到更多的底层信息,对于某些特别疑难的问题调试有所帮助,例如内存泄漏等问题。
    2) SOS扩展命令中最有用的命令是!help命令J,使用该命令可以列出所有可用的SOS扩展命令列表,使用!help [SOSCommandName]可以查看每一个具体扩展命名的详细使用说明,例如!help dumpheap就可以查看!dumpheap这个扩展命名的具体使用方法。多多利用!help命名可以很快上手SOS。
    3) WinDBG本身的资料可以参考 张银奎 先生的《软件调试》一书,另外在互联网上也有非常多的WinDBG资料。


    80%的开发人员是不会去用到IL,也不会去看,顺催就只有概念, 不过最近发现一个地方可以使用IL

    System.Reflection.Emit; 下的Emit可以动态构造代码,提升效率,不存在具体的C# ,vb的代码 == , 这里会用到IL
    其它地方就没有用过了

    如果说错了那里,不要 拍我哦!




  23. 老赵
    admin
    链接

    老赵 2009-04-01 17:30:00

    @Dylan.S.Ma
    说的基本不错,除了说包建强是正确的这点上,呵呵——因为你说的这些基本上也和他说的有冲突,他过分拔高了IL的重要性,而且分不清IL、JIT和汇编……这让我很汗。
    我很多年前开始用WinDBG(虽然用的不多而且近两年才愈发觉得它的用处),所以也就顺下来了。我刚才看了看MDbg,似乎的确是个不错的东西,有空我观察一下,谢谢推荐。

  24. 幸存者[未注册用户]
    *.*.*.*
    链接

    幸存者[未注册用户] 2009-04-01 19:39:00

    其实IL在很多地方还是相当有用的,比如匿名函数、迭代器、lambda这些东西,光从语言本身去看是很难理解透彻的。但是一看IL代码马上就知道编译器究竟做了什么。

  25. 老赵
    admin
    链接

    老赵 2009-04-01 19:45:00

    --引用--------------------------------------------------
    幸存者: 其实IL在很多地方还是相当有用的,比如匿名函数、迭代器、lambda这些东西,光从语言本身去看是很难理解透彻的。但是一看IL代码马上就知道编译器究竟做了什么。
    --------------------------------------------------------
    看这种东西也不需要IL,编译后再用.NET Reflector反编译为C#代码就行。
    根据我的经验来说,一般很少有需要IL的时候。上面一个朋友说的一点有些道理,就是用Emit的时候,就必须熟悉IL了。

  26. Dylan.S.Ma
    *.*.*.*
    链接

    Dylan.S.Ma 2009-04-01 22:37:00

    @幸存者
    --引用--------------------------------------------------
    幸存者: 其实IL在很多地方还是相当有用的,比如匿名函数、迭代器、lambda这些东西,光从语言本身去看是很难理解透彻的。但是一看IL代码马上就知道编译器究竟做了什么。
    --------------------------------------------------------

    如果你发现你的一个函数里面有太多的判断,太多的变量,一些循环, 你再去看,我估计很快就晕了!


  27. 老赵
    admin
    链接

    老赵 2009-04-01 22:46:00

    又被顶上去了……

  28. 木野狐(Neil Chen)
    *.*.*.*
    链接

    木野狐(Neil Chen) 2009-04-02 00:21:00

    我来纯支持。

  29. 水果阿生
    *.*.*.*
    链接

    水果阿生 2009-04-02 08:04:00

    不好意思,包同学,我跟你不熟,不过我是小白,我想请你帮忙解释一下,什么是JIT,什么是IL,什么又是汇编呢?

  30. 水果阿生
    *.*.*.*
    链接

    水果阿生 2009-04-02 08:05:00

    @Jeffrey Zhao
    得,你给指出来了。

  31. 老赵
    admin
    链接

    老赵 2009-04-02 09:01:00

    @木野狐(Neil Chen)
    @水果阿生
    谢谢大哥们支持

  32. 老赵
    admin
    链接

    老赵 2009-04-02 09:06:00

    --引用--------------------------------------------------
    Terry Sun: 哪里来的0028306c, 应该是0094306c
    --------------------------------------------------------
    谢谢指出,这个调试起来有一点不方便,就是调试两遍的话地址是不一样的,修改了两次还出现不一致的状况了……

  33. overred
    *.*.*.*
    链接

    overred 2009-04-02 09:08:00

    在那顶?

  34. 老赵
    admin
    链接

    老赵 2009-04-02 09:25:00

    @overred
    在后台或Live Writer里存为草稿再发布,就piapia地上去了,hang……

  35. 蛙蛙池塘
    *.*.*.*
    链接

    蛙蛙池塘 2009-04-02 09:34:00

    不懂啥是IL的路过。。。。

  36. 巫云
    *.*.*.*
    链接

    巫云 2009-04-02 09:46:00

    懂一点点IL的路过。。。

  37. overred
    *.*.*.*
    链接

    overred 2009-04-02 10:27:00

    @蛙蛙池塘
    又见蛙仔

  38. 鞠强
    *.*.*.*
    链接

    鞠强 2009-04-02 10:38:00

    其实,包子是老赵的马甲...老赵也是包子的马甲...

  39. 老赵
    admin
    链接

    老赵 2009-04-02 10:56:00

    @鞠强
    大哥不要搞笑……

  40. 蛙蛙池塘
    *.*.*.*
    链接

    蛙蛙池塘 2009-04-02 15:04:00

    鞠强也是老赵的马甲,鉴定完毕。。。

  41. mountaintai二世
    *.*.*.*
    链接

    mountaintai二世 2009-04-09 22:51:00

    如果要看函数的汇编代码,可以在Name2EE后面直接加函数全名。
    !Name2EE * TestAsm.TestClass.TestMethod
    如果函数已经jit,会给出jit代码的entrypoint,如果函数还未jit,会提示使用
    !bpmd -md <MethodDesc*>
    其作用是在该方法被jit的代码执行的初始位置下一个断点。

    如果待调试的managed assembly有pdb,则可以直接
    !bpmd <assemblyname> <methodname>,这样最为方便

  42. 老赵
    admin
    链接

    老赵 2009-04-10 09:05:00

    @mountaintai二世
    谢谢!

  43. 肖敏
    *.*.*.*
    链接

    肖敏 2009-05-05 18:01:00

    用NGEN直接编译成本地代码不可以么?

  44. 肖敏
    *.*.*.*
    链接

    肖敏 2009-05-05 18:08:00

    对了。还有Debug-Disassembly不是也可以查看汇编代码么。

  45. 老赵
    admin
    链接

    老赵 2009-05-05 18:15:00

    --引用--------------------------------------------------
    肖敏: 用NGEN直接编译成本地代码不可以么?
    --------------------------------------------------------
    ngen之后也需要在运行时才能看到。

  46. 老赵
    admin
    链接

    老赵 2009-05-05 18:16:00

    --引用--------------------------------------------------
    肖敏: 对了。还有Debug-Disassembly不是也可以查看汇编代码么。
    --------------------------------------------------------
    是可以,文章是用windbg看,可以得到更多细节。vs中往往需要配合断点看起来才方便,有时候这个条件满足不了。

发表回复

登录 / 登录并记住我 ,登陆后便可删除或修改已发表的评论 (请注意保留评论内容)

昵称:(必填)

邮箱:(必填,仅用于Gavatar

主页:(可选)

评论内容(大于5个字符):

  1. Your Name yyyy-MM-dd HH:mm:ss

使用Live Messenger联系我